diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2019-05-02 04:13:03 -0700 |
---|---|---|
committer | Linux Build Service Account <lnxbuild@localhost> | 2019-05-02 04:13:03 -0700 |
commit | fb13b6a373d9e92e8b2adeeb2dcf49e6d1065cef (patch) | |
tree | 5d9af4c49774c5ccc63ea9164964bfe38e5a372e | |
parent | efdc25857558d8d6011701a3f0056c29685fb0ee (diff) | |
parent | ed2cce8e3aaebb68ee7b0db32dd679f75b14d622 (diff) |
Merge ed2cce8e3aaebb68ee7b0db32dd679f75b14d622 on remote branchLA.UM.7.8.r3-01400-SDM710.0
Change-Id: Ic9550ddbaada69bb201a9d09d2b60033d5adc596
313 files changed, 13979 insertions, 3464 deletions
diff --git a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt index 75f901bcde9c..fd53d9f1e127 100644 --- a/Documentation/devicetree/bindings/arm/msm/clock-controller.txt +++ b/Documentation/devicetree/bindings/arm/msm/clock-controller.txt @@ -30,6 +30,7 @@ Required properties: "qcom,gcc-8917" "qcom,gcc-8940" "qcom,gcc-8920" + "qcom,gcc-qm215" "qcom,gcc-spm-8952" "qcom,gcc-spm-8937" "qcom,rpmcc-8909" diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 0d1a67af32a2..99f8c4c62593 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -184,6 +184,9 @@ Optional properties: 255 = default value. - qcom,mdss-brightness-max-level: Specifies the max brightness level supported. 255 = default value. +- qcom,bl-update-flag: A string that specifies controls for backlight update of the panel. + "delay_until_first_frame" = Delay backlight update of the panel + until the first frame is received from the HW. - qcom,mdss-dsi-interleave-mode: Specifies interleave mode. 0 = default value. - qcom,mdss-dsi-panel-type: Specifies the panel operating mode. @@ -600,6 +603,7 @@ Example: qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = < 15>; qcom,mdss-brightness-max-level = <255>; + qcom,bl-update-flag = "delay_until_first_frame"; qcom,mdss-dsi-interleave-mode = <0>; qcom,mdss-dsi-panel-type = "dsi_video_mode"; qcom,mdss-dsi-te-check-enable; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt index 29ea987e306d..8aa0ec530a3a 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt @@ -15,7 +15,8 @@ First Level Node - CAM IFE CSID device - compatible Usage: required Value type: <string> - Definition: Should be "qcom,csid170" or "qcom,csid-lite170". + Definition: Should be "qcom,csid170", "qcom,csid175", "qcom,csid175_200", + "qcom,csid-lite170" or "qcom,csid-lite175". - cell-index Usage: required diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt index f156cc67b2aa..9750d63794d1 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -17,7 +17,8 @@ Required properties: Usage: required Value type: <string> Definition: Should specify the compatibility string for matching the - driver. e.g. "qcom,vfe170", "qcom,vfe-lite170". + driver. e.g. "qcom,vfe175", "qcom,vfe170", "qcom,vfe175_130", + "qcom,vfe-lite175", "qcom,vfe-lite175_130", "qcom,vfe-lite170". - cell-index Usage: required diff --git a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt index d24314ae196d..970dae26dc57 100644 --- a/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt +++ b/Documentation/devicetree/bindings/media/video/msm-camera-flash.txt @@ -124,3 +124,21 @@ led_flash_rear: qcom,camera-flash@0 { qcom,max-current = <1500>; qcom,max-duration = <1200>; }; + + +Example: + +flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,qm215-gpio-flash"; + qcom,flash-type = <2>; + gpios = <&tlmm 34 0>; + <&tlmm 33 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-flash-en = <0>; + qcom,gpio-flash-now = <1>; + qcom,gpio-req-tbl-label = "CAM_FLASH", + "CAM_TORCH"; + status = "ok"; + }; diff --git a/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt index 8b2234e0c9fe..326f279623eb 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt @@ -13,12 +13,15 @@ Required Properties: Optional Properties: -- interrupts This indicates the IRQ number of the GPIO - connected to the STAT pin. +- interrupts This indicates the IRQ numbers of the GPIOs + connected to the STAT and usb-id pins. +- interrupt-names The irq names should be smb1360_stat_irq and + smb1360_usb_id_irq.The stat irq is mandatory + and usb_id irq is optional. - pinctrl-names: The state name of the pin configuration. Only support: "default". -- pinctrl-0: The phandle of the pin configuration node in - pinctrl for smb_int_pin. +- pinctrl-0: The phandles of the pin configuration node in + pinctrl for smb_int_pin and usb-id pin. For details of pinctrl properties, please refer to: "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt" - qcom,float-voltage-mv Float Voltage in mV - the maximum voltage up to which @@ -177,6 +180,8 @@ Optional Properties: Please go through the documentation for PMIC gpio configuration details: Documentation/devicetree/bindings/gpio/qpnp-pin.txt +- qcom,usb-id-gpio GPIO for usb-id detection.This property is mandatory + if usb-id irq is specified. - qcom,parallel-charging-enabled: A bool property which enables SMB1360 to operate in the parallel mode. SMB1360 acts as the primary charger. @@ -192,9 +197,13 @@ Example: compatible = "qcom,smb1360-chg-fg"; reg = <0x1b>; interrupt-parent = <&spmi_bus>; - interrupts = <0x00 0xcd 0>; + interrupts = <0x00 0xcd 0>, + <0 0xc3 0 3>; + interrupt-names = "smb1360_stat_irq", + "smb1360_usb_id_irq"; pinctrl-names = "default"; - pinctrl-0 = <&smb_int_default>; + pinctrl-0 = <&smb_int_default>, + <&usb_id_default>; /* battery-profile selection properties */ qcom,batt-profile-select; @@ -242,5 +251,6 @@ Example: qcom,otg-fet-present; qcom,otg-fet-enable-gpio = <&pm8916_gpios 3 0>; + qcom,usb-id-gpio = <&pm8916_gpios 4 0>; }; }; diff --git a/Documentation/devicetree/bindings/qseecom/qseecom.txt b/Documentation/devicetree/bindings/qseecom/qseecom.txt index 8fbf8e2fc8cc..83a2e8a6ae6a 100644 --- a/Documentation/devicetree/bindings/qseecom/qseecom.txt +++ b/Documentation/devicetree/bindings/qseecom/qseecom.txt @@ -27,6 +27,7 @@ Optional properties: - qcom,qsee-reentrancy-support: indicates the qsee reentrancy phase supported by the target - qcom,commonlib64-loaded-by-uefi: indicates commonlib64 is loaded by uefi already - qcom,fde-key-size: indicates which FDE key size is used in device. + - qcom,enable-key-wrap-in-ks: enables wrapping of ICE key with KS key. Example: qcom,qseecom@fe806000 { @@ -40,6 +41,7 @@ Example: qcom,hlos-ce-hw-instance = <1 2>; qcom,qsee-ce-hw-instance = <0>; qcom,support-fde; + qcom,enable-key-wrap-in-ks; qcom,support-pfe; qcom,msm_bus,name = "qseecom-noc"; qcom,msm_bus,num_cases = <4>; @@ -64,6 +66,7 @@ Example: The following dts setup is the same as the example above. reg = <0x7f00000 0x500000>; reg-names = "secapp-region"; qcom,support-fde; + qcom,enable-key-wrap-in-ks; qcom,full-disk-encrypt-info = <0 1 2>, <0 2 2>; qcom,support-pfe; qcom,per-file-encrypt-info = <0 1 0>, <0 2 0>; diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 084e48707f58..8a5099dc084a 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -329,7 +329,6 @@ CONFIG_FB_MSM_MDSS=y CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_SPI_PANEL=y CONFIG_FB_MSM_MDSS_MDP3=y -CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_SOUND=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 5eaa0eb983a6..b65fbac85719 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -677,7 +677,6 @@ CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_LIST=y diff --git a/arch/arm/configs/msm8937go-perf_defconfig b/arch/arm/configs/msm8937go-perf_defconfig index 3a388860b041..6be2749963db 100644 --- a/arch/arm/configs/msm8937go-perf_defconfig +++ b/arch/arm/configs/msm8937go-perf_defconfig @@ -107,10 +107,12 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=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 @@ -127,7 +129,6 @@ CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=y CONFIG_NF_CONNTRACK_FTP=y @@ -174,6 +175,7 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=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 @@ -207,6 +209,7 @@ 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_DEBUGFS=y CONFIG_L2TP_V3=y diff --git a/arch/arm/configs/msm8937go_defconfig b/arch/arm/configs/msm8937go_defconfig index 0f7c8231c30a..b76c4183a762 100644 --- a/arch/arm/configs/msm8937go_defconfig +++ b/arch/arm/configs/msm8937go_defconfig @@ -110,10 +110,12 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=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 @@ -130,7 +132,6 @@ CONFIG_NF_CONNTRACK=y CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CT_PROTO_DCCP=y -CONFIG_NF_CT_PROTO_SCTP=y CONFIG_NF_CT_PROTO_UDPLITE=y CONFIG_NF_CONNTRACK_AMANDA=y CONFIG_NF_CONNTRACK_FTP=y @@ -177,6 +178,7 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=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 @@ -210,6 +212,7 @@ 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_DEBUGFS=y CONFIG_L2TP_V3=y @@ -671,7 +674,6 @@ CONFIG_PANIC_ON_SCHED_BUG=y CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_DEBUG_PREEMPT is not set -CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_DEBUG_ATOMIC_SLEEP=y CONFIG_DEBUG_LIST=y diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 13e5187ed6b5..dcbfe47cec8f 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -509,7 +509,7 @@ }; }; - qcom,msm-dai-tdm-quat-rx { + 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>; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi index 47a925e4c34a..96a282673b56 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909w-pm660-regulator.dtsi @@ -329,16 +329,43 @@ /* CPR controlled regulator */ &soc { + /delete-node/ regulator@1942130; mem_acc_vreg_corner: regulator@1942130 { compatible = "qcom,mem-acc-regulator"; - reg = <0x1942130 0x4>; - reg-names = "acc-sel-l1"; regulator-name = "mem_acc_corner"; regulator-min-microvolt = <1>; regulator-max-microvolt = <3>; - qcom,acc-sel-l1-bit-pos = <0>; - qcom,corner-acc-map = <0 1 1>; + qcom,acc-reg-addr-list = + <0x1942130 0x1942120>; + + qcom,acc-init-reg-config = <1 0x1>, <2 0x0>; + qcom,num-acc-corners = <3>; + qcom,boot-acc-corner = <2>; + + qcom,corner1-reg-config = + /* SVS => SVS */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* SVS => NOM */ + < 1 0x0 >, < 2 0x09240000>, < 1 0x1 >, + /* SVS => TURBO */ + < 1 0x1 >, < 2 0x0>, < (-1) (-1) >; + + qcom,corner2-reg-config = + /* NOM => SVS */ + < 1 0x0 >, < 2 0x09240000>, < 2 0x0 >, + /* NOM => NOM */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>, + /* NOM => TURBO */ + < 1 0x1 >, < 2 0x08200000>, < 2 0x0 >; + + qcom,corner3-reg-config = + /* TURBO => SVS */ + < 1 0x0 >, < 2 0x0>, < (-1) (-1) >, + /* TURBO => NOM */ + < 1 0x1 >, < 2 0x08200000>, < 2 0x09240000 >, + /* TURBO => TURBO */ + <(-1) (-1)>, <(-1) (-1)>, <(-1) (-1)>; }; apc_vreg_corner: regulator@b018000 { diff --git a/arch/arm64/boot/dts/qcom/msm8937-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-camera-sensor-cdp.dtsi new file mode 100644 index 000000000000..8f174fbda46e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8937-camera-sensor-cdp.dtsi @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2015-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. + */ + +&cci { + actuator0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + actuator1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + qcom,cci-master = <0>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vaf"; + qcom,cam-vreg-min-voltage = <2850000>; + qcom,cam-vreg-max-voltage = <2850000>; + qcom,cam-vreg-op-mode = <80000>; + }; + + eeprom0: qcom,eeprom@0 { + cell-index = <0>; + compatible = "qcom,eeprom"; + qcom,cci-master = <0>; + reg = <0x0>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <0 2800000 2850000>; + qcom,cam-vreg-op-mode = <0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_reset + &cam_sensor_rear_standby + &cam_sensor_rear_vdig>; + pinctrl-1 = <&cam_sensor_mclk0_sleep + &cam_sensor_rear_reset_sleep + &cam_sensor_rear_standby_sleep + &cam_sensor_rear_vdig_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>, + <&tlmm 62 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-vdig = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0", + "CAM_VDIG"; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + eeprom1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + qcom,eeprom-name = "sunny_8865"; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0x6c>; + qcom,cci-master = <0>; + qcom,num-blocks = <8>; + + qcom,page0 = <1 0x0100 2 0x01 1 1>; + qcom,poll0 = <0 0x0 2 0x0 1 0>; + qcom,mem0 = <0 0x0 2 0x0 1 0>; + + qcom,page1 = <1 0x5002 2 0x00 1 0>; + qcom,poll1 = <0 0x0 2 0x0 1 0>; + qcom,mem1 = <0 0x0 2 0x0 1 0>; + + qcom,page2 = <1 0x3d84 2 0xc0 1 0>; + qcom,poll2 = <0 0x0 2 0x0 1 0>; + qcom,mem2 = <0 0x0 2 0x0 1 0>; + + qcom,page3 = <1 0x3d88 2 0x70 1 0>; + qcom,poll3 = <0 0x0 2 0x0 1 0>; + qcom,mem3 = <0 0x0 2 0x0 1 0>; + + qcom,page4 = <1 0x3d89 2 0x10 1 0>; + qcom,poll4 = <0 0x0 2 0x0 1 0>; + qcom,mem4 = <0 0x0 2 0x0 1 0>; + + qcom,page5 = <1 0x3d8a 2 0x70 1 0>; + qcom,poll5 = <0 0x0 2 0x0 1 0>; + qcom,mem5 = <0 0x0 2 0x0 1 0>; + + qcom,page6 = <1 0x3d8b 2 0xf4 1 0>; + qcom,poll6 = <0 0x0 2 0x0 1 0>; + qcom,mem6 = <0 0x0 2 0x0 1 0>; + + qcom,page7 = <1 0x3d81 2 0x01 1 10>; + qcom,poll7 = <0 0x0 2 0x0 1 1>; + qcom,mem7 = <1536 0x7010 2 0 1 0>; + + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,cam-power-seq-type = "sensor_vreg", "sensor_vreg", + "sensor_vreg", + "sensor_gpio", "sensor_gpio" , "sensor_clk"; + qcom,cam-power-seq-val = "cam_vdig", "cam_vana", "cam_vio", + "sensor_gpio_reset", "sensor_gpio_standby", + "sensor_cam_mclk"; + qcom,cam-power-seq-cfg-val = <1 1 1 1 1 24000000>; + qcom,cam-power-seq-delay = <1 1 1 30 30 5>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <19200000 0>; + }; + + qcom,camera@0 { + cell-index = <0>; + compatible = "qcom,camera"; + reg = <0x0>; + qcom,csiphy-sd-index = <0>; + qcom,csid-sd-index = <0>; + qcom,mount-angle = <270>; + qcom,led-flash-src = <&led_flash0>; + qcom,eeprom-src = <&eeprom0>; + qcom,actuator-src = <&actuator0>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vio", "cam_vana", "cam_vaf"; + qcom,cam-vreg-min-voltage = <0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <0 2800000 2850000>; + qcom,cam-vreg-op-mode = <0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_default + &cam_sensor_rear_reset + &cam_sensor_rear_standby + &cam_sensor_rear_vdig>; + pinctrl-1 = <&cam_sensor_mclk0_sleep + &cam_sensor_rear_reset_sleep + &cam_sensor_rear_standby_sleep + &cam_sensor_rear_vdig_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>, + <&tlmm 62 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-vdig = <3>; + qcom,gpio-req-tbl-num = <0 1 2 3>; + qcom,gpio-req-tbl-flags = <1 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0", + "CAM_VDIG"; + qcom,sensor-position = <0>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk0_clk_src>, + <&clock_gcc clk_gcc_camss_mclk0_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@1 { + cell-index = <1>; + compatible = "qcom,camera"; + reg = <0x1>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <200000 0 80000 100000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_default + &cam_sensor_front_default>; + pinctrl-1 = <&cam_sensor_mclk1_sleep + &cam_sensor_front_sleep>; + gpios = <&tlmm 27 0>, + <&tlmm 38 0>, + <&tlmm 50 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_STANDBY1"; + qcom,sensor-position = <0x100>; + qcom,sensor-mode = <1>; + qcom,cci-master = <1>; + clocks = <&clock_gcc clk_mclk1_clk_src>, + <&clock_gcc clk_gcc_camss_mclk1_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; + + qcom,camera@2 { + cell-index = <2>; + compatible = "qcom,camera"; + reg = <0x02>; + qcom,csiphy-sd-index = <1>; + qcom,csid-sd-index = <1>; + qcom,mount-angle = <90>; + qcom,eeprom-src = <&eeprom1>; + qcom,actuator-src = <&actuator1>; + cam_vdig-supply = <&pm8937_l23>; + cam_vana-supply = <&pm8937_l22>; + cam_vio-supply = <&pm8937_l6>; + cam_vaf-supply = <&pm8937_l17>; + qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana", + "cam_vaf"; + qcom,cam-vreg-min-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-max-voltage = <1200000 0 2800000 2850000>; + qcom,cam-vreg-op-mode = <105000 0 80000 100000>; + qcom,gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_default + &cam_sensor_front1_default>; + pinctrl-1 = <&cam_sensor_mclk2_sleep + &cam_sensor_front1_sleep>; + gpios = <&tlmm 28 0>, + <&tlmm 40 0>, + <&tlmm 39 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_STANDBY2"; + qcom,sensor-position = <1>; + qcom,sensor-mode = <0>; + qcom,cci-master = <0>; + status = "ok"; + clocks = <&clock_gcc clk_mclk2_clk_src>, + <&clock_gcc clk_gcc_camss_mclk2_clk>; + clock-names = "cam_src_clk", "cam_clk"; + qcom,clock-rates = <24000000 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8937-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-cdp.dtsi index 46e480ed7f11..c4100ab27c9d 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-cdp.dtsi @@ -12,6 +12,7 @@ */ #include <dt-bindings/clock/msm-clocks-8952.h> +#include "msm8937-camera-sensor-cdp.dtsi" &soc { gpio_keys { diff --git a/arch/arm64/boot/dts/qcom/pm8937.dtsi b/arch/arm64/boot/dts/qcom/pm8937.dtsi index 18a3270c3a0d..b97cec6b7871 100644 --- a/arch/arm64/boot/dts/qcom/pm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8937.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * 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 @@ -284,6 +284,7 @@ qcom,adc-bit-resolution = <15>; qcom,adc-vdd-reference = <1800>; qcom,adc_tm-vadc = <&pm8937_vadc>; + #thermal-sensor-cells = <1>; chan@36 { label = "pa_therm0"; diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 7801775c7e3b..c437ef1dbfac 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -59,7 +59,7 @@ }; &secure_display_memory { - status = "disabled"; + size = <0 0xa000000>; }; &sp_mem { diff --git a/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi index f7c6814a0333..ab5557216974 100644 --- a/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/qm215-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * 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 @@ -97,6 +97,21 @@ qcom,clock-rates = <19200000 0>; }; + flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,qm215-gpio-flash"; + qcom,flash-type = <2>; + gpios = <&tlmm 34 0>, + <&tlmm 33 0>; + qcom,gpio-req-tbl-num = <0 1>; + qcom,gpio-req-tbl-flags = <1 0>; + qcom,gpio-flash-en = <0>; + qcom,gpio-flash-now = <1>; + qcom,gpio-req-tbl-label = "CAM_FLASH", + "CAM_TORCH"; + status = "ok"; + }; + qcom,camera@0 { cell-index = <0>; compatible = "qcom,camera"; @@ -104,6 +119,7 @@ qcom,csiphy-sd-index = <0>; qcom,csid-sd-index = <0>; qcom,mount-angle = <90>; + qcom,led-flash-src = <&flash0>; qcom,actuator-src = <&actuator0>; qcom,eeprom-src = <&eeprom0>; cam_vana-supply = <&pm8916_l16>; diff --git a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi index 0885da1cb2e9..06aadee8c948 100644 --- a/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi +++ b/arch/arm64/boot/dts/qcom/qm215-qrd-smb1360.dtsi @@ -11,3 +11,78 @@ */ #include "qm215-qrd.dtsi" + +&pm8916_chg{ + qcom,use-external-charger; +}; + +&pm8916_bms{ + qcom,disable-bms; +}; + +&tlmm { + /* SMB interrupt pin */ + smb_int_pin { + smb_int_default: smb_int_default { + mux { + pins = "gpio13"; + function ="gpio"; + }; + config { + pins = "gpio13"; + bias-pull-up; /* PULL UP*/ + input-enable; + }; + }; + }; +}; + +&pm8916_gpios { + usb_id { + usb_id_default: usb_id_default { + pins = "gpio4"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +&i2c_2 { + status ="ok"; + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupts-extended = <&tlmm 13 8>, + <&spmi_bus 0 0xc3 0 3>; + interrupt-names = "smb1360_stat_irq", + "smb1360_usb_id_irq"; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>, + <&usb_id_default>; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4400>; + qcom,iterm-ma = <100>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + qcom,fg-batt-capacity-mah = <2800>; + qcom,fg-cutoff-voltage-mv = <3400>; + qcom,fg-iterm-ma = <130>; + qcom,fg-delta-soc = <1>; + qcom,usb-id-gpio = <&pm8916_gpios 4 0>; + qcom,soft-jeita-supported; + qcom,warm-bat-decidegc = <450>; + qcom,cool-bat-decidegc = <150>; + qcom,warm-bat-mv = <4200>; + qcom,cool-bat-mv = <4200>; + qcom,warm-bat-ma = <1000>; + qcom,cool-bat-ma = <1000>; + status= "okay"; + }; +}; + +&usb_otg { + extcon = <&smb1360_otg_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/qm215-qrd.dtsi b/arch/arm64/boot/dts/qcom/qm215-qrd.dtsi index 058edaa9ddd7..fa29c8ed9ad2 100644 --- a/arch/arm64/boot/dts/qcom/qm215-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/qm215-qrd.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * 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 @@ -13,6 +13,8 @@ &blsp1_uart2 { status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; }; #include <dt-bindings/clock/msm-clocks-8952.h> diff --git a/arch/arm64/boot/dts/qcom/qm215.dtsi b/arch/arm64/boot/dts/qcom/qm215.dtsi index 597ce27b1a2f..810932ae7d8c 100644 --- a/arch/arm64/boot/dts/qcom/qm215.dtsi +++ b/arch/arm64/boot/dts/qcom/qm215.dtsi @@ -56,6 +56,10 @@ }; }; +&clock_gcc { + compatible = "qcom,gcc-qm215"; +}; + /* GPU overrides */ &msm_gpu { diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi index 78047bd22f9e..fd0aa8a39a33 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-qrd.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -194,6 +194,11 @@ }; &cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + actuator_rear: qcom,actuator@0 { cell-index = <0>; reg = <0x0>; diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index bf50ce61cec7..b967af9d2ab7 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -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 @@ -1621,6 +1621,7 @@ qcom,xprt-linkid = <1>; qcom,xprt-version = <1>; qcom,fragmented-data; + qcom,dynamic-wakeup-source; }; qcom,ipc_router_cdsp_xprt { diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index b5c1ded20fc7..a64467c3ef68 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -67,7 +67,8 @@ <&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_0>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_rx_1>; 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", @@ -89,7 +90,8 @@ "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.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36914"; }; }; @@ -99,3 +101,13 @@ 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/sdw3100-msm8909w-wtp.dts b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts index f7b9ec1d9207..5df6dc42f122 100644 --- a/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts @@ -26,8 +26,10 @@ qcom,msm-id = <245 0>, <258 0>, <275 0>, - <300 0>; - qcom,board-id = <8 0x10f>; + <300 0>, + <301 0>; + qcom,board-id = <8 0x10f>, + <8 0x117>; qcom,pmic-id = <0x0001001b 0x0 0x0 0x0>, <0x0001011b 0x0 0x0 0x0>; }; diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 2a801e9a4620..467dc4fbb133 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -640,7 +640,6 @@ CONFIG_CORESIGHT_QCOM_REPLICATOR=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y -CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_PFK=y diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 3bc57d26d6b3..5c305104dd12 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -232,6 +232,7 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 707a7d79fa51..35539f0aaba2 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -240,6 +240,7 @@ CONFIG_DNS_RESOLVER=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index e0b731e70f66..c845bf57ccb3 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -779,8 +779,8 @@ static irqreturn_t armv8pmu_handle_irq(int irq_num, void *dev) struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; - /* Ignore if we don't have an event or if it's a zombie event */ - if (!event || event->state == PERF_EVENT_STATE_ZOMBIE) + /* Ignore if we don't have an event */ + if (!event || event->state != PERF_EVENT_STATE_ACTIVE) continue; /* diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 42dde2d64166..c38c08ee630d 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -1256,6 +1256,9 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, size_t array_size = count * sizeof(struct page *); int i = 0; bool is_coherent = is_dma_coherent(dev, attrs); + struct dma_iommu_mapping *mapping = dev->archdata.mapping; + unsigned int alloc_sizes = mapping->domain->pgsize_bitmap; + unsigned long order_mask; if (array_size <= PAGE_SIZE) pages = kzalloc(array_size, gfp); @@ -1284,13 +1287,26 @@ static struct page **__iommu_alloc_buffer(struct device *dev, size_t size, * IOMMU can map any pages, so himem can also be used here */ gfp |= __GFP_NOWARN | __GFP_HIGHMEM; + order_mask = alloc_sizes >> PAGE_SHIFT; + order_mask &= (2U << MAX_ORDER) - 1; + if (!order_mask) + goto error; while (count) { - int j, order = __fls(count); + int j, order; + + order_mask &= (2U << __fls(count)) - 1; + order = __fls(order_mask); + + pages[i] = alloc_pages(order ? (gfp | __GFP_NORETRY) & + ~__GFP_RECLAIM : gfp, order); + while (!pages[i] && order) { + order_mask &= ~(1U << order); + order = __fls(order_mask); + pages[i] = alloc_pages(order ? (gfp | __GFP_NORETRY) & + ~__GFP_RECLAIM : gfp, order); + } - pages[i] = alloc_pages(gfp, order); - while (!pages[i] && order) - pages[i] = alloc_pages(gfp, --order); if (!pages[i]) goto error; diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 1c76daacfb0b..b8fffb591ec4 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -924,14 +924,13 @@ enum lru_status binder_alloc_free_page(struct list_head *item, index = page - alloc->pages; page_addr = (uintptr_t)alloc->buffer + index * PAGE_SIZE; + + mm = alloc->vma_vm_mm; + if (!mmget_not_zero(mm)) + goto err_mmget; + if (!down_write_trylock(&mm->mmap_sem)) + goto err_down_write_mmap_sem_failed; vma = alloc->vma; - if (vma) { - if (!mmget_not_zero(alloc->vma_vm_mm)) - goto err_mmget; - mm = alloc->vma_vm_mm; - if (!down_write_trylock(&mm->mmap_sem)) - goto err_down_write_mmap_sem_failed; - } list_lru_isolate(lru, item); spin_unlock(lock); @@ -945,10 +944,9 @@ enum lru_status binder_alloc_free_page(struct list_head *item, PAGE_SIZE, NULL); trace_binder_unmap_user_end(alloc, index); - - up_write(&mm->mmap_sem); - mmput(mm); } + up_write(&mm->mmap_sem); + mmput(mm); trace_binder_unmap_kernel_start(alloc, index); diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index b332a13a9925..2d0574200459 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * 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 @@ -106,6 +106,7 @@ #define PERF_KEYS \ "count:flush:map:copy:glink:getargs:putargs:invalidate:invoke:tid:ptr" +#define FASTRPC_STATIC_HANDLE_KERNEL (1) #define FASTRPC_STATIC_HANDLE_LISTENER (3) #define FASTRPC_STATIC_HANDLE_MAX (20) #define FASTRPC_LATENCY_CTRL_ENB (1) @@ -1953,6 +1954,14 @@ static int fastrpc_internal_invoke(struct fastrpc_file *fl, uint32_t mode, if (fl->profile) getnstimeofday(&invoket); + if (!kernel) { + VERIFY(err, invoke->handle != FASTRPC_STATIC_HANDLE_KERNEL); + if (err) { + pr_err("adsprpc: ERROR: %s: user application %s trying to send a kernel RPC message to channel %d", + __func__, current->comm, cid); + goto bail; + } + } VERIFY(err, fl->sctx != NULL); if (err) @@ -2092,7 +2101,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, ra[0].buf.pv = (void *)&tgid; ra[0].buf.len = sizeof(tgid); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(0, 1, 0); ioctl.inv.pra = ra; ioctl.fds = NULL; @@ -2187,7 +2196,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, ra[5].buf.len = sizeof(inbuf.siglen); fds[5] = 0; - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(6, 4, 0); if (uproc->attrs) ioctl.inv.sc = REMOTE_SCALARS_MAKE(7, 6, 0); @@ -2273,7 +2282,7 @@ static int fastrpc_init_process(struct fastrpc_file *fl, ra[2].buf.pv = (void *)pages; ra[2].buf.len = sizeof(*pages); fds[2] = 0; - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(8, 3, 0); ioctl.inv.pra = ra; @@ -2325,7 +2334,7 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl) tgid = fl->tgid; ra[0].buf.pv = (void *)&tgid; ra[0].buf.len = sizeof(tgid); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(1, 1, 0); ioctl.inv.pra = ra; ioctl.fds = NULL; @@ -2371,7 +2380,7 @@ static int fastrpc_mmap_on_dsp(struct fastrpc_file *fl, uint32_t flags, ra[2].buf.pv = (void *)&routargs; ra[2].buf.len = sizeof(routargs); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; if (fl->apps->compat) ioctl.inv.sc = REMOTE_SCALARS_MAKE(4, 2, 1); else @@ -2426,7 +2435,7 @@ static int fastrpc_munmap_on_dsp_rh(struct fastrpc_file *fl, uint64_t phys, ra[0].buf.pv = (void *)&routargs; ra[0].buf.len = sizeof(routargs); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; ioctl.inv.sc = REMOTE_SCALARS_MAKE(7, 0, 1); ioctl.inv.pra = ra; ioctl.fds = NULL; @@ -2477,7 +2486,7 @@ static int fastrpc_munmap_on_dsp(struct fastrpc_file *fl, uintptr_t raddr, ra[0].buf.pv = (void *)&inargs; ra[0].buf.len = sizeof(inargs); - ioctl.inv.handle = 1; + ioctl.inv.handle = FASTRPC_STATIC_HANDLE_KERNEL; if (fl->apps->compat) ioctl.inv.sc = REMOTE_SCALARS_MAKE(5, 1, 0); else diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 0937b2f14d77..5a1afd0e41c7 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -2757,10 +2757,11 @@ err: int diag_dci_init(void) { - int ret = 0; + int ret = 0, i; driver->dci_tag = 0; - driver->dci_client_id = 0; + for (i = 0; i < MAX_DCI_CLIENTS; i++) + driver->dci_client_id[i] = 0; driver->num_dci_client = 0; mutex_init(&driver->dci_mutex); mutex_init(&dci_log_mask_mutex); @@ -2956,8 +2957,8 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) mutex_init(&new_entry->write_buf_mutex); new_entry->dci_log_mask = vzalloc(DCI_LOG_MASK_SIZE); if (!new_entry->dci_log_mask) { - pr_err("diag: Unable to create log mask for client, %d", - driver->dci_client_id); + pr_err("diag: Unable to create log mask for DCI client, tgid: %d\n", + current->tgid); goto fail_alloc; } create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN); @@ -3006,17 +3007,24 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) proc_buf->buf_curr = proc_buf->buf_primary; } - list_add_tail(&new_entry->track, &driver->dci_client_list); - driver->dci_client_id++; - new_entry->client_info.client_id = driver->dci_client_id; - reg_entry->client_id = driver->dci_client_id; + for (i = 0; i < MAX_DCI_CLIENTS; i++) { + if (driver->dci_client_id[i] == 0) + break; + } + + if (i == MAX_DCI_CLIENTS) + goto fail_alloc; + driver->dci_client_id[i] = 1; + new_entry->client_info.client_id = i+1; + reg_entry->client_id = i+1; driver->num_dci_client++; + list_add_tail(&new_entry->track, &driver->dci_client_list); if (driver->num_dci_client == 1) diag_update_proc_vote(DIAG_PROC_DCI, VOTE_UP, reg_entry->token); queue_work(driver->diag_real_time_wq, &driver->diag_real_time_work); mutex_unlock(&driver->dci_mutex); - return driver->dci_client_id; + return reg_entry->client_id; fail_alloc: if (new_entry) { @@ -3075,7 +3083,11 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) */ if (!list_empty(&entry->track)) list_del(&entry->track); + + if (entry->client_info.client_id > MAX_DCI_CLIENTS) + return DIAG_DCI_NO_REG; driver->num_dci_client--; + driver->dci_client_id[entry->client_info.client_id - 1] = 0; /* * Clear the client's log and event masks, update the cumulative * masks and send the masks to peripherals diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h index 2fb0e3f7adf3..835c0c1708cf 100644 --- a/drivers/char/diag/diag_dci.h +++ b/drivers/char/diag/diag_dci.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2016, 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 @@ -12,7 +12,6 @@ #ifndef DIAG_DCI_H #define DIAG_DCI_H -#define MAX_DCI_CLIENTS 10 #define DCI_PKT_RSP_CODE 0x93 #define DCI_DELAYED_RSP_CODE 0x94 #define DCI_CONTROL_PKT_CODE 0x9A diff --git a/drivers/char/diag/diag_usb.c b/drivers/char/diag/diag_usb.c index 24a9f8af728a..b8b8b3206528 100644 --- a/drivers/char/diag/diag_usb.c +++ b/drivers/char/diag/diag_usb.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -324,8 +324,8 @@ static void diag_usb_write_done(struct diag_usb_info *ch, DIAG_LOG(DIAG_DEBUG_MUX, "partial write_done ref %d\n", atomic_read(&entry->ref_count)); diag_ws_on_copy_complete(DIAG_WS_MUX); - spin_unlock_irqrestore(&ch->write_lock, flags); diagmem_free(driver, req, ch->mempool); + spin_unlock_irqrestore(&ch->write_lock, flags); return; } DIAG_LOG(DIAG_DEBUG_MUX, "full write_done, ctxt: %d\n", @@ -343,8 +343,8 @@ static void diag_usb_write_done(struct diag_usb_info *ch, buf = NULL; len = 0; ctxt = 0; - spin_unlock_irqrestore(&ch->write_lock, flags); diagmem_free(driver, req, ch->mempool); + spin_unlock_irqrestore(&ch->write_lock, flags); } static void diag_usb_notifier(void *priv, unsigned int event, diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index f63d78c32b6e..56be94c8197f 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -288,6 +288,7 @@ for (i = 0; i <= fwd_info->num_pd - 2; i++) \ #define DIAG_CNTL_TYPE 2 #define DIAG_DCI_TYPE 3 +#define MAX_DCI_CLIENTS 10 /* * List of diag ids * 0 is reserved for unknown diag id, 1 for apps, diag ids @@ -479,6 +480,12 @@ struct diag_logging_mode_param_t { int peripheral; } __packed; +struct diag_query_pid_t { + uint32_t peripheral_mask; + uint32_t pd_mask; + int pid; +}; + struct diag_md_session_t { int pid; int peripheral_mask; @@ -580,7 +587,7 @@ struct diagchar_dev { struct list_head dci_req_list; struct list_head dci_client_list; int dci_tag; - int dci_client_id; + int dci_client_id[MAX_DCI_CLIENTS]; struct mutex dci_mutex; int num_dci_client; unsigned char *apps_dci_buf; @@ -597,6 +604,7 @@ struct diagchar_dev { unsigned int poolsize_hdlc; unsigned int poolsize_dci; unsigned int poolsize_user; + spinlock_t diagmem_lock; /* Buffers for masks */ struct mutex diag_cntl_mutex; /* Members for Sending response */ diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 8adaf6478acb..8a88cf08e574 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -213,17 +213,19 @@ static void drain_timer_func(unsigned long data) static void diag_drain_apps_data(struct diag_apps_data_t *data) { int err = 0; + unsigned long flags; if (!data || !data->buf) return; err = diag_mux_write(DIAG_LOCAL_PROC, data->buf, data->len, data->ctxt); + spin_lock_irqsave(&driver->diagmem_lock, flags); if (err) diagmem_free(driver, data->buf, POOL_TYPE_HDLC); - data->buf = NULL; data->len = 0; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } void diag_update_user_client_work_fn(struct work_struct *work) @@ -294,6 +296,8 @@ static void diag_mempool_init(void) diagmem_init(driver, POOL_TYPE_HDLC); diagmem_init(driver, POOL_TYPE_USER); diagmem_init(driver, POOL_TYPE_DCI); + + spin_lock_init(&driver->diagmem_lock); } static void diag_mempool_exit(void) @@ -2356,6 +2360,93 @@ static int diag_ioctl_query_pd_logging(struct diag_logging_mode_param_t *param) return ret; } +static void diag_ioctl_query_session_pid(struct diag_query_pid_t *param) +{ + int prev_pid = 0, test_pid = 0, i = 0, count = 0; + uint32_t pd_mask = 0, peripheral_mask = 0; + struct diag_md_session_t *info = NULL; + + param->pid = 0; + + if (param->pd_mask && param->peripheral_mask) { + param->pid = -EINVAL; + return; + } else if (param->peripheral_mask) { + if (param->peripheral_mask == DIAG_CON_ALL) { + for (i = 0; i <= NUM_PERIPHERALS; i++) { + if (driver->md_session_map[i]) { + test_pid = + driver->md_session_map[i]->pid; + count++; + if (!prev_pid) + prev_pid = test_pid; + if (test_pid != prev_pid) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: One of the peripherals is being logged already\n"); + param->pid = -EINVAL; + } + } + } + if (i == count && prev_pid) + param->pid = prev_pid; + } else { + peripheral_mask = + diag_translate_mask(param->peripheral_mask); + for (i = 0; i <= NUM_PERIPHERALS; i++) { + if (driver->md_session_map[i] && + (peripheral_mask & + MD_PERIPHERAL_MASK(i))) { + info = driver->md_session_map[i]; + if (peripheral_mask != + info->peripheral_mask) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: Invalid Peripheral mask given as input\n"); + param->pid = -EINVAL; + return; + } + test_pid = info->pid; + if (!prev_pid) + prev_pid = test_pid; + if (test_pid != prev_pid) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: One of the peripherals is logged in different session\n"); + param->pid = -EINVAL; + return; + } + } + } + param->pid = prev_pid; + } + } else if (param->pd_mask) { + pd_mask = + diag_translate_mask(param->pd_mask); + for (i = UPD_WLAN; i < NUM_MD_SESSIONS; i++) { + if (driver->md_session_map[i] && + (pd_mask & MD_PERIPHERAL_MASK(i))) { + info = driver->md_session_map[i]; + if (pd_mask != info->peripheral_mask) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: Invalid PD mask given as input\n"); + param->pid = -EINVAL; + return; + } + test_pid = info->pid; + if (!prev_pid) + prev_pid = test_pid; + if (test_pid != prev_pid) { + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: One of the PDs is being logged already\n"); + param->pid = -EINVAL; + return; + } + } + } + param->pid = prev_pid; + } + DIAG_LOG(DIAG_DEBUG_USERSPACE, + "diag: Pid for the active ODL session: %d\n", param->pid); +} + static int diag_ioctl_register_callback(unsigned long ioarg) { int err = 0; @@ -2482,6 +2573,7 @@ long diagchar_compat_ioctl(struct file *filp, uint16_t remote_dev; struct diag_dci_client_tbl *dci_client = NULL; struct diag_logging_mode_param_t mode_param; + struct diag_query_pid_t pid_query; switch (iocmd) { case DIAG_IOCTL_COMMAND_REG: @@ -2600,6 +2692,22 @@ long diagchar_compat_ioctl(struct file *filp, return -EFAULT; result = diag_ioctl_query_pd_logging(&mode_param); break; + case DIAG_IOCTL_QUERY_MD_PID: + if (copy_from_user((void *)&pid_query, (void __user *)ioarg, + sizeof(pid_query))) { + result = -EFAULT; + break; + } + mutex_lock(&driver->md_session_lock); + diag_ioctl_query_session_pid(&pid_query); + mutex_unlock(&driver->md_session_lock); + + if (copy_to_user((void __user *)ioarg, &pid_query, + sizeof(pid_query))) + result = -EFAULT; + else + result = 0; + break; } return result; } @@ -2614,6 +2722,7 @@ long diagchar_ioctl(struct file *filp, uint16_t remote_dev; struct diag_dci_client_tbl *dci_client = NULL; struct diag_logging_mode_param_t mode_param; + struct diag_query_pid_t pid_query; switch (iocmd) { case DIAG_IOCTL_COMMAND_REG: @@ -2732,6 +2841,23 @@ long diagchar_ioctl(struct file *filp, return -EFAULT; result = diag_ioctl_query_pd_logging(&mode_param); break; + case DIAG_IOCTL_QUERY_MD_PID: + if (copy_from_user((void *)&pid_query, (void __user *)ioarg, + sizeof(pid_query))) { + result = -EFAULT; + break; + } + + mutex_lock(&driver->md_session_lock); + diag_ioctl_query_session_pid(&pid_query); + mutex_unlock(&driver->md_session_lock); + + if (copy_to_user((void __user *)ioarg, &pid_query, + sizeof(pid_query))) + result = -EFAULT; + else + result = 0; + break; } return result; } @@ -2744,6 +2870,7 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, struct diag_apps_data_t *data = &hdlc_data; struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 }; struct diag_hdlc_dest_type enc = { NULL, NULL, 0 }; + unsigned long flags; /* * The maximum encoded size of the buffer can be atmost twice the length * of the packet. Add three bytes foe footer - 16 bit CRC (2 bytes) + @@ -2848,10 +2975,11 @@ static int diag_process_apps_data_hdlc(unsigned char *buf, int len, return PKT_ALLOC; fail_free_buf: + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, data->buf, POOL_TYPE_HDLC); data->buf = NULL; data->len = 0; - + spin_unlock_irqrestore(&driver->diagmem_lock, flags); fail_ret: return ret; } @@ -2863,6 +2991,7 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len, int ret = PKT_DROP; struct diag_pkt_frame_t header; struct diag_apps_data_t *data = &non_hdlc_data; + unsigned long flags; /* * The maximum packet size, when the data is non hdlc encoded is equal * to the size of the packet frame header and the length. Add 1 for the @@ -2927,10 +3056,11 @@ static int diag_process_apps_data_non_hdlc(unsigned char *buf, int len, return PKT_ALLOC; fail_free_buf: + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, data->buf, POOL_TYPE_HDLC); data->buf = NULL; data->len = 0; - + spin_unlock_irqrestore(&driver->diagmem_lock, flags); fail_ret: return ret; } diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index f1bc1c5047e1..d637405a71d1 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-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 @@ -1823,9 +1823,11 @@ static int diagfwd_mux_write_done(unsigned char *buf, int len, int buf_ctxt, diagfwd_write_done(peripheral, type, num); diag_ws_on_copy(DIAG_WS_MUX); } else if (peripheral == APPS_DATA) { + spin_lock_irqsave(&driver->diagmem_lock, flags); diagmem_free(driver, (unsigned char *)buf, POOL_TYPE_HDLC); buf = NULL; + spin_unlock_irqrestore(&driver->diagmem_lock, flags); } else { pr_err_ratelimited("diag: Invalid peripheral %d in %s, type: %d\n", peripheral, __func__, type); diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index a6d5ca8a952a..7a7d0fc27d05 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -619,7 +619,12 @@ static int update_msg_mask_tbl_entry(struct diag_msg_mask_t *mask, } if (range->ssid_last >= mask->ssid_last) { temp_range = range->ssid_last - mask->ssid_first + 1; - mask->ssid_last = range->ssid_last; + if (temp_range > MAX_SSID_PER_RANGE) { + temp_range = MAX_SSID_PER_RANGE; + mask->ssid_last = mask->ssid_first + temp_range - 1; + } else + mask->ssid_last = range->ssid_last; + mask->ssid_last_tools = mask->ssid_last; mask->range = temp_range; } diff --git a/drivers/char/diag/diagmem.c b/drivers/char/diag/diagmem.c index ada645d92104..2a3602568a1d 100644 --- a/drivers/char/diag/diagmem.c +++ b/drivers/char/diag/diagmem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2014, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2014, 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 @@ -221,7 +221,7 @@ void diagmem_free(struct diagchar_dev *driver, void *buf, int pool_type) break; } spin_lock_irqsave(&mempool->lock, flags); - if (mempool->count > 0) { + if (mempool->count > 0 && buf) { mempool_free(buf, mempool->pool); atomic_add(-1, (atomic_t *)&mempool->count); } else { diff --git a/drivers/clk/msm/clock-gcc-8952.c b/drivers/clk/msm/clock-gcc-8952.c index 71f0ea6fb746..ed39a8ba777f 100644 --- a/drivers/clk/msm/clock-gcc-8952.c +++ b/drivers/clk/msm/clock-gcc-8952.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * 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 @@ -371,6 +371,7 @@ DEFINE_EXT_CLK(gpll0_clk_src, NULL); DEFINE_EXT_CLK(gpll0_ao_clk_src, NULL); DEFINE_EXT_CLK(gpll0_out_aux_clk_src, &gpll0_clk_src.c); DEFINE_EXT_CLK(gpll0_out_main_clk_src, &gpll0_clk_src.c); +DEFINE_EXT_CLK(gpll0_gfx_clk_src, &gpll0_clk_src.c); DEFINE_EXT_CLK(ext_pclk0_clk_src, NULL); DEFINE_EXT_CLK(ext_byte0_clk_src, NULL); DEFINE_EXT_CLK(ext_pclk1_clk_src, NULL); @@ -428,6 +429,7 @@ static struct pll_vote_clk gpll6_clk_src = { DEFINE_EXT_CLK(gpll6_aux_clk_src, &gpll6_clk_src.c); DEFINE_EXT_CLK(gpll6_out_main_clk_src, &gpll6_clk_src.c); +DEFINE_EXT_CLK(gpll6_gfx_clk_src, &gpll6_clk_src.c); static struct alpha_pll_masks pll_masks_p = { .lock_mask = BIT(31), @@ -873,6 +875,28 @@ static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_8917_650MHz[] = { F_END }; +static struct clk_freq_tbl ftbl_gcc_oxili_gfx3d_clk_qm215[] = { + F_SLEW( 19200000, FIXED_CLK_SRC, xo, 1, 0, 0), + F_SLEW( 50000000, FIXED_CLK_SRC, gpll0_gfx, 16, 0, 0), + F_SLEW( 80000000, FIXED_CLK_SRC, gpll0_gfx, 10, 0, 0), + F_SLEW( 100000000, FIXED_CLK_SRC, gpll0_gfx, 8, 0, 0), + F_SLEW( 160000000, FIXED_CLK_SRC, gpll0_gfx, 5, 0, 0), + F_SLEW( 200000000, FIXED_CLK_SRC, gpll0_gfx, 4, 0, 0), + F_SLEW( 228570000, FIXED_CLK_SRC, gpll0_gfx, 3.5, 0, 0), + F_SLEW( 240000000, FIXED_CLK_SRC, gpll6_gfx, 4.5, 0, 0), + F_SLEW( 266670000, FIXED_CLK_SRC, gpll0_gfx, 3, 0, 0), + F_SLEW( 270000000, FIXED_CLK_SRC, gpll6_gfx, 4, 0, 0), + F_SLEW( 320000000, FIXED_CLK_SRC, gpll0_gfx, 2.5, 0, 0), + F_SLEW( 400000000, FIXED_CLK_SRC, gpll0_gfx, 2, 0, 0), + F_SLEW( 465000000, 930000000, gpll3, 1, 0, 0), + F_SLEW( 484800000, 969600000, gpll3, 1, 0, 0), + F_SLEW( 500000000, 1000000000, gpll3, 1, 0, 0), + F_SLEW( 523200000, 1046400000, gpll3, 1, 0, 0), + F_SLEW( 550000000, 1100000000, gpll3, 1, 0, 0), + F_SLEW( 598000000, 1196000000, gpll3, 1, 0, 0), + F_END +}; + static struct rcg_clk gfx3d_clk_src = { .cmd_rcgr_reg = GFX3D_CMD_RCGR, .set_rate = set_rate_hid, @@ -4388,6 +4412,7 @@ static int msm_gcc_probe(struct platform_device *pdev) bool compat_bin4 = false; bool compat_bin5 = false; bool compat_bin6 = false; + bool compat_bin7 = false; compat_bin = of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-8937"); @@ -4407,11 +4432,14 @@ static int msm_gcc_probe(struct platform_device *pdev) compat_bin6 = of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdm439"); + compat_bin7 = of_device_is_compatible(pdev->dev.of_node, + "qcom,gcc-qm215"); + ret = vote_bimc(&bimc_clk, INT_MAX); if (ret < 0) return ret; - if (compat_bin2 || compat_bin4 || compat_bin5) + if (compat_bin2 || compat_bin4 || compat_bin5 || compat_bin7) nbases = APCS_C0_PLL_BASE; if (compat_bin5 || compat_bin6) { @@ -4444,7 +4472,7 @@ static int msm_gcc_probe(struct platform_device *pdev) return PTR_ERR(vdd_dig.regulator[0]); } - if (!compat_bin2 && !compat_bin4 && !compat_bin5) { + if (!compat_bin2 && !compat_bin4 && !compat_bin5 && !compat_bin7) { vdd_sr2_pll.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_sr2_pll"); if (IS_ERR(vdd_sr2_pll.regulator[0])) { @@ -4538,7 +4566,7 @@ static int msm_gcc_probe(struct platform_device *pdev) 475000000; } } - } else if (compat_bin2 || compat_bin4) { + } else if (compat_bin2 || compat_bin4 || compat_bin7) { gpll0_clk_src.c.parent = &gpll0_clk_src_8937.c; gpll0_ao_clk_src.c.parent = &gpll0_ao_clk_src_8937.c; vdd_dig.num_levels = VDD_DIG_NUM_8917; @@ -4548,6 +4576,9 @@ static int msm_gcc_probe(struct platform_device *pdev) get_speed_bin(pdev, &speed_bin); override_for_8917(speed_bin); + if (compat_bin7) + OVERRIDE_FTABLE(gfx3d, ftbl_gcc_oxili_gfx3d_clk, qm215); + if (compat_bin2) { blsp1_qup2_spi_apps_clk_src.freq_tbl = ftbl_gcc_blsp1_2_qup1_4_spi_apps_clk_8917; @@ -4577,7 +4608,7 @@ static int msm_gcc_probe(struct platform_device *pdev) ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_lookup_8937, ARRAY_SIZE(msm_clocks_lookup_8937)); - else if (compat_bin2) + else if (compat_bin2 || compat_bin7) ret = of_msm_clock_register(pdev->dev.of_node, msm_clocks_lookup_8917, ARRAY_SIZE(msm_clocks_lookup_8917)); @@ -4650,6 +4681,7 @@ static const struct of_device_id msm_clock_gcc_match_table[] = { { .compatible = "qcom,gcc-8920" }, { .compatible = "qcom,gcc-sdm439" }, { .compatible = "qcom,gcc-sdm429" }, + { .compatible = "qcom,gcc-qm215" }, {} }; diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 6254f45ca907..2ba2c204758b 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -29,8 +29,10 @@ static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS); -static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */ -static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */ +/* task->time_in_state */ +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(task_time_in_state_lock); +/* uid_hash_table */ +static __cacheline_aligned_in_smp DEFINE_SPINLOCK(uid_lock); struct uid_entry { uid_t uid; diff --git a/drivers/crypto/msm/ice.c b/drivers/crypto/msm/ice.c index 3c90fe5527f7..d13d8897fcec 100644 --- a/drivers/crypto/msm/ice.c +++ b/drivers/crypto/msm/ice.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -1798,7 +1798,7 @@ int qcom_ice_setup_ice_hw(const char *storage_type, int enable) if (ice_dev == ERR_PTR(-EPROBE_DEFER)) return -EPROBE_DEFER; - if (!ice_dev) + if (!ice_dev || (ice_dev->is_ice_enabled == false)) return ret; if (enable) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index bfe98b505cf6..5396a35ff4bb 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -1,5 +1,5 @@ /* - * 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 @@ -780,12 +780,10 @@ static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl, } static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl, - u32 rate, u32 stream_rate_khz, - bool fixed_nvid) + u32 rate, u32 stream_rate_khz) { u32 pixel_m, pixel_n; u32 mvid, nvid; - u64 mvid_calc; u32 const nvid_fixed = 0x8000; u32 const link_rate_hbr2 = 540000; u32 const link_rate_hbr3 = 810000; @@ -798,44 +796,31 @@ static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl, } catalog = dp_catalog_get_priv(ctrl); - if (fixed_nvid) { - pr_debug("use fixed NVID=0x%x\n", nvid_fixed); - nvid = nvid_fixed; - - pr_debug("link rate=%dkbps, stream_rate_khz=%uKhz", - rate, stream_rate_khz); - - /* - * For intermediate results, use 64 bit arithmetic to avoid - * loss of precision. - */ - mvid_calc = (u64) stream_rate_khz * nvid; - mvid_calc = div_u64(mvid_calc, rate); - - /* - * truncate back to 32 bits as this final divided value will - * always be within the range of a 32 bit unsigned int. - */ - mvid = (u32) mvid_calc; - } else { - io_data = catalog->io.dp_mmss_cc; - - pixel_m = dp_read(catalog, io_data, MMSS_DP_PIXEL_M); - pixel_n = dp_read(catalog, io_data, MMSS_DP_PIXEL_N); - pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); + io_data = catalog->io.dp_mmss_cc; - mvid = (pixel_m & 0xFFFF) * 5; - nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); + pixel_m = dp_read(catalog, io_data, MMSS_DP_PIXEL_M); + pixel_n = dp_read(catalog, io_data, MMSS_DP_PIXEL_N); + pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); - pr_debug("rate = %d\n", rate); + mvid = (pixel_m & 0xFFFF) * 5; + nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); - if (link_rate_hbr2 == rate) - nvid *= 2; + if (nvid < nvid_fixed) { + u32 temp; - if (link_rate_hbr3 == rate) - nvid *= 3; + temp = (nvid_fixed / nvid) * nvid; + mvid = (nvid_fixed / nvid) * mvid; + nvid = temp; } + pr_debug("rate = %d\n", rate); + + if (link_rate_hbr2 == rate) + nvid *= 2; + + if (link_rate_hbr3 == rate) + nvid *= 3; + io_data = catalog->io.dp_link; pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid); dp_write(catalog, io_data, DP_SOFTWARE_MVID, mvid); diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h index 743468de6c26..dbcbd8b0efd9 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ b/drivers/gpu/drm/msm/dp/dp_catalog.h @@ -1,5 +1,5 @@ /* - * 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 @@ -94,7 +94,7 @@ struct dp_catalog_ctrl { void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable); void (*config_misc)(struct dp_catalog_ctrl *ctrl, u32 cc, u32 tb); void (*config_msa)(struct dp_catalog_ctrl *ctrl, u32 rate, - u32 stream_rate_khz, bool fixed_nvid); + u32 stream_rate_khz); void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern); void (*reset)(struct dp_catalog_ctrl *ctrl); void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip); diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c index f2e9085cb5a2..befbc5c7f9f9 100644 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + * 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 @@ -1177,24 +1177,6 @@ static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) pr_debug("Host deinitialized successfully\n"); } -static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) -{ - u8 *dpcd = ctrl->panel->dpcd; - - /* - * For better interop experience, used a fixed NVID=0x8000 - * whenever connected to a VGA dongle downstream. - */ - if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) { - u8 type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & - DP_DWN_STRM_PORT_TYPE_MASK; - if (type == DP_DWN_STRM_PORT_TYPE_ANALOG) - return true; - } - - return false; -} - static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) { int ret = 0; @@ -1247,8 +1229,7 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl) ctrl->catalog->config_msa(ctrl->catalog, drm_dp_bw_code_to_link_rate( - ctrl->link->link_params.bw_code), - ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl)); + ctrl->link->link_params.bw_code), ctrl->pixel_rate); reinit_completion(&ctrl->idle_comp); @@ -1306,9 +1287,7 @@ static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) u32 pattern_sent = 0x0; u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; - ctrl->catalog->update_vx_px(ctrl->catalog, - ctrl->link->phy_params.v_level, - ctrl->link->phy_params.p_level); + dp_ctrl_update_vx_px(ctrl); ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); ctrl->link->send_test_response(ctrl->link); @@ -1416,8 +1395,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) { ctrl->catalog->config_msa(ctrl->catalog, drm_dp_bw_code_to_link_rate( - ctrl->link->link_params.bw_code), - ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl)); + ctrl->link->link_params.bw_code), ctrl->pixel_rate); rc = dp_ctrl_setup_main_link(ctrl, true); if (!rc) diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 6e6efa5cd416..64945cf752cd 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -1,5 +1,5 @@ /* - * 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 @@ -49,6 +49,7 @@ struct dp_debug_private { struct device *dev; struct work_struct sim_work; struct dp_debug dp_debug; + struct mutex lock; }; static int dp_debug_get_edid_buf(struct dp_debug_private *debug) @@ -98,6 +99,8 @@ static ssize_t dp_debug_write_edid(struct file *file, if (!debug) return -ENODEV; + mutex_lock(&debug->lock); + if (*ppos) goto bail; @@ -148,6 +151,7 @@ bail: if (!debug->dp_debug.sim_mode) debug->panel->set_edid(debug->panel, edid); + mutex_unlock(&debug->lock); return rc; } @@ -166,6 +170,8 @@ static ssize_t dp_debug_write_dpcd(struct file *file, if (!debug) return -ENODEV; + mutex_lock(&debug->lock); + if (*ppos) goto bail; @@ -230,6 +236,7 @@ bail: else debug->panel->set_dpcd(debug->panel, dpcd); + mutex_unlock(&debug->lock); return rc; } @@ -873,6 +880,8 @@ static ssize_t dp_debug_write_sim(struct file *file, if (*ppos) return 0; + mutex_lock(&debug->lock); + /* Leave room for termination char */ len = min_t(size_t, count, SZ_8 - 1); if (copy_from_user(buf, user_buff, len)) @@ -906,9 +915,11 @@ static ssize_t dp_debug_write_sim(struct file *file, debug->aux->set_sim_mode(debug->aux, debug->dp_debug.sim_mode, debug->edid, debug->dpcd); end: + mutex_unlock(&debug->lock); return len; error: devm_kfree(debug->dev, debug->edid); + mutex_unlock(&debug->lock); return len; } @@ -1272,6 +1283,8 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, dp_debug->hdisplay = 0; dp_debug->vrefresh = 0; + mutex_init(&debug->lock); + rc = dp_debug_init(dp_debug); if (rc) { devm_kfree(dev, debug); @@ -1308,6 +1321,8 @@ void dp_debug_put(struct dp_debug *dp_debug) dp_debug_deinit(dp_debug); + mutex_destroy(&debug->lock); + if (debug->edid) devm_kfree(debug->dev, debug->edid); diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index a0a0daf42c6a..f80c371b4666 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1,5 +1,5 @@ /* - * 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 @@ -140,9 +140,18 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) struct sde_hdcp_ops *ops; int rc = 0; u32 hdcp_auth_state; + u8 sink_status = 0; dp = container_of(dw, struct dp_display_private, hdcp_cb_work); + drm_dp_dpcd_readb(dp->aux->drm_aux, DP_SINK_STATUS, &sink_status); + sink_status &= (DP_RECEIVE_PORT_0_STATUS | DP_RECEIVE_PORT_1_STATUS); + if (sink_status < 1) { + pr_debug("Sink not synchronized. Queuing again then exiting\n"); + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ); + return; + } + rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl); if (rc >= 0) { hdcp_auth_state = (rc >> 20) & 0x3; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h index cdcb331dbf9d..9f81ed1411e0 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -261,13 +261,13 @@ void *dsi_register_clk_handle(void *clk_mngr, char *client); int dsi_deregister_clk_handle(void *client); /** - * dsi_display_link_clk_force_update_ctrl() - force to set link clks + * dsi_display_link_clk_force_update() - force to set link clks * @handle: Handle of desired DSI clock client. * * return: error code in case of failure or 0 for success. */ -int dsi_display_link_clk_force_update_ctrl(void *handle); +int dsi_display_link_clk_force_update(void *handle); /** * dsi_display_clk_ctrl() - set frequencies for link clks @@ -277,7 +277,8 @@ int dsi_display_link_clk_force_update_ctrl(void *handle); * * return: error code in case of failure or 0 for success. */ -int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state); +int dsi_display_clk_ctrl(void *handle, enum dsi_clk_type clk_type, + enum dsi_clk_state clk_state); /** * dsi_clk_set_link_frequencies() - set frequencies for link clks @@ -331,4 +332,14 @@ int dsi_clk_prepare_enable(struct dsi_clk_link_set *clk); * @clk: list of src clocks. */ void dsi_clk_disable_unprepare(struct dsi_clk_link_set *clk); + +/** + * dsi_clk_req_state() - request to change dsi clock state + * @client: DSI clocl client pointer. + * @clk: DSI clock list. + * @state: Requested state of the clock. + */ +int dsi_clk_req_state(void *client, enum dsi_clk_type clk, + enum dsi_clk_state state); + #endif /* _DSI_CLK_H_ */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c index 9592603f7491..2faccadd829c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -1255,9 +1255,7 @@ int dsi_clk_req_state(void *client, enum dsi_clk_type clk, return rc; } -DEFINE_MUTEX(dsi_mngr_clk_mutex); - -static int dsi_display_link_clk_force_update(void *client) +int dsi_display_link_clk_force_update(void *client) { int rc = 0; struct dsi_clk_client_info *c = client; @@ -1304,42 +1302,6 @@ error: } -int dsi_display_link_clk_force_update_ctrl(void *handle) -{ - int rc = 0; - - if (!handle) { - pr_err("%s: Invalid arg\n", __func__); - return -EINVAL; - } - - mutex_lock(&dsi_mngr_clk_mutex); - - rc = dsi_display_link_clk_force_update(handle); - - mutex_unlock(&dsi_mngr_clk_mutex); - - return rc; -} - -int dsi_display_clk_ctrl(void *handle, u32 clk_type, u32 clk_state) -{ - int rc = 0; - - if (!handle) { - pr_err("%s: Invalid arg\n", __func__); - return -EINVAL; - } - - mutex_lock(&dsi_mngr_clk_mutex); - rc = dsi_clk_req_state(handle, clk_type, clk_state); - if (rc) - pr_err("%s: failed set clk state, rc = %d\n", __func__, rc); - mutex_unlock(&dsi_mngr_clk_mutex); - - return rc; -} - void *dsi_register_clk_handle(void *clk_mngr, char *client) { void *handle = NULL; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index f8170b2df2b1..612cea70f4f1 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -45,6 +45,9 @@ static DEFINE_MUTEX(dsi_display_list_lock); static LIST_HEAD(dsi_display_list); + +static DEFINE_MUTEX(dsi_display_clk_mutex); + static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN]; static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN]; static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY]; @@ -4261,6 +4264,7 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, int i; struct dsi_display_ctrl *ctrl; struct dsi_display_mode_priv_info *priv_info; + struct dsi_host_config *config; priv_info = mode->priv_info; if (!dsi_display_has_ext_bridge(display) && !priv_info) { @@ -4269,9 +4273,9 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, return -EINVAL; } - rc = dsi_panel_get_host_cfg_for_mode(display->panel, - mode, - &display->config); + config = &display->config; + + rc = dsi_panel_get_host_cfg_for_mode(display->panel, mode, config); if (rc) { pr_err("[%s] failed to get host config for mode, rc=%d\n", display->name, rc); @@ -4303,8 +4307,16 @@ static int dsi_display_set_mode_sub(struct dsi_display *display, for (i = 0; i < display->ctrl_count; i++) { ctrl = &display->ctrl[i]; - rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config, - mode->dsi_mode_flags, display->dsi_clk_handle); + /* + * if bit clock is overridden then update the phy timings + * and clock out control values first. + */ + if (config->bit_clk_rate_hz) + dsi_phy_update_phy_timings(ctrl->phy, config); + + rc = dsi_ctrl_update_host_config(ctrl->ctrl, config, + mode->dsi_mode_flags, + display->dsi_clk_handle); if (rc) { pr_err("[%s] failed to update ctrl config, rc=%d\n", display->name, rc); @@ -4515,6 +4527,43 @@ int dsi_display_splash_res_cleanup(struct dsi_display *display) return rc; } +static int dsi_display_link_clk_force_update_ctrl(void *handle) +{ + int rc = 0; + + if (!handle) { + pr_err("%s: Invalid arg\n", __func__); + return -EINVAL; + } + + mutex_lock(&dsi_display_clk_mutex); + + rc = dsi_display_link_clk_force_update(handle); + + mutex_unlock(&dsi_display_clk_mutex); + + return rc; +} + +int dsi_display_clk_ctrl(void *handle, + enum dsi_clk_type clk_type, enum dsi_clk_state clk_state) +{ + int rc = 0; + + if (!handle) { + pr_err("%s: Invalid arg\n", __func__); + return -EINVAL; + } + + mutex_lock(&dsi_display_clk_mutex); + rc = dsi_clk_req_state(handle, clk_type, clk_state); + if (rc) + pr_err("%s: failed set clk state, rc = %d\n", __func__, rc); + mutex_unlock(&dsi_display_clk_mutex); + + return rc; +} + static int dsi_display_force_update_dsi_clk(struct dsi_display *display) { int rc = 0; @@ -4603,6 +4652,7 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev, mutex_lock(&display->display_lock); + mutex_lock(&dsi_display_clk_mutex); display->cached_clk_rate = clk_rate; rc = dsi_display_update_dsi_bitrate(display, clk_rate); if (!rc) { @@ -4615,12 +4665,14 @@ static ssize_t sysfs_dynamic_dsi_clk_write(struct device *dev, atomic_set(&display->clkrate_change_pending, 0); display->cached_clk_rate = 0; + mutex_unlock(&dsi_display_clk_mutex); mutex_unlock(&display->display_lock); return rc; } atomic_set(&display->clkrate_change_pending, 1); + mutex_unlock(&dsi_display_clk_mutex); mutex_unlock(&display->display_lock); return count; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 8e78ae55b7f9..b43b23cda9c3 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1998,6 +1998,7 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, { int rc = 0; const char *bl_type; + const char *data; u32 val = 0; bl_type = of_get_property(of_node, @@ -2017,6 +2018,17 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel, panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN; } + data = of_get_property(of_node, "qcom,bl-update-flag", NULL); + if (!data) { + panel->bl_config.bl_update = BL_UPDATE_NONE; + } else if (!strcmp(data, "delay_until_first_frame")) { + panel->bl_config.bl_update = BL_UPDATE_DELAY_UNTIL_FIRST_FRAME; + } else { + pr_debug("[%s] No valid bl-update-flag: %s\n", + panel->name, data); + panel->bl_config.bl_update = BL_UPDATE_NONE; + } + panel->bl_config.bl_scale = MAX_BL_SCALE_LEVEL; panel->bl_config.bl_scale_ad = MAX_AD_BL_SCALE_LEVEL; @@ -2115,7 +2127,7 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc) int target_bpp_x16; int data; int final_value, final_scale; - int ratio_index; + int ratio_index, mod_offset; dsc->rc_model_size = 8192; @@ -2187,7 +2199,20 @@ int dsi_dsc_populate_static_param(struct msm_display_dsc_info *dsc) dsc->quant_incr_limit1 = 19; } - dsc->slice_last_group_size = 3 - (dsc->slice_width % 3); + mod_offset = dsc->slice_width % 3; + switch (mod_offset) { + case 0: + dsc->slice_last_group_size = 2; + break; + case 1: + dsc->slice_last_group_size = 0; + break; + case 2: + dsc->slice_last_group_size = 1; + break; + default: + break; + } dsc->det_thresh_flatness = 7 + 2*(bpc - 8); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index ac55d7d2b5e2..ab8ccee9fb98 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -51,6 +51,11 @@ enum dsi_backlight_type { DSI_BACKLIGHT_MAX, }; +enum bl_update_flag { + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME, + BL_UPDATE_NONE, +}; + enum { MODE_GPIO_NOT_VALID = 0, MODE_SEL_DUAL_PORT, @@ -93,6 +98,7 @@ struct dsi_panel_phy_props { struct dsi_backlight_config { enum dsi_backlight_type type; + enum bl_update_flag bl_update; u32 bl_min_level; u32 bl_max_level; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index ebc699aa13ff..32497ffe9abd 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -883,6 +883,8 @@ int dsi_phy_update_phy_timings(struct msm_dsi_phy *phy, &phy->cfg.timing, true); if (rc) pr_err("failed to calculate phy timings %d\n", rc); + else + phy->cfg.is_phy_timing_present = true; return rc; } @@ -1045,6 +1047,9 @@ int dsi_phy_set_timing_params(struct msm_dsi_phy *phy, return -EINVAL; } + if (phy->cfg.is_phy_timing_present) + return rc; + mutex_lock(&phy->phy_lock); if (phy->hw.ops.phy_timing_val) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c index 44d092846117..5d9759d90467 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_calc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -434,6 +434,44 @@ error: return rc; } +static int calc_clk_post(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + struct timing_entry *t = &desc->clk_post; + int temp = 0, rc; + + temp = DIV_ROUND_UP(((60 * clk_params->bitclk_mbps) + 9000), 8000) - 1; + t->rec = DIV_ROUND_UP((t->rec_max + (9 * temp)), 10); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_post"); + + pr_debug("clk_post val 0x%x\n", t->reg_value); + return rc; +} + +static int calc_clk_pre(struct dsi_phy_hw *phy, + struct phy_clk_params *clk_params, + struct phy_timing_desc *desc) +{ + struct timing_entry *t = &desc->clk_pre; + int temp = 0, rc; + + temp = desc->clk_prepare.reg_value + desc->clk_zero.reg_value + + desc->hs_rqst_clk.reg_value + 2; + + if (temp > t->rec_max) { + t->rec = DIV_ROUND_UP(((2 * t->rec_max) + (9 * temp)), 10); + t->rec = t->rec / 2; + } else + t->rec = DIV_ROUND_UP((t->rec_max + (9 * temp)), 10); + + rc = dsi_phy_cmn_validate_and_set(t, "clk_pre"); + + pr_debug("clk_pre val 0x%x\n", t->reg_value); + return rc; +} + /** * dsi_phy_calc_timing_params - calculates timing paramets for a given bit clock */ @@ -501,6 +539,19 @@ static int dsi_phy_cmn_calc_timing_params(struct dsi_phy_hw *phy, pr_err("hs_rqst_clk calculations failed, rc=%d\n", rc); goto error; } + + rc = calc_clk_post(phy, clk_params, desc); + if (rc) { + pr_err("clk_post calculation failed, rc= %d\n", rc); + goto error; + } + + rc = calc_clk_pre(phy, clk_params, desc); + if (rc) { + pr_err("clk_pre calculation failed, rc= %d\n", rc); + goto error; + } + error: return rc; } @@ -582,6 +633,8 @@ int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy, desc.hs_exit.rec_max = hs_exit_reco_max; desc.hs_rqst.mipi_min = hs_rqst_spec_min; desc.hs_rqst_clk.mipi_min = hs_rqst_spec_min; + desc.clk_post.rec_max = 63; + desc.clk_pre.rec_max = 63; if (ops->get_default_phy_params) { ops->get_default_phy_params(&clk_params); @@ -611,6 +664,9 @@ int dsi_phy_hw_calculate_timing_params(struct dsi_phy_hw *phy, if (ops->update_timing_params) { ops->update_timing_params(timing, &desc); + /* update clock out timing control values */ + host->t_clk_pre = desc.clk_pre.reg_value; + host->t_clk_post = desc.clk_post.reg_value; } else { rc = -EINVAL; goto error; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c index c0e9d441542d..c169a435981b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v3_0.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * 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 @@ -17,14 +17,14 @@ void dsi_phy_hw_v3_0_get_default_phy_params( struct phy_clk_params *params) { - params->clk_prep_buf = 0; - params->clk_zero_buf = 0; - params->clk_trail_buf = 0; - params->hs_prep_buf = 0; - params->hs_zero_buf = 0; - params->hs_trail_buf = 0; + params->clk_prep_buf = 50; + params->clk_zero_buf = 2; + params->clk_trail_buf = 30; + params->hs_prep_buf = 50; + params->hs_zero_buf = 10; + params->hs_trail_buf = 30; params->hs_rqst_buf = 0; - params->hs_exit_buf = 0; + params->hs_exit_buf = 10; } int32_t dsi_phy_hw_v3_0_calc_clk_zero(s64 rec_temp1, s64 mult) diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 4b152ac05e86..a4d71f79da6a 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -50,6 +50,7 @@ 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 @@ -63,6 +64,7 @@ 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 diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c index 8680449b3e88..378847d92308 100644 --- a/drivers/gpu/drm/msm/sde/sde_color_processing.c +++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c @@ -1862,24 +1862,29 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en, node = container_of(ad_irq, struct sde_crtc_irq_info, irq); + /* deregister AD irq */ if (!en) { spin_lock_irqsave(&node->state_lock, flags); if (node->state == IRQ_ENABLED) { + node->state = IRQ_DISABLING; + spin_unlock_irqrestore(&node->state_lock, flags); ret = sde_core_irq_disable(kms, &irq_idx, 1); - if (ret) + spin_lock_irqsave(&node->state_lock, flags); + if (ret) { DRM_ERROR("disable irq %d error %d\n", irq_idx, ret); - else - node->state = IRQ_NOINIT; - } else { - node->state = IRQ_NOINIT; + node->state = IRQ_ENABLED; + } else { + node->state = IRQ_DISABLED; + } } spin_unlock_irqrestore(&node->state_lock, flags); + sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); - ret = 0; goto exit; } + /* register AD irq */ ad_irq->arg = crtc; ad_irq->func = sde_cp_ad_interrupt_cb; ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq); @@ -1889,11 +1894,15 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en, } spin_lock_irqsave(&node->state_lock, flags); - if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) { + if (node->state == IRQ_DISABLED) { + node->state = IRQ_ENABLING; + spin_unlock_irqrestore(&node->state_lock, flags); ret = sde_core_irq_enable(kms, &irq_idx, 1); + spin_lock_irqsave(&node->state_lock, flags); if (ret) { DRM_ERROR("enable irq %d error %d\n", irq_idx, ret); sde_core_irq_unregister_callback(kms, irq_idx, ad_irq); + node->state = IRQ_DISABLED; } else { node->state = IRQ_ENABLED; } @@ -2138,15 +2147,10 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en, irq_idx, ret); node->state = IRQ_ENABLED; } else { - node->state = IRQ_NOINIT; + node->state = IRQ_DISABLED; } - spin_unlock_irqrestore(&node->state_lock, flags); - } else if (node->state == IRQ_DISABLED) { - node->state = IRQ_NOINIT; - spin_unlock_irqrestore(&node->state_lock, flags); - } else { - spin_unlock_irqrestore(&node->state_lock, flags); } + spin_unlock_irqrestore(&node->state_lock, flags); sde_core_irq_unregister_callback(kms, irq_idx, hist_irq); goto exit; @@ -2162,12 +2166,16 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en, } spin_lock_irqsave(&node->state_lock, flags); - if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) { + if (node->state == IRQ_DISABLED) { + node->state = IRQ_ENABLING; + spin_unlock_irqrestore(&node->state_lock, flags); ret = sde_core_irq_enable(kms, &irq_idx, 1); + spin_lock_irqsave(&node->state_lock, flags); if (ret) { DRM_ERROR("enable irq %d error %d\n", irq_idx, ret); sde_core_irq_unregister_callback(kms, irq_idx, hist_irq); + node->state = IRQ_DISABLED; } else { node->state = IRQ_ENABLED; } diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index fce87e34ccaf..85b9f7e153a9 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -89,12 +89,19 @@ static int sde_backlight_device_update_status(struct backlight_device *bd) if (!bl_lvl && brightness) bl_lvl = 1; + if (display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) { + c_conn->unset_bl_level = bl_lvl; + return 0; + } + if (c_conn->ops.set_backlight) { event.type = DRM_EVENT_SYS_BACKLIGHT; event.length = sizeof(u32); msm_mode_object_event_notify(&c_conn->base.base, c_conn->base.dev, &event, (u8 *)&brightness); rc = c_conn->ops.set_backlight(c_conn->display, bl_lvl); + c_conn->unset_bl_level = 0; } return rc; @@ -519,6 +526,15 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) bl_config = &dsi_display->panel->bl_config; + if (dsi_display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) { + c_conn->unset_bl_level = bl_config->bl_level; + return 0; + } + + if (c_conn->unset_bl_level) + bl_config->bl_level = c_conn->unset_bl_level; + if (c_conn->bl_scale > MAX_BL_SCALE_LEVEL) bl_config->bl_scale = MAX_BL_SCALE_LEVEL; else @@ -533,6 +549,7 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn) bl_config->bl_scale, bl_config->bl_scale_ad, bl_config->bl_level); rc = c_conn->ops.set_backlight(dsi_display, bl_config->bl_level); + c_conn->unset_bl_level = 0; return rc; } @@ -572,8 +589,11 @@ static int _sde_connector_update_dirty_properties( } } - /* Special handling for postproc properties */ - if (c_conn->bl_scale_dirty) { + /* + * Special handling for postproc properties and + * for updating backlight if any unset backlight level is present + */ + if (c_conn->bl_scale_dirty || c_conn->unset_bl_level) { _sde_connector_update_bl_scale(c_conn); c_conn->bl_scale_dirty = false; } @@ -639,29 +659,44 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector) sde_connector_schedule_status_work(connector, false); c_conn = to_sde_connector(connector); - if (c_conn->panel_dead) { + if (c_conn->bl_device) { c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; c_conn->bl_device->props.state |= BL_CORE_FBBLANK; backlight_update_status(c_conn->bl_device); } + + c_conn->allow_bl_update = false; } void sde_connector_helper_bridge_enable(struct drm_connector *connector) { struct sde_connector *c_conn = NULL; + struct dsi_display *display; if (!connector) return; c_conn = to_sde_connector(connector); + display = (struct dsi_display *) c_conn->display; + + /* + * Special handling for some panels which need atleast + * one frame to be transferred to GRAM before enabling backlight. + * So delay backlight update to these panels until the + * first frame commit is received from the HW. + */ + if (display->panel->bl_config.bl_update == + BL_UPDATE_DELAY_UNTIL_FIRST_FRAME) + sde_encoder_wait_for_event(c_conn->encoder, + MSM_ENC_TX_COMPLETE); + c_conn->allow_bl_update = true; - /* Special handling for ESD recovery case */ - if (c_conn->panel_dead) { + if (c_conn->bl_device) { c_conn->bl_device->props.power = FB_BLANK_UNBLANK; c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK; backlight_update_status(c_conn->bl_device); - c_conn->panel_dead = false; } + c_conn->panel_dead = false; } int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index 51dc92ded875..0ae6a91461d1 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -329,7 +329,9 @@ struct sde_connector_evt { * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed * @bl_scale: BL scale value for ABA feature * @bl_scale_ad: BL scale value for AD feature - * last_cmd_tx_sts: status of the last command transfer + * @unset_bl_level: BL level that needs to be set later + * @allow_bl_update: Flag to indicate if BL update is allowed currently or not + * @last_cmd_tx_sts: status of the last command transfer */ struct sde_connector { struct drm_connector base; @@ -373,6 +375,8 @@ struct sde_connector { bool bl_scale_dirty; u32 bl_scale; u32 bl_scale_ad; + u32 unset_bl_level; + bool allow_bl_update; bool last_cmd_tx_sts; }; diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 53a7a60cb09e..e0094d7ec766 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -6216,7 +6216,7 @@ static int _sde_crtc_event_enable(struct sde_kms *kms, INIT_LIST_HEAD(&node->list); node->func = custom_events[i].func; node->event = event; - node->state = IRQ_NOINIT; + node->state = IRQ_DISABLED; spin_lock_init(&node->state_lock); break; } diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 709a51f15618..4700a6cb6a71 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -430,7 +430,7 @@ struct sde_crtc_state { }; enum sde_crtc_irq_state { - IRQ_NOINIT, + IRQ_ENABLING, IRQ_ENABLED, IRQ_DISABLING, IRQ_DISABLED, diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index a1986dbbb659..122f319c7c00 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -1454,7 +1454,7 @@ static void _sde_encoder_update_vsync_source(struct sde_encoder_virt *sde_enc, struct msm_mode_info mode_info; int i, rc = 0; - if (!sde_enc || !disp_info) { + if (!sde_enc || !sde_enc->cur_master || !disp_info) { SDE_ERROR("invalid param sde_enc:%d or disp_info:%d\n", sde_enc != NULL, disp_info != NULL); return; @@ -2708,6 +2708,21 @@ void sde_encoder_virt_restore(struct drm_encoder *drm_enc) _sde_encoder_virt_enable_helper(drm_enc); } +static void sde_encoder_off_work(struct kthread_work *work) +{ + struct sde_encoder_virt *sde_enc = container_of(work, + struct sde_encoder_virt, delayed_off_work.work); + struct drm_encoder *drm_enc; + + if (!sde_enc) { + SDE_ERROR("invalid sde encoder\n"); + return; + } + drm_enc = &sde_enc->base; + + sde_encoder_idle_request(drm_enc); +} + static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) { struct sde_encoder_virt *sde_enc = NULL; @@ -2768,6 +2783,11 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) sde_enc->input_handler_registered = true; } + if (!(msm_is_mode_seamless_vrr(cur_mode) + || msm_is_mode_seamless_dms(cur_mode))) + kthread_init_delayed_work(&sde_enc->delayed_off_work, + sde_encoder_off_work); + ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF); if (ret) { SDE_ERROR_ENC(sde_enc, "sde resource control failed: %d\n", @@ -3094,21 +3114,6 @@ int sde_encoder_idle_request(struct drm_encoder *drm_enc) return 0; } -static void sde_encoder_off_work(struct kthread_work *work) -{ - struct sde_encoder_virt *sde_enc = container_of(work, - struct sde_encoder_virt, delayed_off_work.work); - struct drm_encoder *drm_enc; - - if (!sde_enc) { - SDE_ERROR("invalid sde encoder\n"); - return; - } - drm_enc = &sde_enc->base; - - sde_encoder_idle_request(drm_enc); -} - /** * _sde_encoder_trigger_flush - trigger flush for a physical encoder * drm_enc: Pointer to drm encoder structure diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 4e9430e0d8f8..953106ee9823 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -255,6 +255,7 @@ struct sde_encoder_irq { * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @enable_state: Enable state tracking * @vblank_refcount: Reference count of vblank request + * @wbirq_refcount: Reference count of wb irq request * @vsync_cnt: Vsync count for the physical encoder * @underrun_cnt: Underrun count for the physical encoder * @pending_kickoff_cnt: Atomic counter tracking the number of kickoffs @@ -293,6 +294,7 @@ struct sde_encoder_phys { enum sde_enc_enable_state enable_state; struct mutex *vblank_ctl_lock; atomic_t vblank_refcount; + atomic_t wbirq_refcount; atomic_t vsync_cnt; atomic_t underrun_cnt; atomic_t pending_ctlstart_cnt; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index f06ceb7e5f5c..4409408ba3fe 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -348,6 +348,24 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( struct sde_encoder_phys *phys_enc) { struct sde_encoder_irq *irq; + struct sde_kms *sde_kms = phys_enc->sde_kms; + int ret = 0; + + mutex_lock(&sde_kms->vblank_ctl_global_lock); + + if (atomic_read(&phys_enc->vblank_refcount)) { + SDE_ERROR( + "vblank_refcount mismatch detected, try to reset %d\n", + atomic_read(&phys_enc->vblank_refcount)); + ret = sde_encoder_helper_unregister_irq(phys_enc, + INTR_IDX_RDPTR); + if (ret) + SDE_ERROR( + "control vblank irq registration error %d\n", + ret); + + } + atomic_set(&phys_enc->vblank_refcount, 0); irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; @@ -368,6 +386,8 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( irq = &phys_enc->irq[INTR_IDX_AUTOREFRESH_DONE]; irq->hw_idx = phys_enc->hw_pp->idx; irq->irq_idx = -EINVAL; + + mutex_unlock(&sde_kms->vblank_ctl_global_lock); } static void sde_encoder_phys_cmd_cont_splash_mode_set( @@ -674,13 +694,15 @@ static int sde_encoder_phys_cmd_control_vblank_irq( to_sde_encoder_phys_cmd(phys_enc); int ret = 0; int refcount; + struct sde_kms *sde_kms; if (!phys_enc || !phys_enc->hw_pp) { SDE_ERROR("invalid encoder\n"); return -EINVAL; } + sde_kms = phys_enc->sde_kms; - mutex_lock(phys_enc->vblank_ctl_lock); + mutex_lock(&sde_kms->vblank_ctl_global_lock); refcount = atomic_read(&phys_enc->vblank_refcount); /* Slave encoders don't report vblank */ @@ -698,11 +720,17 @@ static int sde_encoder_phys_cmd_control_vblank_irq( SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, enable, refcount); - if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) { ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR); - else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) + if (ret) + atomic_dec_return(&phys_enc->vblank_refcount); + } else if (!enable && + atomic_dec_return(&phys_enc->vblank_refcount) == 0) { ret = sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR); + if (ret) + atomic_inc_return(&phys_enc->vblank_refcount); + } end: if (ret) { @@ -714,7 +742,7 @@ end: enable, refcount, SDE_EVTLOG_ERROR); } - mutex_unlock(phys_enc->vblank_ctl_lock); + mutex_unlock(&sde_kms->vblank_ctl_global_lock); return ret; } diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 4bbcb3ae567c..1042e207274b 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * 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 @@ -904,7 +904,8 @@ static void sde_encoder_phys_wb_irq_ctrl( { struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys); - int index = 0; + int index = 0, refcount; + int ret = 0; if (!wb_enc) return; @@ -912,17 +913,33 @@ static void sde_encoder_phys_wb_irq_ctrl( if (wb_enc->bypass_irqreg) return; - if (enable) { - sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE); - if (phys->in_clone_mode) { + refcount = atomic_read(&phys->wbirq_refcount); + + if (!enable && !refcount) + return; + + SDE_EVT32(DRMID(phys->parent), enable, + atomic_read(&phys->wbirq_refcount)); + + if (enable && atomic_inc_return(&phys->wbirq_refcount) == 1) { + ret = sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE); + if (ret) + atomic_dec_return(&phys->wbirq_refcount); + + } else if (!enable && + atomic_dec_return(&phys->wbirq_refcount) == 0) { + ret = sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE); + if (ret) + atomic_inc_return(&phys->wbirq_refcount); + } + + if (phys->in_clone_mode) { + if (enable) { for (index = 0; index < CRTC_DUAL_MIXERS; index++) sde_encoder_helper_register_irq(phys, index ? INTR_IDX_PP3_OVFL : INTR_IDX_PP2_OVFL); - } - } else { - sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE); - if (phys->in_clone_mode) { + } else { for (index = 0; index < CRTC_DUAL_MIXERS; index++) sde_encoder_helper_unregister_irq(phys, index ? INTR_IDX_PP3_OVFL @@ -1349,15 +1366,17 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) /* reset h/w before final flush */ if (phys_enc->hw_ctl->ops.clear_pending_flush) phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); - if (sde_encoder_helper_reset_mixers(phys_enc, wb_enc->fb_disable)) + if (sde_encoder_helper_reset_mixers(phys_enc, NULL)) goto exit; phys_enc->enable_state = SDE_ENC_DISABLING; sde_encoder_phys_wb_prepare_for_kickoff(phys_enc, NULL); + sde_encoder_phys_wb_irq_ctrl(phys_enc, true); if (phys_enc->hw_ctl->ops.trigger_flush) phys_enc->hw_ctl->ops.trigger_flush(phys_enc->hw_ctl); sde_encoder_helper_trigger_start(phys_enc); sde_encoder_phys_wb_wait_for_commit_done(phys_enc); + sde_encoder_phys_wb_irq_ctrl(phys_enc, false); exit: phys_enc->enable_state = SDE_ENC_DISABLED; wb_enc->crtc = NULL; @@ -1576,6 +1595,7 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( phys_enc->enc_spinlock = p->enc_spinlock; phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; atomic_set(&phys_enc->pending_retire_fence_cnt, 0); + atomic_set(&phys_enc->wbirq_refcount, 0); irq = &phys_enc->irq[INTR_IDX_WB_DONE]; INIT_LIST_HEAD(&irq->cb.list); diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index baec526f4d31..750cd5794cbd 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -3269,6 +3269,8 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->perf.min_prefill_lines = 24; sde_cfg->vbif_qos_nlvl = 8; sde_cfg->ts_prefill_rev = 2; + sde_cfg->sui_misr_supported = true; + sde_cfg->sui_block_xin_mask = 0x3F71; } else { SDE_ERROR("unsupported chipset id:%X\n", hw_rev); sde_cfg->perf.min_prefill_lines = 0xffff; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c index 9fd3c25b4d49..4fa13bd8fb59 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_dsc.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_dsc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* 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 @@ -65,7 +65,7 @@ static void sde_hw_dsc_config(struct sde_hw_dsc *hw_dsc, initial_lines += 1; data |= (initial_lines << 20); - data |= ((dsc->slice_last_group_size - 1) << 18); + data |= (dsc->slice_last_group_size << 18); /* bpp is 6.4 format, 4 LSBs bits are for fractional part */ lsb = dsc->bpp % 4; bpp = dsc->bpp / 4; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index ed0e7b818da7..6cbd663bec09 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark <robdclark@gmail.com> * @@ -3291,6 +3291,13 @@ static int sde_kms_hw_init(struct msm_kms *kms) if (rc) SDE_DEBUG("sde splash data fetch failed: %d\n", rc); + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) { + priv->phandle.data_bus_handle[i].ab_rt = + SDE_POWER_HANDLE_CONT_SPLASH_BUS_AB_QUOTA; + priv->phandle.data_bus_handle[i].ib_rt = + SDE_POWER_HANDLE_CONT_SPLASH_BUS_IB_QUOTA; + } + rc = sde_power_resource_enable(&priv->phandle, sde_kms->core_client, true); if (rc) { @@ -3420,6 +3427,8 @@ static int sde_kms_hw_init(struct msm_kms *kms) dev->mode_config.max_height = sde_kms->catalog->max_display_height; mutex_init(&sde_kms->secure_transition_lock); + mutex_init(&sde_kms->vblank_ctl_global_lock); + atomic_set(&sde_kms->detach_sec_cb, 0); atomic_set(&sde_kms->detach_all_cb, 0); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index fb79fe79436b..2f1d4181998b 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -288,6 +288,7 @@ struct sde_kms { atomic_t detach_sec_cb; atomic_t detach_all_cb; struct mutex secure_transition_lock; + struct mutex vblank_ctl_global_lock; bool first_kickoff; }; diff --git a/drivers/gpu/drm/msm/sde_hdcp_1x.c b/drivers/gpu/drm/msm/sde_hdcp_1x.c index 2c7f52c7970b..53e20e261ebd 100644 --- a/drivers/gpu/drm/msm/sde_hdcp_1x.c +++ b/drivers/gpu/drm/msm/sde_hdcp_1x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-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 @@ -1263,6 +1263,8 @@ static void sde_hdcp_1x_off(void *input) hdcp->sink_r0_ready = false; + hdcp1_unload_app(); + pr_debug("%s: HDCP: Off\n", SDE_HDCP_STATE_NAME); } /* hdcp_1x_off */ diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 68a7c2a2f987..699aff56bc4f 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2245,7 +2245,7 @@ static int a5xx_microcode_load(struct adreno_device *adreno_dev) desc.args[1] = 13; desc.arginfo = SCM_ARGS(2); - ret = scm_call2(SCM_SIP_FNID(SCM_SVC_BOOT, 0xA), &desc); + ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_BOOT, 0xA), &desc); if (ret) { pr_err("SCM resume call failed with error %d\n", ret); return ret; diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index 2a149ac87ed1..06403a87bec8 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2010-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 @@ -64,7 +64,7 @@ static const char * const clocks[] = { "ahb_clk" }; -static unsigned int ib_votes[KGSL_MAX_BUSLEVELS]; +static unsigned long ib_votes[KGSL_MAX_BUSLEVELS]; static int last_vote_buslevel; static int max_vote_buslevel; @@ -127,7 +127,7 @@ static void _record_pwrevent(struct kgsl_device *device, /** * kgsl_get_bw() - Return latest msm bus IB vote */ -static unsigned int kgsl_get_bw(void) +static unsigned long kgsl_get_bw(void) { return ib_votes[last_vote_buslevel]; } @@ -141,8 +141,8 @@ static unsigned int kgsl_get_bw(void) static void _ab_buslevel_update(struct kgsl_pwrctrl *pwr, unsigned long *ab) { - unsigned int ib = ib_votes[last_vote_buslevel]; - unsigned int max_bw = ib_votes[max_vote_buslevel]; + unsigned long ib = ib_votes[last_vote_buslevel]; + unsigned long max_bw = ib_votes[max_vote_buslevel]; if (!ab) return; diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c index 0ed17d859080..099daaf8403a 100644 --- a/drivers/gpu/msm/kgsl_snapshot.c +++ b/drivers/gpu/msm/kgsl_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -335,10 +335,8 @@ int kgsl_snapshot_get_object(struct kgsl_snapshot *snapshot, entry = kgsl_sharedmem_find(process, gpuaddr); - if (entry == NULL) { - KGSL_CORE_ERR("Unable to find GPU buffer 0x%016llX\n", gpuaddr); + if (entry == NULL) return -EINVAL; - } /* We can't freeze external memory, because we don't own it */ if (entry->memdesc.flags & KGSL_MEMFLAGS_USERMEM_MASK) diff --git a/drivers/hwtracing/coresight/coresight-ost.c b/drivers/hwtracing/coresight/coresight-ost.c index 340c58944424..aadc5885afbc 100644 --- a/drivers/hwtracing/coresight/coresight-ost.c +++ b/drivers/hwtracing/coresight/coresight-ost.c @@ -14,6 +14,7 @@ #include <linux/bitmap.h> #include <linux/io.h> #include "coresight-ost.h" +#include <linux/coresight-stm.h> #define STM_USERSPACE_HEADER_SIZE (8) #define STM_USERSPACE_MAGIC1_VAL (0xf0) @@ -139,7 +140,7 @@ static int stm_trace_data_header(void __iomem *addr) } static int stm_trace_data(void __iomem *ch_addr, uint32_t flags, - const void *data, uint32_t size) + uint32_t entity_id, const void *data, uint32_t size) { void __iomem *addr; int len = 0; @@ -148,8 +149,10 @@ static int stm_trace_data(void __iomem *ch_addr, uint32_t flags, addr = (void __iomem *)(ch_addr + stm_channel_off(STM_PKT_TYPE_DATA, flags)); - /* send the data header */ - len += stm_trace_data_header(addr); + /* OST_ENTITY_DIAG no need to send the data header */ + if (entity_id != OST_ENTITY_DIAG) + len += stm_trace_data_header(addr); + /* send the actual data */ len += stm_ost_send(addr, data, size); @@ -192,7 +195,7 @@ static inline int __stm_trace(uint32_t flags, uint8_t entity_id, proto_id); /* send the payload data */ - len += stm_trace_data(ch_addr, flags, data, size); + len += stm_trace_data(ch_addr, flags, entity_id, data, size); /* send the ost tail */ len += stm_trace_ost_tail(ch_addr, flags); diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 36c84df078c7..30815df2ba6b 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -369,8 +369,9 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, unsigned int order = __fls(order_mask); order_size = 1U << order; - page = alloc_pages((order_mask - order_size) ? - gfp | __GFP_NORETRY : gfp, order); + page = alloc_pages(order ? + (gfp | __GFP_NORETRY) & + ~__GFP_RECLAIM : gfp, order); if (!page) continue; if (!order) diff --git a/drivers/iommu/dma-mapping-fast.c b/drivers/iommu/dma-mapping-fast.c index 7e6287c986ef..31482f99f37f 100644 --- a/drivers/iommu/dma-mapping-fast.c +++ b/drivers/iommu/dma-mapping-fast.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -546,12 +546,22 @@ static void *fast_smmu_alloc(struct device *dev, size_t size, av8l_fast_iopte *ptep; unsigned long flags; struct sg_mapping_iter miter; - unsigned int count = ALIGN(size, SZ_4K) >> PAGE_SHIFT; + size_t count = ALIGN(size, SZ_4K) >> PAGE_SHIFT; int prot = IOMMU_READ | IOMMU_WRITE; /* TODO: extract from attrs */ bool is_coherent = is_dma_coherent(dev, attrs); pgprot_t remap_prot = __get_dma_pgprot(attrs, PAGE_KERNEL, is_coherent); struct page **pages; + /* + * sg_alloc_table_from_pages accepts unsigned int value for count + * so check count doesn't exceed UINT_MAX. + */ + + if (count > UINT_MAX) { + dev_err(dev, "count: %zx exceeds UNIT_MAX\n", count); + return NULL; + } + prot = __get_iommu_pgprot(attrs, prot, is_coherent); *handle = DMA_ERROR_CODE; diff --git a/drivers/iommu/iommu-debug.c b/drivers/iommu/iommu-debug.c index 2dcac176812c..87a1244206ba 100644 --- a/drivers/iommu/iommu-debug.c +++ b/drivers/iommu/iommu-debug.c @@ -1395,7 +1395,7 @@ static ssize_t iommu_debug_test_virt_addr_read(struct file *file, else snprintf(buf, buf_len, "0x%pK\n", test_virt_addr); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1518,7 +1518,7 @@ static ssize_t iommu_debug_pte_read(struct file *file, char __user *ubuf, else snprintf(buf, sizeof(buf), "pte=%016llx\n", pte); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1587,7 +1587,7 @@ static ssize_t iommu_debug_atos_read(struct file *file, char __user *ubuf, snprintf(buf, 100, "%pa\n", &phys); } - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1640,7 +1640,7 @@ static ssize_t iommu_debug_dma_atos_read(struct file *file, char __user *ubuf, else snprintf(buf, sizeof(buf), "%pa\n", &phys); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; @@ -1873,7 +1873,7 @@ static ssize_t iommu_debug_dma_map_read(struct file *file, char __user *ubuf, iova = ddev->iova; snprintf(buf, sizeof(buf), "%pa\n", &iova); - buflen = min(count, strlen(buf)+1); + buflen = min(count, strlen(buf)); if (copy_to_user(ubuf, buf, buflen)) { pr_err("Couldn't copy_to_user\n"); retval = -EFAULT; diff --git a/drivers/leds/leds-qpnp-vibrator.c b/drivers/leds/leds-qpnp-vibrator.c index cc2615daf1c1..c428bfb386b9 100644 --- a/drivers/leds/leds-qpnp-vibrator.c +++ b/drivers/leds/leds-qpnp-vibrator.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 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 @@ -314,6 +314,13 @@ static ssize_t qpnp_vib_get_state(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", !!chip->reg_en_ctl); } +static ssize_t qpnp_vib_set_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_vib_get_duration(struct device *dev, struct device_attribute *attr, char *buf) { @@ -391,7 +398,6 @@ static ssize_t qpnp_vib_set_activate(struct device *dev, (vib->vib_play_ms % 1000) * 1000000), HRTIMER_MODE_REL); } - vib->vib_play_ms = 0; mutex_unlock(&vib->lock); schedule_work(&vib->work); @@ -399,7 +405,7 @@ static ssize_t qpnp_vib_set_activate(struct device *dev, } static struct device_attribute qpnp_vib_attrs[] = { - __ATTR(state, 0444, qpnp_vib_get_state, NULL), + __ATTR(state, 0664, qpnp_vib_get_state, qpnp_vib_set_state), __ATTR(duration, 0664, qpnp_vib_get_duration, qpnp_vib_set_duration), __ATTR(activate, 0664, qpnp_vib_get_activate, qpnp_vib_set_activate), }; diff --git a/drivers/leds/leds-qti-tri-led.c b/drivers/leds/leds-qti-tri-led.c index c303893e1a28..c49465532f83 100644 --- a/drivers/leds/leds-qti-tri-led.c +++ b/drivers/leds/leds-qti-tri-led.c @@ -43,14 +43,14 @@ #define PWM_PERIOD_DEFAULT_NS 1000000 struct pwm_setting { - u32 pre_period_ns; - u32 period_ns; - u32 duty_ns; + u64 pre_period_ns; + u64 period_ns; + u64 duty_ns; }; struct led_setting { - u32 on_ms; - u32 off_ms; + u64 on_ms; + u64 off_ms; enum led_brightness brightness; bool blink; bool breath; @@ -164,24 +164,16 @@ static int __tri_led_set(struct qpnp_led_dev *led) static int qpnp_tri_led_set(struct qpnp_led_dev *led) { - u32 on_ms, off_ms, period_ns, duty_ns; + u64 on_ms, off_ms, period_ns, duty_ns; enum led_brightness brightness = led->led_setting.brightness; int rc = 0; if (led->led_setting.blink) { on_ms = led->led_setting.on_ms; off_ms = led->led_setting.off_ms; - if (on_ms > INT_MAX / NSEC_PER_MSEC) - duty_ns = INT_MAX - 1; - else - duty_ns = on_ms * NSEC_PER_MSEC; - if (on_ms + off_ms > INT_MAX / NSEC_PER_MSEC) { - period_ns = INT_MAX; - duty_ns = (period_ns / (on_ms + off_ms)) * on_ms; - } else { - period_ns = (on_ms + off_ms) * NSEC_PER_MSEC; - } + duty_ns = on_ms * NSEC_PER_MSEC; + period_ns = (on_ms + off_ms) * NSEC_PER_MSEC; if (period_ns < duty_ns && duty_ns != 0) period_ns = duty_ns + 1; @@ -191,15 +183,14 @@ static int qpnp_tri_led_set(struct qpnp_led_dev *led) if (brightness == LED_OFF) duty_ns = 0; - else if (period_ns > INT_MAX / brightness) - duty_ns = (period_ns / LED_FULL) * brightness; - else - duty_ns = (period_ns * brightness) / LED_FULL; + + duty_ns = period_ns * brightness; + do_div(duty_ns, LED_FULL); if (period_ns < duty_ns && duty_ns != 0) period_ns = duty_ns + 1; } - dev_dbg(led->chip->dev, "PWM settings for %s led: period = %dns, duty = %dns\n", + dev_dbg(led->chip->dev, "PWM settings for %s led: period = %lluns, duty = %lluns\n", led->cdev.name, period_ns, duty_ns); led->pwm_setting.duty_ns = duty_ns; diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c index e4ec08b41504..f753b34514bd 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_intf.c @@ -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 @@ -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/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c index 9021ecabb27c..b2575825f983 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_virtual_core.c @@ -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 @@ -118,6 +118,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/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index 8021f12934a9..dc16733f3bbb 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c @@ -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 @@ -275,6 +275,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; + size_t remain_len = 0; int32_t i = 0, j = 0; if (!ctx || !cmd) { @@ -323,12 +324,21 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, goto free_req; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CTXT, "invalid buff length: %zu or offset", len); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); cfg.packet = packet; + cfg.remain_len = remain_len; cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; cfg.max_hw_update_entries = CAM_CTX_CFG_MAX; cfg.num_hw_update_entries = req->num_hw_update_entries; diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h index 54b0f4d63bf8..656fcfac3996 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera/cam_core/cam_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 @@ -152,6 +152,7 @@ struct cam_hw_mgr_dump_pf_data { * struct cam_hw_prepare_update_args - Payload for prepare command * * @packet: CSL packet from user mode driver + * @remain_len Remaining length of CPU buffer after config offset * @ctxt_to_hw_map: HW context from the acquire * @max_hw_update_entries: Maximum hardware update entries supported * @hw_update_entries: Actual hardware update configuration (returned) @@ -168,6 +169,7 @@ struct cam_hw_mgr_dump_pf_data { */ struct cam_hw_prepare_update_args { struct cam_packet *packet; + size_t remain_len; void *ctxt_to_hw_map; uint32_t max_hw_update_entries; struct cam_hw_update_entry *hw_update_entries; diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index 7e78f458ec2b..c72893561980 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -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 @@ -30,7 +30,8 @@ static struct cam_fd_hw_mgr g_fd_hw_mgr; -static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet) +static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) { struct cam_cmd_buf_desc *cmd_desc = NULL; int i, rc; @@ -50,7 +51,7 @@ static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet) packet->patch_offset, packet->num_patches, packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); - if (cam_packet_util_validate_packet(packet)) { + if (cam_packet_util_validate_packet(packet, remain_len)) { CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d", packet->kmd_cmd_buf_index, packet->num_cmd_buf, packet->cmd_buf_offset, @@ -608,7 +609,13 @@ 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); + return -EINVAL; + } cpu_addr[plane] += io_cfg[i].offsets[plane]; } @@ -1559,7 +1566,8 @@ static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv, goto error; } - rc = cam_fd_mgr_util_packet_validate(prepare->packet); + rc = cam_fd_mgr_util_packet_validate(prepare->packet, + prepare->remain_len); if (rc) { CAM_ERR(CAM_FD, "Error in packet validation %d", rc); goto error; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index ca8bb3c8d543..94e259311326 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -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 @@ -3698,6 +3698,9 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, packet = prepare_args->packet; + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + return -EINVAL; + rc = cam_icp_mgr_pkt_validation(packet); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index aaa172deea97..69fa90693c5d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -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 @@ -2035,6 +2035,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; + size_t remain_len = 0; struct cam_hw_prepare_update_args cfg; struct cam_req_mgr_add_request add_req; struct cam_isp_context *ctx_isp = @@ -2069,6 +2070,14 @@ static int __cam_isp_ctx_config_dev_in_top_state( goto free_req; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle); CAM_DBG(CAM_ISP, "packet address is 0x%zx", packet_addr); @@ -2082,6 +2091,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); cfg.packet = packet; + cfg.remain_len = remain_len; cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; cfg.max_hw_update_entries = CAM_ISP_CTX_CFG_MAX; cfg.hw_update_entries = req_isp->cfg; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index d29506fb8a21..45f88b3e79da 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -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 @@ -715,7 +715,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; @@ -805,7 +806,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; @@ -918,7 +920,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; @@ -1150,7 +1153,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( goto end; } - 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; if (in_port->usage_type) @@ -1568,6 +1572,14 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, u64_to_user_ptr(isp_resource[i].res_hdl), isp_resource[i].length); if (!IS_ERR(in_port)) { + if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + kfree(in_port); + goto free_res; + } + in_port_length = sizeof(struct cam_isp_in_port_info) + (in_port->num_out_res - 1) * sizeof(struct cam_isp_out_port_info); @@ -2663,7 +2675,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_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); + rc = cam_packet_util_validate_packet(prepare->packet, + prepare->remain_len); if (rc) return rc; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index f652256d3dc5..abf208cb0361 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -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 @@ -105,7 +105,7 @@ static int cam_isp_update_dual_config( 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; + size_t len = 0, remain_len = 0; uint32_t *cpu_addr; uint32_t i, j; @@ -117,9 +117,22 @@ static int cam_isp_update_dual_config( if (rc) return rc; + if ((len < sizeof(struct cam_isp_dual_config)) || + (cmd_desc->offset >= + (len - sizeof(struct cam_isp_dual_config)))) { + CAM_ERR(CAM_UTIL, "not enough buffer provided"); + return -EINVAL; + } + remain_len = len - cmd_desc->offset; cpu_addr += (cmd_desc->offset / 4); dual_config = (struct cam_isp_dual_config *)cpu_addr; + if ((dual_config->num_ports * + sizeof(struct cam_isp_dual_stripe_config)) > + (remain_len - offsetof(struct cam_isp_dual_config, stripes))) { + CAM_ERR(CAM_UTIL, "not enough buffer for all the dual configs"); + return -EINVAL; + } for (i = 0; i < dual_config->num_ports; i++) { if (i >= CAM_ISP_IFE_OUT_RES_MAX) { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 9ffd923b55cb..a4c0cb10863e 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* 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 @@ -2634,18 +2634,20 @@ static int cam_ife_csid_sof_irq_debug( if (*((uint32_t *)cmd_args) == 1) sof_irq_enable = true; - val = cam_io_r_mb(soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_ipp_irq_mask_addr); + if (csid_reg->ipp_reg) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_mask_addr); - if (val) { - if (sof_irq_enable) - val |= CSID_PATH_INFO_INPUT_SOF; - else - val &= ~CSID_PATH_INFO_INPUT_SOF; + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; - cam_io_w_mb(val, soc_info->reg_map[0].mem_base + - csid_reg->ipp_reg->csid_ipp_irq_mask_addr); - val = 0; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_mask_addr); + val = 0; + } } for (i = 0; i < csid_reg->cmn_reg->no_rdis; i++) { diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 7f0199f6e119..77fea6bfbc06 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -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 @@ -275,6 +275,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); @@ -713,7 +719,7 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return -EINVAL; } - rc = cam_packet_util_validate_packet(packet); + rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len); if (rc) { CAM_ERR(CAM_JPEG, "invalid packet %d", rc); return rc; diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index eecba3972875..c6250327b640 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -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 @@ -83,7 +83,8 @@ static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr, return 0; } -static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet) +static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) { struct cam_cmd_buf_desc *cmd_desc = NULL; int i, rc; @@ -105,7 +106,7 @@ static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet) packet->patch_offset, packet->num_patches, packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); - if (cam_packet_util_validate_packet(packet)) { + if (cam_packet_util_validate_packet(packet, remain_len)) { CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d", packet->kmd_cmd_buf_index, packet->num_cmd_buf, packet->cmd_buf_offset, @@ -166,13 +167,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,6 +180,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, 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", @@ -194,6 +194,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, 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 = @@ -209,6 +215,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 = @@ -841,7 +853,7 @@ static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, goto error; } - rc = cam_lrme_mgr_util_packet_validate(args->packet); + rc = cam_lrme_mgr_util_packet_validate(args->packet, args->remain_len); if (rc) { CAM_ERR(CAM_LRME, "Error in packet validation %d", rc); goto error; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c index f2c243e8c7a9..66142dbf3f74 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -23,6 +23,7 @@ #include "cam_debug_util.h" static struct cam_mem_table tbl; +static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); static int cam_mem_util_map_cpu_va(struct ion_handle *hdl, uintptr_t *vaddr, @@ -108,6 +109,7 @@ int cam_mem_mgr_init(void) tbl.bufq[i].buf_handle = -1; } mutex_init(&tbl.m_lock); + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); return rc; bitmap_fail: @@ -151,6 +153,11 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, { int rc = 0, idx; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "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; @@ -191,6 +198,10 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) uintptr_t kvaddr = 0; size_t klen = 0; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } if (!buf_handle || !vaddr_ptr || !len) return -EINVAL; @@ -242,6 +253,11 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) uint32_t ion_cache_ops; unsigned long ion_flag = 0; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd) return -EINVAL; @@ -518,6 +534,11 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) dma_addr_t hw_vaddr = 0; size_t len; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd) { CAM_ERR(CAM_MEM, " Invalid argument"); return -EINVAL; @@ -616,6 +637,11 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) dma_addr_t hw_vaddr = 0; size_t len = 0; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd || (cmd->fd < 0)) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; @@ -801,6 +827,7 @@ 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); @@ -889,6 +916,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; @@ -936,6 +968,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp || !out) { CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; @@ -1054,6 +1091,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; @@ -1103,6 +1145,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp || !out) { CAM_ERR(CAM_MEM, "Invalid param(s)"); return -EINVAL; @@ -1195,6 +1242,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h index 92c366d723f9..73f0eb3d3425 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_mem_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -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, diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 4c4afc1841f8..8de297db8ff7 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -2432,16 +2432,17 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) return -EINVAL; } + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); 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) { @@ -2778,7 +2779,8 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) goto end; } - if (control->num_links > MAX_LINKS_PER_SESSION) { + if ((control->num_links <= 0) || + (control->num_links > MAX_LINKS_PER_SESSION)) { CAM_ERR(CAM_CRM, "Invalid number of links %d", control->num_links); rc = -EINVAL; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index c14a74d7c862..8519115cb437 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -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 @@ -17,6 +17,7 @@ #include "cam_trace.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" int32_t cam_actuator_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -214,12 +215,12 @@ static int32_t cam_actuator_i2c_modes_util( } int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_i2c_info *i2c_info; - if (!a_ctrl || !cmd_buf) { + if (!a_ctrl || !cmd_buf || (len < sizeof(struct cam_cmd_i2c_info))) { CAM_ERR(CAM_ACTUATOR, "Invalid Args"); return -EINVAL; } @@ -413,6 +414,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, int32_t i = 0; uint32_t total_cmd_buf_in_bytes = 0; size_t len_of_buff = 0; + size_t remain_len = 0; uint32_t *offset = NULL; uint32_t *cmd_buf = NULL; uintptr_t generic_ptr; @@ -449,16 +451,27 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, return rc; } - if (config.offset > len_of_buff) { + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { CAM_ERR(CAM_ACTUATOR, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buff); + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); return -EINVAL; } - csl_packet = - (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *) + (generic_ptr + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_ACTUATOR, "Invalid packet params"); + return -EINVAL; + } + + 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: @@ -482,6 +495,14 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_ERR(CAM_ACTUATOR, "invalid cmd buf"); return -EINVAL; } + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_ACTUATOR, + "Invalid length for sensor cmd"); + return -EINVAL; + } + remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmm_hdr = (struct common_header *)cmd_buf; @@ -490,7 +511,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "Received slave info buffer"); rc = cam_actuator_slaveInfo_pkt_parser( - a_ctrl, cmd_buf); + a_ctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to parse slave info: %d", rc); @@ -504,7 +525,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - power_info); + power_info, remain_len); if (rc) { CAM_ERR(CAM_ACTUATOR, "Failed:parse power settings: %d", diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index cb0bcc292037..9a1188537dd7 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -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 @@ -15,6 +15,8 @@ #include "cam_csiphy_dev.h" #include "cam_csiphy_soc.h" #include "cam_common_util.h" +#include "cam_packet_util.h" + #include <soc/qcom/scm.h> #include <cam_mem_mgr.h> @@ -31,6 +33,7 @@ static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, bool protect, int32_t offset) { struct scm_desc desc = {0}; + int result = -1; if (offset >= CSIPHY_MAX_INSTANCES) return -EINVAL; @@ -38,8 +41,19 @@ static int cam_csiphy_notify_secure_mode(struct csiphy_device *csiphy_dev, desc.args[0] = protect; desc.args[1] = csiphy_dev->csiphy_cpas_cp_reg_mask[offset]; - if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID_2), - &desc)) { + /* + * If SECURE_SYSCALL_ID_2 is not supported + * then fallback to SECURE_SYSCALL_ID + */ + result = scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID_2), + &desc); + if (result == -EOPNOTSUPP) { + desc.args[1] = csiphy_dev->soc_info.index; + CAM_ERR(CAM_CSIPHY, "SCM CALL 7 not supported fallback to 6"); + result = scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, + SECURE_SYSCALL_ID), &desc); + } + if (result) { CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); return -EINVAL; } @@ -156,6 +170,7 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, uint32_t *cmd_buf = NULL; struct cam_csiphy_info *cam_cmd_csiphy_info = NULL; size_t len; + size_t remain_len; if (!cfg_dev || !csiphy_dev) { CAM_ERR(CAM_CSIPHY, "Invalid Args"); @@ -169,16 +184,25 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, return rc; } - if (cfg_dev->offset > len) { + remain_len = len; + if ((sizeof(struct cam_packet) > len) || + ((size_t)cfg_dev->offset >= len - sizeof(struct cam_packet))) { CAM_ERR(CAM_CSIPHY, "offset is out of bounds: offset: %lld len: %zu", cfg_dev->offset, len); return -EINVAL; } + remain_len -= (size_t)cfg_dev->offset; csl_packet = (struct cam_packet *) (generic_ptr + (uint32_t)cfg_dev->offset); + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_CSIPHY, "Invalid packet params"); + return -EINVAL; + } + cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *)&csl_packet->payload + csl_packet->cmd_buf_offset / 4); @@ -191,6 +215,13 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, return rc; } + if ((len < sizeof(struct cam_csiphy_info)) || + (cmd_desc->offset > (len - sizeof(struct cam_csiphy_info)))) { + CAM_ERR(CAM_CSIPHY, + "Not enough buffer provided for cam_cisphy_info"); + return -EINVAL; + } + cmd_buf = (uint32_t *)generic_ptr; cmd_buf += cmd_desc->offset / 4; cam_cmd_csiphy_info = (struct cam_csiphy_info *)cmd_buf; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 92bace40be4a..4dce293eb7ab 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -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 @@ -18,6 +18,7 @@ #include "cam_eeprom_soc.h" #include "cam_debug_util.h" #include "cam_common_util.h" +#include "cam_packet_util.h" /** * cam_eeprom_read_memory() - read map data into buffer @@ -413,7 +414,7 @@ static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl, 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) + int *num_map, size_t remain_buf_len) { int32_t rc = 0; int32_t cnt = 0; @@ -427,8 +428,21 @@ static int32_t cam_eeprom_parse_memory_map( struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL; struct cam_cmd_conditional_wait *i2c_poll = NULL; struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL; + size_t validate_size = 0; generic_op_code = cmm_hdr->third_byte; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR) + validate_size = sizeof(struct cam_cmd_i2c_random_wr); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD) + validate_size = sizeof(struct cam_cmd_i2c_continuous_rd); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf_len < validate_size) { + CAM_ERR(CAM_EEPROM, "not enough buffer"); + return -EINVAL; + } switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; @@ -535,6 +549,7 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, uint32_t *cmd_buf = NULL; uintptr_t generic_pkt_addr; size_t pkt_len = 0; + size_t remain_len = 0; uint32_t total_cmd_buf_in_bytes = 0; uint32_t processed_cmd_buf_in_bytes = 0; struct common_header *cmm_hdr = NULL; @@ -577,13 +592,36 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, CAM_ERR(CAM_EEPROM, "invalid cmd buf"); return -EINVAL; } + + if ((pkt_len < sizeof(struct common_header)) || + (cmd_desc[i].offset > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + return -EINVAL; + } + remain_len = pkt_len - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + return -EINVAL; + } /* Loop through multiple cmd formats in one cmd buffer */ while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + return -EINVAL; + } cmm_hdr = (struct common_header *)cmd_buf; switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + return -EINVAL; + } /* Configure the following map slave address */ map[num_map + 1].saddr = i2c_info->slave_addr; rc = cam_eeprom_update_slaveInfo(e_ctrl, @@ -599,7 +637,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, 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); + cmd_length_in_bytes, power_info, + (remain_len - + processed_cmd_buf_in_bytes)); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/ @@ -616,7 +656,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, rc = cam_eeprom_parse_memory_map( &e_ctrl->cal_data, cmd_buf, total_cmd_buf_in_bytes, - &cmd_length_in_bytes, &num_map); + &cmd_length_in_bytes, &num_map, + (remain_len - + processed_cmd_buf_in_bytes)); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/sizeof(uint32_t); @@ -647,6 +689,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, uintptr_t buf_addr; size_t buf_size; uint8_t *read_buffer; + size_t remain_len = 0; io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) &csl_packet->payload + @@ -660,6 +703,17 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, if (io_cfg->direction == CAM_BUF_OUTPUT) { rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], &buf_addr, &buf_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "Fail in get buffer: %d", + rc); + return rc; + } + if (buf_size <= io_cfg->offsets[0]) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + return -EINVAL; + } + + remain_len = buf_size - io_cfg->offsets[0]; CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", (void *)buf_addr, buf_size); @@ -671,7 +725,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, } read_buffer += io_cfg->offsets[0]; - if (buf_size < e_ctrl->cal_data.num_data) { + if (remain_len < e_ctrl->cal_data.num_data) { CAM_ERR(CAM_EEPROM, "failed to copy, Invalid size"); return -EINVAL; @@ -704,6 +758,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) struct cam_config_dev_cmd dev_config; uintptr_t generic_pkt_addr; size_t pkt_len; + size_t remain_len = 0; struct cam_packet *csl_packet = NULL; struct cam_eeprom_soc_private *soc_private = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; @@ -723,15 +778,26 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) return rc; } - if (dev_config.offset > pkt_len) { + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { CAM_ERR(CAM_EEPROM, - "Offset is out of bound: off: %lld, %zu", - dev_config.offset, pkt_len); + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); return -EINVAL; } + remain_len -= (size_t)dev_config.offset; csl_packet = (struct cam_packet *) (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_EEPROM, "Invalid packet params"); + return -EINVAL; + } + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_EEPROM_PACKET_OPCODE_INIT: if (e_ctrl->userspace_probe == false) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c index 8c075f576ce6..182eec325789 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_core.c @@ -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 @@ -16,6 +16,7 @@ #include "cam_flash_core.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, bool regulator_enable) @@ -438,7 +439,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; } @@ -452,7 +453,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; @@ -591,11 +592,15 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, } static int32_t cam_flash_slaveInfo_pkt_parser(struct cam_flash_ctrl *fctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if (len < sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } if (fctrl->io_master_info.master_type == CCI_MASTER) { fctrl->io_master_info.cci_client->cci_i2c_master = fctrl->cci_i2c_master; @@ -889,6 +894,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) uint32_t *offset = NULL; uint32_t frm_offset = 0; size_t len_of_buffer; + size_t remain_len; struct cam_flash_init *flash_init = NULL; struct common_header *cmn_hdr = NULL; struct cam_control *ioctl_ctrl = NULL; @@ -920,16 +926,27 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) return rc; } - if (config.offset > len_of_buffer) { + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { CAM_ERR(CAM_FLASH, "offset is out of bounds: offset: %lld len: %zu", config.offset, len_of_buffer); return -EINVAL; } + remain_len -= (size_t)config.offset; /* Add offset to the flash csl header */ - csl_packet = (struct cam_packet *)(uintptr_t)(generic_ptr + - config.offset); + csl_packet = (struct cam_packet *)(generic_ptr + + (uintptr_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + return -EINVAL; + } + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_FLASH_PACKET_OPCODE_INIT: { /* INIT packet*/ @@ -954,6 +971,15 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_ERR(CAM_FLASH, "invalid cmd buf"); return -EINVAL; } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buffer - + sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "invalid cmd buf length"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmn_hdr = (struct common_header *)cmd_buf; @@ -964,6 +990,12 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) total_cmd_buf_in_bytes); switch (cmn_hdr->cmd_type) { case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: + if (len_of_buffer < + sizeof(struct cam_flash_init)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + flash_init = (struct cam_flash_init *)cmd_buf; fctrl->flash_type = flash_init->flash_type; cmd_length_in_bytes = @@ -975,7 +1007,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) break; case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: rc = cam_flash_slaveInfo_pkt_parser( - fctrl, cmd_buf); + fctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_FLASH, "Failed parsing slave info: rc: %d", @@ -998,7 +1030,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - &fctrl->power_info); + &fctrl->power_info, remain_len); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/ @@ -1196,6 +1228,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) uint32_t *offset = NULL; uint32_t frm_offset = 0; size_t len_of_buffer; + size_t remain_len; struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -1230,16 +1263,26 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) return rc; } - if (config.offset > len_of_buffer) { + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { CAM_ERR(CAM_FLASH, "offset is out of bounds: offset: %lld len: %zu", config.offset, len_of_buffer); return -EINVAL; } + remain_len -= (size_t)config.offset; /* Add offset to the flash csl header */ - csl_packet = - (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); + csl_packet = (struct cam_packet *)(generic_ptr + + (uintptr_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + return -EINVAL; + } switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_FLASH_PACKET_OPCODE_INIT: { @@ -1249,6 +1292,18 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + return -EINVAL; + } + if ((len_of_buffer < sizeof(struct cam_flash_init)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct cam_flash_init)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + + remain_len = len_of_buffer - cmd_desc->offset; cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + cmd_desc->offset); cam_flash_info = (struct cam_flash_init *)cmd_buf; @@ -1278,8 +1333,23 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: { CAM_DBG(CAM_FLASH, "INIT_FIRE Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + 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; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + return -EINVAL; + } fctrl->nrt_info.cmn_attr.count = flash_operation_info->count; fctrl->nrt_info.cmn_attr.request_id = 0; @@ -1327,9 +1397,22 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: 0x%x", + cmd_desc->mem_handle); + return -EINVAL; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "not enough buffer"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + cmd_desc->offset); - if (!cmd_buf) return -EINVAL; @@ -1347,6 +1430,10 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) flash_data->cmn_attr.is_settings_valid = false; return 0; } + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } flash_operation_info = (struct cam_flash_set_on_off *) cmd_buf; @@ -1355,6 +1442,11 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) "flash_operation_info Null"); return -EINVAL; } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + return -EINVAL; + } flash_data->opcode = flash_operation_info->opcode; flash_data->cmn_attr.count = @@ -1378,6 +1470,18 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, &generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + return -EINVAL; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc->offset; cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + cmd_desc->offset); cmn_hdr = (struct common_header *)cmd_buf; @@ -1385,8 +1489,23 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) switch (cmn_hdr->cmd_type) { case CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET: { CAM_DBG(CAM_FLASH, "Widget Flash Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } 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; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + return -EINVAL; + } + fctrl->nrt_info.cmn_attr.count = flash_operation_info->count; fctrl->nrt_info.cmn_attr.request_id = 0; @@ -1408,6 +1527,10 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) case CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR: { int query_curr_ma = 0; + if (remain_len < sizeof(struct cam_flash_query_curr)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } flash_query_info = (struct cam_flash_query_curr *)cmd_buf; @@ -1425,7 +1548,22 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) } case CAMERA_SENSOR_FLASH_CMD_TYPE_RER: { rc = 0; + if (remain_len < sizeof(struct cam_flash_set_rer)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } flash_rer_info = (struct cam_flash_set_rer *)cmd_buf; + if (!flash_rer_info) { + CAM_ERR(CAM_FLASH, + "flash_rer_info Null"); + return -EINVAL; + } + if (flash_rer_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + return -EINVAL; + } + fctrl->nrt_info.cmn_attr.cmd_type = CAMERA_SENSOR_FLASH_CMD_TYPE_RER; fctrl->nrt_info.opcode = flash_rer_info->opcode; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index 850b315c26a7..281b25482864 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -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 @@ -19,6 +19,7 @@ #include "cam_debug_util.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -256,12 +257,12 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, } static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_ois_info *ois_info; - if (!o_ctrl || !cmd_buf) { + if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_info)) { CAM_ERR(CAM_OIS, "Invalid Args"); return -EINVAL; } @@ -274,7 +275,8 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, 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); + memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN); + o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0'; o_ctrl->io_master_info.cci_client->retries = 3; o_ctrl->io_master_info.cci_client->id_map = 0; memcpy(&(o_ctrl->opcode), &(ois_info->opcode), @@ -433,6 +435,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) struct cam_cmd_buf_desc *cmd_desc = NULL; uintptr_t generic_pkt_addr; size_t pkt_len; + size_t remain_len = 0; struct cam_packet *csl_packet = NULL; size_t len_of_buff = 0; uint32_t *offset = NULL, *cmd_buf; @@ -453,15 +456,26 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) return rc; } - if (dev_config.offset > pkt_len) { + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { CAM_ERR(CAM_OIS, "offset is out of bound: off: %lld len: %zu", dev_config.offset, pkt_len); return -EINVAL; } + remain_len -= (size_t)dev_config.offset; csl_packet = (struct cam_packet *) (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_OIS, "Invalid packet params"); + return -EINVAL; + } + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_OIS_PACKET_OPCODE_INIT: offset = (uint32_t *)&csl_packet->payload; @@ -485,13 +499,22 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_ERR(CAM_OIS, "invalid cmd buf"); return -EINVAL; } + + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_OIS, + "Invalid length for sensor cmd"); + return -EINVAL; + } + remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmm_hdr = (struct common_header *)cmd_buf; switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: rc = cam_ois_slaveInfo_pkt_parser( - o_ctrl, cmd_buf); + o_ctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed in parsing slave info"); @@ -505,7 +528,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - power_info); + power_info, remain_len); if (rc) { CAM_ERR(CAM_OIS, "Failed: parse power settings"); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h index d6f0ec564508..06022ababf4e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.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 @@ -16,6 +16,8 @@ #include <linux/dma-contiguous.h> #include "cam_ois_dev.h" +#define OIS_NAME_LEN 32 + /** * @power_info: power setting info to control the power * diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index c88e96980ff9..a9985e5e1ff5 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -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 @@ -17,6 +17,8 @@ #include "cam_soc_util.h" #include "cam_trace.h" #include "cam_common_util.h" +#include "cam_packet_util.h" + static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, @@ -94,6 +96,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, struct cam_cmd_buf_desc *cmd_desc = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; size_t len_of_buff = 0; + size_t remain_len = 0; uint32_t *offset = NULL; struct cam_config_dev_cmd config; struct i2c_data_settings *i2c_data = NULL; @@ -119,12 +122,23 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, return rc; } + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_SENSOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + return -EINVAL; + } + + remain_len -= (size_t)config.offset; csl_packet = (struct cam_packet *)(generic_ptr + (uint32_t)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); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_SENSOR, "Invalid packet params"); return -EINVAL; } @@ -342,7 +356,7 @@ int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, 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 cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) { int32_t rc = 0; @@ -351,6 +365,13 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, struct cam_cmd_i2c_info *i2c_info = NULL; struct cam_cmd_probe *probe_info; + if (remain_len < + (sizeof(struct cam_cmd_i2c_info) + + sizeof(struct cam_cmd_probe))) { + CAM_ERR(CAM_SENSOR, + "not enough buffer for cam_cmd_i2c_info"); + return -EINVAL; + } i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); if (rc < 0) { @@ -369,7 +390,8 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, break; case 1: { rc = cam_sensor_update_power_settings(cmd_buf, - cmd_buf_length, &s_ctrl->sensordata->power_info); + cmd_buf_length, &s_ctrl->sensordata->power_info, + remain_len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in updating power settings"); @@ -390,10 +412,11 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) 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; + size_t remain_len = 0; rc = cam_mem_get_cpu_buf(handle, &packet, &len); @@ -401,7 +424,19 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); return -EINVAL; } + pkt = (struct cam_packet *)packet; + if (pkt == NULL) { + CAM_ERR(CAM_SENSOR, "packet pos is invalid"); + return -EINVAL; + } + + if ((len < sizeof(struct cam_packet)) || + (pkt->cmd_buf_offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_SENSOR, "Not enough buf provided"); + return -EINVAL; + } + cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *)&pkt->payload + pkt->cmd_buf_offset/4); if (cmd_desc == NULL) { @@ -423,12 +458,23 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) "Failed to parse the command Buffer Header"); return -EINVAL; } + if (cmd_desc[i].offset >= len) { + CAM_ERR(CAM_SENSOR, + "offset past length of buffer"); + return -EINVAL; + } + remain_len = len - cmd_desc[i].offset; + if (cmd_desc[i].length > remain_len) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided for cmd"); + 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); + i, cmd_desc[i].length, remain_len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 5c1143ece162..061e054c3f9f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -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 @@ -298,6 +298,8 @@ int cam_sensor_i2c_command_parser( size_t len_of_buff = 0; uintptr_t generic_ptr; uint16_t cmd_length_in_bytes = 0; + size_t remain_len = 0; + size_t tot_size = 0; for (i = 0; i < num_cmd_buffers; i++) { uint32_t *cmd_buf = NULL; @@ -319,16 +321,34 @@ int cam_sensor_i2c_command_parser( rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, &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: %zd", cmd_desc[i].mem_handle, rc, len_of_buff); return rc; } + + remain_len = len_of_buff; + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buff - sizeof(struct common_header)))) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + cmd_buf = (uint32_t *)generic_ptr; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + if (remain_len < cmd_desc[i].length) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + while (byte_cnt < cmd_desc[i].length) { + if ((remain_len - byte_cnt) < + sizeof(struct common_header)) { + CAM_ERR(CAM_SENSOR, "Not enough buffer"); + return -EINVAL; + } cmm_hdr = (struct common_header *)cmd_buf; generic_op_code = cmm_hdr->third_byte; switch (cmm_hdr->cmd_type) { @@ -338,6 +358,22 @@ int cam_sensor_i2c_command_parser( *cam_cmd_i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_random_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct i2c_random_wr_payload) * + cam_cmd_i2c_random_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + rc = cam_sensor_handle_random_write( cam_cmd_i2c_random_wr, i2c_reg_settings, @@ -360,6 +396,24 @@ int cam_sensor_i2c_command_parser( (struct cam_cmd_i2c_continuous_wr *) cmd_buf; + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + (sizeof(struct cam_cmd_read) * + cam_cmd_i2c_continuous_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + rc = cam_sensor_handle_continuous_write( cam_cmd_i2c_continuous_wr, i2c_reg_settings, @@ -376,11 +430,16 @@ int cam_sensor_i2c_command_parser( break; } case CAMERA_SENSOR_CMD_TYPE_WAIT: { + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_unconditional_wait)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + return -EINVAL; + } 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, @@ -412,6 +471,12 @@ int cam_sensor_i2c_command_parser( break; } case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + return -EINVAL; + } rc = cam_sensor_handle_slave_info( io_master, cmd_buf); if (rc) { @@ -750,8 +815,32 @@ int cam_sensor_util_request_gpio_table( return rc; } + +static int32_t cam_sensor_validate(void *ptr, size_t remain_buf) +{ + struct common_header *cmm_hdr = (struct common_header *)ptr; + size_t validate_size = 0; + + if (remain_buf < sizeof(struct common_header)) + return -EINVAL; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP || + cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) + validate_size = sizeof(struct cam_cmd_power); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf < validate_size) { + CAM_ERR(CAM_SENSOR, "Invalid cmd_buf len %zu min %zu", + remain_buf, validate_size); + return -EINVAL; + } + return 0; +} + int32_t cam_sensor_update_power_settings(void *cmd_buf, - int cmd_length, struct cam_sensor_power_ctrl_t *power_info) + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len) { int32_t rc = 0, tot_size = 0, last_cmd_type = 0; int32_t i = 0, pwr_up = 0, pwr_down = 0; @@ -760,7 +849,8 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, 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) { + if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || + cam_sensor_validate(cmd_buf, cmd_buf_len)) { CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", pwr_cmd, cmd_length); return -EINVAL; @@ -787,6 +877,10 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } while (tot_size < cmd_length) { + if (cam_sensor_validate(ptr, (cmd_length - tot_size))) { + rc = -EINVAL; + goto free_power_settings; + } if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP) { struct cam_cmd_power *pwr_cmd = diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index 583ddb14243b..85497fda011c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.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 @@ -60,7 +60,8 @@ int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, 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); + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len); int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, int bob_reg_idx, bool flag); diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index 56209c67255e..7a489d7204ff 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -3005,7 +3005,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; diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c index 66a4487af172..a1a372008cb8 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.c @@ -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 @@ -50,23 +50,44 @@ int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) return 0; } -int cam_packet_util_validate_packet(struct cam_packet *packet) +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len) { + size_t sum_cmd_desc = 0; + size_t sum_io_cfgs = 0; + size_t sum_patch_desc = 0; + size_t pkt_wo_payload = 0; + if (!packet) return -EINVAL; + if ((size_t)packet->header.size > remain_len) { + CAM_ERR(CAM_UTIL, + "Invalid packet size: %zu, CPU buf length: %zu", + (size_t)packet->header.size, remain_len); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "num cmd buf:%d num of io config:%d kmd buf index:%d", packet->num_cmd_buf, packet->num_io_configs, packet->kmd_cmd_buf_index); - 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); + sum_cmd_desc = packet->num_cmd_buf * sizeof(struct cam_cmd_buf_desc); + sum_io_cfgs = packet->num_io_configs * sizeof(struct cam_buf_io_cfg); + sum_patch_desc = packet->num_patches * sizeof(struct cam_patch_desc); + pkt_wo_payload = offsetof(struct cam_packet, payload); + + if ((!packet->header.size) || + ((pkt_wo_payload + (size_t)packet->cmd_buf_offset + + sum_cmd_desc) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->io_configs_offset + + sum_io_cfgs) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->patch_offset + + sum_patch_desc) > (size_t)packet->header.size)) { + CAM_ERR(CAM_UTIL, "params not within mem len:%zu %zu %zu %zu", + (size_t)packet->header.size, sum_cmd_desc, + sum_io_cfgs, sum_patch_desc); return -EINVAL; } @@ -78,6 +99,7 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, { int rc = 0; size_t len = 0; + size_t remain_len = 0; struct cam_cmd_buf_desc *cmd_desc; uint32_t *cpu_addr; @@ -86,6 +108,13 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, return -EINVAL; } + if ((packet->kmd_cmd_buf_index < 0) || + (packet->kmd_cmd_buf_index > packet->num_cmd_buf)) { + CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d", + packet->kmd_cmd_buf_index); + return -EINVAL; + } + /* Take first command descriptor and add offset to it for kmd*/ cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *) &packet->payload + packet->cmd_buf_offset); @@ -100,12 +129,21 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, if (rc) return rc; - if (len < cmd_desc->size) { + remain_len = len; + if (((size_t)cmd_desc->offset >= len) || + ((size_t)cmd_desc->size >= (len - (size_t)cmd_desc->offset))) { CAM_ERR(CAM_UTIL, "invalid memory len:%zd and cmd desc size:%d", len, cmd_desc->size); return -EINVAL; } + remain_len -= (size_t)cmd_desc->offset; + if ((size_t)packet->kmd_cmd_buf_offset >= remain_len) { + CAM_ERR(CAM_UTIL, "Invalid kmd cmd buf offset: %zu", + (size_t)packet->kmd_cmd_buf_offset); + return -EINVAL; + } + cpu_addr += (cmd_desc->offset / 4) + (packet->kmd_cmd_buf_offset / 4); CAM_DBG(CAM_UTIL, "total size %d, cmd size: %d, KMD buffer size: %d", cmd_desc->size, cmd_desc->length, @@ -171,21 +209,17 @@ int cam_packet_util_process_patches(struct cam_packet *packet, patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); - if (patch_desc[i].src_offset >= src_buf_size) { - CAM_ERR_RATE_LIMIT(CAM_UTIL, - "Inval src offset:0x%x src len:0x%x reqid:%lld", - patch_desc[i].src_offset, - (unsigned int)src_buf_size, - packet->header.request_id); + if ((size_t)patch_desc[i].src_offset >= src_buf_size) { + CAM_ERR(CAM_UTIL, + "Invalid src buf patch offset"); return -EINVAL; } - if (patch_desc[i].dst_offset >= dst_buf_len) { - CAM_ERR_RATE_LIMIT(CAM_UTIL, - "Inval dst offset:0x%x dst len:0x%x reqid:%lld", - patch_desc[i].dst_offset, - (unsigned int)dst_buf_len, - packet->header.request_id); + if ((dst_buf_len < sizeof(void *)) || + ((dst_buf_len - sizeof(void *)) < + (size_t)patch_desc[i].dst_offset)) { + CAM_ERR(CAM_UTIL, + "Invalid dst buf patch offset"); return -EINVAL; } @@ -211,6 +245,7 @@ int cam_packet_util_process_generic_cmd_buffer( int rc; uintptr_t cpu_addr; size_t buf_size; + size_t remain_len = 0; uint32_t *blob_ptr; uint32_t blob_type, blob_size, blob_block_size, len_read; @@ -233,6 +268,21 @@ int cam_packet_util_process_generic_cmd_buffer( return rc; } + remain_len = buf_size; + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_buf->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_buf->offset); + return -EINVAL; + } + remain_len -= (size_t)cmd_buf->offset; + + if (remain_len < (size_t)cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_buf->length); + return -EINVAL; + } + blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) + cmd_buf->offset); diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h index 94d269313c7d..284f0a520aed 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_packet_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, 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 @@ -59,10 +59,13 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, * * @packet: Packet to be validated * + * @remain_len: CPU buff length after config offset + * * @return: 0 for success * -EINVAL for Fail */ -int cam_packet_util_validate_packet(struct cam_packet *packet); +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len); /** * cam_packet_util_validate_cmd_desc() diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile index 6a28da5926c7..69be506f6b0b 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/Makefile @@ -3,3 +3,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v2 ccflags-y += -Idrivers/media/platform/msm/camera_v2/common ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io obj-$(CONFIG_MSMB_CAMERA) += msm_flash.o +obj-$(CONFIG_MSMB_CAMERA) += qm215_gpio_flash.o diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c index 656b1ca2dc98..89a5ea06cc49 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-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 @@ -17,6 +17,7 @@ #include <linux/of_gpio.h> #include <linux/leds-qpnp-flash.h> #include "msm_flash.h" +#include "msm_camera_io_util.h" #include "msm_camera_dt_util.h" #include "msm_cci.h" @@ -514,6 +515,8 @@ static int32_t msm_flash_init( __func__, __LINE__, flash_data->cfg.flash_init_info->flash_driver_type); } + if (flash_ctrl->platform_flash_init) + flash_ctrl->platform_flash_init(flash_ctrl, flash_data); if (flash_ctrl->func_tbl->camera_flash_init) { rc = flash_ctrl->func_tbl->camera_flash_init( @@ -600,6 +603,8 @@ static int32_t msm_flash_prepare( __func__, __LINE__, flash_ctrl->flash_state); if (flash_ctrl->switch_trigger == NULL) { + if (flash_ctrl->platform_flash_init) + return ret; pr_err("%s:%d Invalid argument\n", __func__, __LINE__); return -EINVAL; @@ -1286,6 +1291,8 @@ static int32_t msm_flash_platform_probe(struct platform_device *pdev) kfree(flash_ctrl); return -EINVAL; } + if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO) + platform_set_drvdata(pdev, flash_ctrl); flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE; flash_ctrl->power_info.dev = &flash_ctrl->pdev->dev; @@ -1334,6 +1341,11 @@ static int32_t msm_flash_platform_probe(struct platform_device *pdev) return rc; } +int32_t camera_flash_platform_probe(struct platform_device *pdev) +{ + return msm_flash_platform_probe(pdev); +} + MODULE_DEVICE_TABLE(of, msm_flash_dt_match); static struct platform_driver msm_flash_platform_driver = { diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h index eda6ce44b6bc..67a8c2c7333a 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/msm_flash.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2016, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-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 @@ -102,6 +102,8 @@ struct msm_flash_ctrl_t { /* flash state */ enum msm_camera_flash_state_t flash_state; + int32_t (*platform_flash_init)(struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data); }; int msm_flash_i2c_probe(struct i2c_client *client, @@ -124,4 +126,6 @@ int msm_flash_led_release(struct msm_flash_ctrl_t *fctrl); int msm_flash_led_off(struct msm_flash_ctrl_t *fctrl); int msm_flash_led_low(struct msm_flash_ctrl_t *fctrl); int msm_flash_led_high(struct msm_flash_ctrl_t *fctrl); +int32_t camera_flash_platform_probe(struct platform_device *pdev); + #endif diff --git a/drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c b/drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c new file mode 100644 index 000000000000..11a7db55e3f4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v2/sensor/flash/qm215_gpio_flash.c @@ -0,0 +1,264 @@ +/* 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 <linux/module.h> +#include <linux/export.h> +#include "msm_camera_io_util.h" +#include "msm_flash.h" + +#define FLASH_NAME "qcom,gpio-flash" + +#undef CDBG +#define CDBG(fmt, args...) pr_debug(fmt, ##args) + +static const struct of_device_id msm_gpio_flash_dt_match[] = { + {.compatible = "qcom,qm215-gpio-flash", .data = NULL}, + {} +}; +static struct msm_flash_table qm215_gpio_flash_table; +MODULE_DEVICE_TABLE(of, msm_flash_dt_match); + +static int32_t qm215_flash_low( + struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ + struct msm_camera_power_ctrl_t *power_info = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + if (!flash_ctrl) { + pr_err("device data NULL\n"); + return -EINVAL; + } + + CDBG("Enter"); + power_info = &flash_ctrl->power_info; + gpio_num_info = power_info->gpio_conf->gpio_num_info; + + if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO && + gpio_num_info->valid[SENSOR_GPIO_FL_NOW] && + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]) { + + CDBG("flash op low gpio num %d(state:%d) %d(state: %d)\n", + gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH, + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + gpio_set_value_cansleep( + gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_HIGH); + gpio_set_value_cansleep( + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + } + CDBG("Exit\n"); + return 0; +} + +static int32_t qm215_flash_high( + struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ + struct msm_camera_power_ctrl_t *power_info = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + if (!flash_ctrl) { + pr_err("device data NULL\n"); + return -EINVAL; + } + + CDBG("Enter\n"); + power_info = &flash_ctrl->power_info; + gpio_num_info = power_info->gpio_conf->gpio_num_info; + + if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO && + gpio_num_info->valid[SENSOR_GPIO_FL_NOW] && + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]) { + + CDBG("flash op high gpio num %d(state:%d) %d(state:%d)\n", + gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW, + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + gpio_set_value_cansleep( + gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + gpio_set_value_cansleep( + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_HIGH); + } + CDBG("Exit\n"); + + return 0; +} + +static int32_t qm215_flash_release( + struct msm_flash_ctrl_t *flash_ctrl) +{ + int32_t rc = 0; + + if (!flash_ctrl) { + pr_err("device data NULL\n"); + return -EINVAL; + } + + CDBG("Enter\n"); + rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, NULL); + if (rc < 0) { + pr_err("%s:%d camera_flash_init failed rc = %d", + __func__, __LINE__, rc); + return rc; + } + flash_ctrl->flash_state = MSM_CAMERA_FLASH_RELEASE; + CDBG("Exit\n"); + return 0; +} + +static int32_t qm215_flash_off(struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ + struct msm_camera_power_ctrl_t *power_info = NULL; + struct msm_camera_gpio_num_info *gpio_num_info = NULL; + + if (!flash_ctrl) { + pr_err("device data NULL\n"); + return -EINVAL; + } + + CDBG("Enter\n"); + power_info = &flash_ctrl->power_info; + gpio_num_info = power_info->gpio_conf->gpio_num_info; + + if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO && + gpio_num_info->valid[SENSOR_GPIO_FL_NOW] && + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN]) { + + CDBG("flash off gpio num %d(state:%d) %d(state: %d)\n", + gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW, + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_LOW); + gpio_set_value_cansleep( + gpio_num_info->gpio_num[SENSOR_GPIO_FL_NOW], + GPIO_OUT_LOW); + gpio_set_value_cansleep( + gpio_num_info->gpio_num[SENSOR_GPIO_FL_EN], + GPIO_OUT_LOW); + } + + CDBG("Exit\n"); + return 0; +} + +static int32_t qm215_flash_gpio_init( + struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ + int32_t rc = 0; + + CDBG("Enter"); + rc = flash_ctrl->func_tbl->camera_flash_off(flash_ctrl, flash_data); + + CDBG("Exit"); + return rc; +} + + +static int32_t qm215_platform_flash_init(struct msm_flash_ctrl_t *flash_ctrl, + struct msm_flash_cfg_data_t *flash_data) +{ + if (!flash_ctrl) { + pr_err("devices data NULL\n"); + return -EINVAL; + } + + if (flash_ctrl->flash_driver_type == FLASH_DRIVER_GPIO) + flash_ctrl->func_tbl = &qm215_gpio_flash_table.func_tbl; + + return 0; +} +static int32_t qm215_flash_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct msm_flash_ctrl_t *flash_ctrl = NULL; + struct msm_camera_power_ctrl_t *power_info = NULL; + struct msm_camera_gpio_conf *gpio_conf = NULL; + + if (!pdev->dev.of_node) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + CDBG("enter probe\n"); + rc = camera_flash_platform_probe(pdev); + if (rc >= 0) { + flash_ctrl = + (struct msm_flash_ctrl_t *) platform_get_drvdata(pdev); + CDBG("device data %pK\n", flash_ctrl); + if (!flash_ctrl) { + pr_err("of_node NULL\n"); + return -EINVAL; + } + power_info = &flash_ctrl->power_info; + gpio_conf = power_info->gpio_conf; + rc = msm_camera_request_gpio_table(gpio_conf->cam_gpio_req_tbl, + gpio_conf->cam_gpio_req_tbl_size, 1); + if (rc < 0) { + pr_err("%s: request gpio failed\n", __func__); + return rc; + } + flash_ctrl->platform_flash_init = qm215_platform_flash_init; + } + return rc; +} + +static struct platform_driver msm_gpio_flash_platform_driver = { + .probe = qm215_flash_platform_probe, + .driver = { + .name = "qcom,camera-gpio-flash", + .owner = THIS_MODULE, + .of_match_table = msm_gpio_flash_dt_match, + }, +}; + +static int __init qm215_gpio_flash_init_module(void) +{ + int32_t rc = 0; + + CDBG("Enter\n"); + rc = platform_driver_register(&msm_gpio_flash_platform_driver); + if (rc) + pr_err("platform probe for flash failed"); + + return rc; +} + +static void __exit qm215_gpio_flash_exit_module(void) +{ + platform_driver_unregister(&msm_gpio_flash_platform_driver); +} + +static struct msm_flash_table qm215_gpio_flash_table = { + .flash_driver_type = FLASH_DRIVER_GPIO, + .func_tbl = { + .camera_flash_init = qm215_flash_gpio_init, + .camera_flash_release = qm215_flash_release, + .camera_flash_off = qm215_flash_off, + .camera_flash_low = qm215_flash_low, + .camera_flash_high = qm215_flash_high, + .camera_flash_query_current = NULL, + }, +}; + +module_init(qm215_gpio_flash_init_module); +module_exit(qm215_gpio_flash_exit_module); +MODULE_DESCRIPTION("MSM GPIO FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c index 13a653ae0399..e1809a1d789c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_hw_core.c @@ -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 @@ -509,8 +509,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)) { @@ -550,35 +550,33 @@ static void cam_hw_cdm_work(struct work_struct *work) cdm_hw = payload->hw; core = (struct cam_cdm *)cdm_hw->core_info; - CAM_DBG(CAM_CDM, "IRQ status=%x", payload->irq_status); + CAM_DBG(CAM_CDM, "IRQ status=0x%x", payload->irq_status); if (payload->irq_status & CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { - struct cam_cdm_bl_cb_request_entry *node; + struct cam_cdm_bl_cb_request_entry *node, *tnode; - CAM_DBG(CAM_CDM, "inline IRQ data=%x", + CAM_DBG(CAM_CDM, "inline IRQ data=0x%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) { + list_for_each_entry_safe(node, tnode, + &core->bl_request_list, entry) { if (node->request_type == CAM_HW_CDM_BL_CB_CLIENT) { cam_cdm_notify_clients(cdm_hw, CAM_CDM_CB_STATUS_BL_SUCCESS, (void *)node); } else if (node->request_type == - CAM_HW_CDM_BL_CB_INTERNAL) { + CAM_HW_CDM_BL_CB_INTERNAL) { CAM_ERR(CAM_CDM, "Invalid node=%pK %d", node, node->request_type); } list_del_init(&node->entry); + if (node->bl_tag == payload->irq_data) { + kfree(node); + break; + } kfree(node); - } 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); } @@ -684,7 +682,7 @@ irqreturn_t cam_hw_cdm_irq(int irq_num, void *data) 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", + CAM_ERR(CAM_CDM, "Failed to queue work for irq=0x%x", payload->irq_status); kfree(payload); } diff --git a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c index 9021ecabb27c..e5034c59a4a2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_cdm/cam_cdm_virtual_core.c @@ -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 @@ -118,6 +118,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_v3/cam_core/cam_context.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c index d4f9b72f99f3..5f9d1e06d8a8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context.c @@ -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 @@ -43,7 +43,6 @@ int cam_context_shutdown(struct cam_context *ctx) int rc = 0; struct cam_release_dev_cmd cmd; - mutex_lock(&ctx->ctx_mutex); if (ctx->state > CAM_CTX_AVAILABLE && ctx->state < CAM_CTX_STATE_MAX) { cmd.session_handle = ctx->session_hdl; cmd.dev_handle = ctx->dev_hdl; @@ -60,7 +59,6 @@ int cam_context_shutdown(struct cam_context *ctx) ctx->dev_name, ctx->ctx_id, ctx->state); rc = -EINVAL; } - mutex_unlock(&ctx->ctx_mutex); rc = cam_destroy_device_hdl(ctx->dev_hdl); if (rc) @@ -173,6 +171,7 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, 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); @@ -181,6 +180,7 @@ int cam_context_handle_crm_apply_req(struct cam_context *ctx, ctx->dev_hdl, ctx->state); rc = -EPROTO; } + mutex_unlock(&ctx->ctx_mutex); return rc; } @@ -243,6 +243,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, return -EINVAL; } + mutex_lock(&ctx->ctx_mutex); if (ctx->state_machine[ctx->state].pagefault_ops) { rc = ctx->state_machine[ctx->state].pagefault_ops(ctx, iova, buf_info); @@ -250,6 +251,7 @@ int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova, CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d", ctx->dev_hdl, ctx->state); } + mutex_unlock(&ctx->ctx_mutex); return rc; } @@ -528,6 +530,7 @@ int cam_context_init(struct cam_context *ctx, ctx->dev_name = dev_name; ctx->dev_id = dev_id; ctx->ctx_id = ctx_id; + ctx->last_flush_req = 0; ctx->ctx_crm_intf = NULL; ctx->crm_ctx_intf = crm_node_intf; ctx->hw_mgr_intf = hw_mgr_intf; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c index d98b900bc07a..174469e473da 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_context_utils.c @@ -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 @@ -262,6 +262,7 @@ int32_t cam_context_release_dev_to_hw(struct cam_context *ctx, ctx->session_hdl = -1; ctx->dev_hdl = -1; ctx->link_hdl = -1; + ctx->last_flush_req = 0; return 0; } @@ -303,6 +304,12 @@ int32_t cam_context_config_dev_to_hw( return rc; } + if ((len < sizeof(struct cam_packet)) || + (cmd->offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_CTXT, "Not enough buf"); + return -EINVAL; + + } packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); @@ -333,6 +340,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; + size_t remain_len = 0; int32_t i = 0, j = 0; if (!ctx || !cmd) { @@ -381,11 +389,19 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, goto free_req; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_CTXT, "invalid buff length: %zu or offset", len); + return -EINVAL; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *) ((uint8_t *)packet_addr + (uint32_t)cmd->offset); if (packet->header.request_id <= ctx->last_flush_req) { - CAM_DBG(CAM_CORE, + CAM_ERR(CAM_CORE, "request %lld has been flushed, reject packet", packet->header.request_id); rc = -EINVAL; @@ -398,6 +414,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); cfg.packet = packet; + cfg.remain_len = remain_len; cfg.ctxt_to_hw_map = ctx->ctxt_to_hw_map; cfg.max_hw_update_entries = CAM_CTX_CFG_MAX; cfg.num_hw_update_entries = req->num_hw_update_entries; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_core_defs.h b/drivers/media/platform/msm/camera_v3/cam_core/cam_core_defs.h deleted file mode 100644 index 32330b1e07e4..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_core_defs.h +++ /dev/null @@ -1,44 +0,0 @@ -/* 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_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_v3/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h index fd30f115cc0c..c3d1c2eff4e9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_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 @@ -153,6 +153,7 @@ struct cam_hw_mgr_dump_pf_data { * struct cam_hw_prepare_update_args - Payload for prepare command * * @packet: CSL packet from user mode driver + * @remain_len Remaining length of CPU buffer after config offset * @ctxt_to_hw_map: HW context from the acquire * @max_hw_update_entries: Maximum hardware update entries supported * @hw_update_entries: Actual hardware update configuration (returned) @@ -169,6 +170,7 @@ struct cam_hw_mgr_dump_pf_data { */ struct cam_hw_prepare_update_args { struct cam_packet *packet; + size_t remain_len; void *ctxt_to_hw_map; uint32_t max_hw_update_entries; struct cam_hw_update_entry *hw_update_entries; diff --git a/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c b/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c index 9da340b1e766..ee9b2bfc1bfa 100644 --- a/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera_v3/cam_core/cam_node.c @@ -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 @@ -111,6 +111,7 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, goto err; } + ctx->last_flush_req = 0; rc = cam_context_handle_acquire_dev(ctx, acquire); if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", @@ -657,6 +658,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "acquire device failed(rc = %d)", rc); goto acquire_kfree; } + CAM_INFO(CAM_CORE, "Acquire HW successful"); } if (copy_to_user((void __user *)cmd->handle, acquire_ptr, @@ -763,6 +765,8 @@ acquire_kfree: "release device failed(rc = %d)", rc); } + CAM_INFO(CAM_CORE, "Release HW done(rc = %d)", rc); + release_kfree: kfree(release_ptr); break; diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c index 2a91f03ecdc8..017e810e07c0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.c @@ -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 @@ -313,6 +313,9 @@ static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, goto mnoc_node_get_fail; } axi_port->axi_port_mnoc_node = axi_port_mnoc_node; + axi_port->ib_bw_voting_needed = + of_property_read_bool(axi_port_node, + "ib-bw-voting-needed"); rc = cam_cpas_util_register_bus_client(soc_info, axi_port_mnoc_node, &axi_port->mnoc_bus); @@ -662,12 +665,19 @@ static int cam_cpas_util_apply_client_axi_vote( 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 (axi_port->ib_bw_voting_needed) + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, + mnoc_bw, mnoc_bw, false); + else + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, + mnoc_bw, 0, false); + if (rc) { CAM_ERR(CAM_CPAS, "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", - mnoc_bw, mnoc_bw, rc); + mnoc_bw, + (axi_port->ib_bw_voting_needed ? mnoc_bw : 0), + rc); goto unlock_axi_port; } diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h index f93d036ecfcf..8e016191edb2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.h +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cam_cpas_hw.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 @@ -149,6 +149,7 @@ struct cam_cpas_bus_client { * @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 + * @ib_bw_voting_needed: if this port can update ib bw dynamically * @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 @@ -161,6 +162,7 @@ struct cam_cpas_axi_port { struct cam_cpas_bus_client camnoc_bus; struct cam_cpas_bus_client mnoc_bus; const char *axi_port_name; + bool ib_bw_voting_needed; struct device_node *axi_port_node; struct device_node *axi_port_mnoc_node; struct device_node *axi_port_camnoc_node; diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c index 8f89c4b7b5fd..49774f24ba20 100644 --- a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -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 @@ -20,9 +20,11 @@ #include "cam_io_util.h" #include "cam_cpas_soc.h" #include "cpastop100.h" +#include "cpastop_v150_100.h" #include "cpastop_v170_110.h" #include "cpastop_v175_100.h" #include "cpastop_v175_101.h" +#include "cpastop_v175_120.h" struct cam_camnoc_info *camnoc_info; @@ -104,6 +106,17 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, (hw_caps->cpas_version.minor == 0) && (hw_caps->cpas_version.incr == 1)) soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V120; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 5) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_150_V100; } CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); @@ -642,6 +655,12 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, case CAM_CPAS_TITAN_175_V101: camnoc_info = &cam175_cpas101_camnoc_info; break; + case CAM_CPAS_TITAN_175_V120: + camnoc_info = &cam175_cpas120_camnoc_info; + break; + case CAM_CPAS_TITAN_150_V100: + camnoc_info = &cam150_cpas100_camnoc_info; + break; default: CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d", hw_caps->camera_version.major, diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v150_100.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v150_100.h new file mode 100644 index 000000000000..cf9f82d07b20 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v150_100.h @@ -0,0 +1,537 @@ +/* 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. + */ + +#ifndef _CPASTOP_V150_100_H_ +#define _CPASTOP_V150_100_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v150_100_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2040, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2048, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2080, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v150_100_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2718, /* ERRLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x5a0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x590, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x598, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x9a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x990, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x998, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0xd20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0xd10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0xd18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x11a0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x1190, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x1198, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2088, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2090, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v150_100_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x30, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x34, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x38, /* SPECIFIC_CDM_URGENCY_LOW */ + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x40, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x48, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE02, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x430, /* SPECIFIC_IFE02_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x434, /* SPECIFIC_IFE02_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x438, /* SPECIFIC_IFE02_URGENCY_LOW */ + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE02_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x440, /* SPECIFIC_IFE02_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x448, /* SPECIFIC_IFE02_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE13, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x830, /* SPECIFIC_IFE13_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x834, /* SPECIFIC_IFE13_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x838, /* SPECIFIC_IFE13_URGENCY_LOW */ + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE13_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x840, /* SPECIFIC_IFE13_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x848, /* SPECIFIC_IFE13_SAFELUT_LOW */ + .value = 0x1, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0xc38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xc48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0xd08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1030, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1034, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x1038, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1040, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1048, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1188, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0x5, + }, + }, + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1430, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1434, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1438, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1440, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x1448, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = false, + }, + { + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2088, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam150_cpas100_err_logger_offsets = { + .mainctrl = 0x2708, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x2710, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x2720, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x2724, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x2728, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x272c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x2730, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x2734, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x2738, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x273c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam150_cpas100_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2100, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam150_cpas100_camnoc_info = { + .specific = &cam_cpas_v150_100_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v150_100_camnoc_specific) / + sizeof(cam_cpas_v150_100_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v150_100_irq_sbm, + .irq_err = &cam_cpas_v150_100_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v150_100_irq_err) / + sizeof(cam_cpas_v150_100_irq_err[0]), + .err_logger = &cam150_cpas100_err_logger_offsets, + .errata_wa_list = &cam150_cpas100_errata_wa_list, +}; + +#endif /* _CPASTOP_V150_100_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v175_120.h b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v175_120.h new file mode 100644 index 000000000000..7212bb30940a --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_cpas/cpas_top/cpastop_v175_120.h @@ -0,0 +1,769 @@ +/* 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. + */ + +#ifndef _CPASTOP_V175_120_H_ +#define _CPASTOP_V175_120_H_ + +#define TEST_IRQ_ENABLE 0 + +static struct cam_camnoc_irq_sbm cam_cpas_v175_120_irq_sbm = { + .sbm_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2240, /* SBM_FAULTINEN0_LOW */ + .value = 0x1 | /* SBM_FAULTINEN0_LOW_PORT0_MASK*/ + 0x2 | /* SBM_FAULTINEN0_LOW_PORT1_MASK */ + 0x4 | /* SBM_FAULTINEN0_LOW_PORT2_MASK */ + 0x8 | /* SBM_FAULTINEN0_LOW_PORT3_MASK */ + 0x10 | /* SBM_FAULTINEN0_LOW_PORT4_MASK */ + 0x20 | /* SBM_FAULTINEN0_LOW_PORT5_MASK */ + (TEST_IRQ_ENABLE ? + 0x100 : /* SBM_FAULTINEN0_LOW_PORT8_MASK */ + 0x0), + }, + .sbm_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2248, /* SBM_FAULTINSTATUS0_LOW */ + }, + .sbm_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2280, /* SBM_FLAGOUTCLR0_LOW */ + .value = TEST_IRQ_ENABLE ? 0x6 : 0x2, + } +}; + +static struct cam_camnoc_irq_err + cam_cpas_v175_120_irq_err[] = { + { + .irq_type = CAM_CAMNOC_HW_IRQ_SLAVE_ERROR, + .enable = true, + .sbm_port = 0x1, /* SBM_FAULTINSTATUS0_LOW_PORT0_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x4F08, /* ERRORLOGGER_MAINCTL_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x4F10, /* ERRORLOGGER_ERRVLD_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x4F18, /* ERRORLOGGER_ERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE0_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x2, /* SBM_FAULTINSTATUS0_LOW_PORT1_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x3BA0, /* SPECIFIC_IFE02_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x3B90, /* SPECIFIC_IFE02_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x3B98, /* SPECIFIC_IFE02_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x4, /* SBM_FAULTINSTATUS0_LOW_PORT2_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x55a0, /* SPECIFIC_IFE13_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x5590, /* SPECIFIC_IFE13_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x5598, /* SPECIFIC_IFE13_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR, + .enable = true, + .sbm_port = 0x8, /* SBM_FAULTINSTATUS0_LOW_PORT3_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2F20, /* SPECIFIC_IBL_RD_DECERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2F10, /* SPECIFIC_IBL_RD_DECERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2F18, /* SPECIFIC_IBL_RD_DECERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR, + .enable = true, + .sbm_port = 0x10, /* SBM_FAULTINSTATUS0_LOW_PORT4_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2Ba0, /* SPECIFIC_IBL_WR_ENCERREN_LOW */ + .value = 1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2B90, + /* SPECIFIC_IBL_WR_ENCERRSTATUS_LOW */ + }, + .err_clear = { + .access_type = CAM_REG_TYPE_WRITE, + .enable = true, + .offset = 0x2B98, /* SPECIFIC_IBL_WR_ENCERRCLR_LOW */ + .value = 1, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT, + .enable = true, + .sbm_port = 0x20, /* SBM_FAULTINSTATUS0_LOW_PORT5_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x1, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED1, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_RESERVED2, + .enable = false, + }, + { + .irq_type = CAM_CAMNOC_HW_IRQ_CAMNOC_TEST, + .enable = TEST_IRQ_ENABLE ? true : false, + .sbm_port = 0x100, /* SBM_FAULTINSTATUS0_LOW_PORT8_MASK */ + .err_enable = { + .access_type = CAM_REG_TYPE_READ_WRITE, + .enable = true, + .offset = 0x2288, /* SBM_FLAGOUTSET0_LOW */ + .value = 0x5, + }, + .err_status = { + .access_type = CAM_REG_TYPE_READ, + .enable = true, + .offset = 0x2290, /* SBM_FLAGOUTSTATUS0_LOW */ + }, + .err_clear = { + .enable = false, + }, + }, +}; + +static struct cam_camnoc_specific + cam_cpas_v175_120_camnoc_specific[] = { + { + .port_type = CAM_CAMNOC_CDM, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4230, /* SPECIFIC_CDM_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4234, /* SPECIFIC_CDM_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* cdm_main_SpecificToNttpTr_Urgency_Low */ + .offset = 0x4238, + .mask = 0x7, /* SPECIFIC_CDM_URGENCY_LOW_READ_MASK */ + .shift = 0x0, /* SPECIFIC_CDM_URGENCY_LOW_READ_SHIFT */ + .value = 0x2, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4240, /* SPECIFIC_CDM_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x4248, /* SPECIFIC_CDM_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0123_RDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_LOW */ + .offset = 0x3630, + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE0123_PRIORITYLUT_HIGH */ + .offset = 0x3634, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3638, /* SPECIFIC_IFE0123_URGENCY_LOW */ + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0123_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3640, /* SPECIFIC_IFE0123_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3648, /* SPECIFIC_IFE0123_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE0_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A30, /* SPECIFIC_IFE0_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3A34, /* SPECIFIC_IFE0_PRIORITYLUT_HIGH */ + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3A38, /* SPECIFIC_IFE0_URGENCY_LOW */ + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE0_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A40, /* SPECIFIC_IFE0_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3A48, /* SPECIFIC_IFE0_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3B88, /* SPECIFIC_IFE0_ENCCTL_LOW */ + .value = 1, + }, + }, + { + /* IFE0/1 RDI READ PATH */ + .port_type = CAM_CAMNOC_IFE01_RDI_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3230, /* SPECIFIC_IFE1_PRIORITYLUT_LOW */ + .value = 0x44443333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3234, /* SPECIFIC_IFE1_PRIORITYLUT_HIGH */ + .value = 0x66665555, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x3238, /* SPECIFIC_IFE1_URGENCY_LOW */ + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_MASK */ + .mask = 0x7, + /* SPECIFIC_IFE1_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x0, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3240, /* SPECIFIC_IFE1_DANGERLUT_LOW */ + .value = 0x00000000, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x3248, /* SPECIFIC_IFE1_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_IFE1_NRDI_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5430, /* SPECIFIC_IFE1_WR_PRIORITYLUT_LOW */ + .value = 0x66665433, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IFE1_WR_PRIORITYLUT_HIGH */ + .offset = 0x5434, + .value = 0x66666666, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x5438, /* SPECIFIC_IFE1_WR_URGENCY_LOW */ + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IFE1_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5440, /* SPECIFIC_IFE1_WR_DANGERLUT_LOW */ + .value = 0xFFFFFF00, + }, + .safe_lut = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .offset = 0x5448, /* SPECIFIC_IFE1_WR_SAFELUT_LOW */ + .value = 0xF, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5588, /* SPECIFIC_IFE1_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_READ, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E30, /* SPECIFIC_IBL_RD_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E34, /* SPECIFIC_IBL_RD_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2E38, /* SPECIFIC_IBL_RD_URGENCY_LOW */ + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_MASK */ + .mask = 0x7, + /* SPECIFIC_IBL_RD_URGENCY_LOW_READ_SHIFT */ + .shift = 0x0, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E40, /* SPECIFIC_IBL_RD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2E48, /* SPECIFIC_IBL_RD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2F08, /* SPECIFIC_IBL_RD_DECCTL_LOW */ + .value = 1, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_BPS_LRME_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A30, /* SPECIFIC_IBL_WR_PRIORITYLUT_LOW */ + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A34, /* SPECIFIC_IBL_WR_PRIORITYLUT_HIGH */ + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + .offset = 0x2A38, /* SPECIFIC_IBL_WR_URGENCY_LOW */ + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_MASK */ + .mask = 0x70, + /* SPECIFIC_IBL_WR_URGENCY_LOW_WRITE_SHIFT */ + .shift = 0x4, + .value = 0x3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A40, /* SPECIFIC_IBL_WR_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2A48, /* SPECIFIC_IBL_WR_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2B88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 0, + }, + }, + { + .port_type = CAM_CAMNOC_IPE_VID_DISP_WRITE, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_LOW */ + .offset = 0x5E30, + .value = 0x33333333, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_PRIORITYLUT_HIGH */ + .offset = 0x5E34, + .value = 0x33333333, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 1, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW */ + .offset = 0x5E38, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_MASK */ + .mask = 0x70, + /* SPECIFIC_IPE_VID_DISP_URGENCY_LOW_READ_SHIFT */ + .shift = 0x4, + .value = 3, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC__IPE_VID_DISP_DANGERLUT_LOW */ + .offset = 0x5E40, + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + /* SPECIFIC_IPE_VID_DISP_SAFELUT_LOW */ + .offset = 0x5E48, + .value = 0x0, + }, + .ubwc_ctl = { + /* + * Do not explicitly set ubwc config register. + * Power on default values are taking care of required + * register settings. + */ + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x5F88, /* SPECIFIC_IBL_WR_ENCCTL_LOW */ + .value = 1, + }, + }, + + { + .port_type = CAM_CAMNOC_JPEG, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2630, /* SPECIFIC_JPEG_PRIORITYLUT_LOW */ + .value = 0x22222222, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2634, /* SPECIFIC_JPEG_PRIORITYLUT_HIGH */ + .value = 0x22222222, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2638, /* SPECIFIC_JPEG_URGENCY_LOW */ + .value = 0x22, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2640, /* SPECIFIC_JPEG_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x2648, /* SPECIFIC_JPEG_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + }, + { + .port_type = CAM_CAMNOC_FD, + .enable = true, + .priority_lut_low = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E30, /* SPECIFIC_FD_PRIORITYLUT_LOW */ + .value = 0x44444444, + }, + .priority_lut_high = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E34, /* SPECIFIC_FD_PRIORITYLUT_HIGH */ + .value = 0x44444444, + }, + .urgency = { + .enable = true, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E38, /* SPECIFIC_FD_URGENCY_LOW */ + .value = 0x44, + }, + .danger_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E40, /* SPECIFIC_FD_DANGERLUT_LOW */ + .value = 0x0, + }, + .safe_lut = { + .enable = false, + .access_type = CAM_REG_TYPE_READ_WRITE, + .masked_value = 0, + .offset = 0x3E48, /* SPECIFIC_FD_SAFELUT_LOW */ + .value = 0x0, + }, + .ubwc_ctl = { + .enable = false, + }, + + }, + { + /*SidebandManager_main_SidebandManager_FlagOutSet0_Low*/ + .port_type = CAM_CAMNOC_ICP, + .enable = true, + .flag_out_set0_low = { + .enable = true, + .access_type = CAM_REG_TYPE_WRITE, + .masked_value = 0, + .offset = 0x2288, + .value = 0x100000, + }, + }, +}; + +static struct cam_camnoc_err_logger_info cam175_cpas120_err_logger_offsets = { + .mainctrl = 0x4F08, /* ERRLOGGER_MAINCTL_LOW */ + .errvld = 0x4F10, /* ERRLOGGER_ERRVLD_LOW */ + .errlog0_low = 0x4F20, /* ERRLOGGER_ERRLOG0_LOW */ + .errlog0_high = 0x4F24, /* ERRLOGGER_ERRLOG0_HIGH */ + .errlog1_low = 0x4F28, /* ERRLOGGER_ERRLOG1_LOW */ + .errlog1_high = 0x4F2c, /* ERRLOGGER_ERRLOG1_HIGH */ + .errlog2_low = 0x4F30, /* ERRLOGGER_ERRLOG2_LOW */ + .errlog2_high = 0x4F34, /* ERRLOGGER_ERRLOG2_HIGH */ + .errlog3_low = 0x4F38, /* ERRLOGGER_ERRLOG3_LOW */ + .errlog3_high = 0x4F3c, /* ERRLOGGER_ERRLOG3_HIGH */ +}; + +static struct cam_cpas_hw_errata_wa_list cam175_cpas120_errata_wa_list = { + .camnoc_flush_slave_pending_trans = { + .enable = false, + .data.reg_info = { + .access_type = CAM_REG_TYPE_READ, + .offset = 0x2300, /* SidebandManager_SenseIn0_Low */ + .mask = 0xE0000, /* Bits 17, 18, 19 */ + .value = 0, /* expected to be 0 */ + }, + }, +}; + +static struct cam_camnoc_info cam175_cpas120_camnoc_info = { + .specific = &cam_cpas_v175_120_camnoc_specific[0], + .specific_size = sizeof(cam_cpas_v175_120_camnoc_specific) / + sizeof(cam_cpas_v175_120_camnoc_specific[0]), + .irq_sbm = &cam_cpas_v175_120_irq_sbm, + .irq_err = &cam_cpas_v175_120_irq_err[0], + .irq_err_size = sizeof(cam_cpas_v175_120_irq_err) / + sizeof(cam_cpas_v175_120_irq_err[0]), + .err_logger = &cam175_cpas120_err_logger_offsets, + .errata_wa_list = &cam175_cpas120_errata_wa_list, +}; + +#endif /* _CPASTOP_V175_120_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/Makefile b/drivers/media/platform/msm/camera_v3/cam_fd/Makefile index ed896e511963..2e4511d2b48f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_fd/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw_mgr/ diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile index d6e76d18e799..61c255e75158 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw/ diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index ec0a906cb99a..8403d4dbe533 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -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 @@ -30,7 +30,8 @@ static struct cam_fd_hw_mgr g_fd_hw_mgr; -static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet) +static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) { struct cam_cmd_buf_desc *cmd_desc = NULL; int i, rc; @@ -50,7 +51,7 @@ static int cam_fd_mgr_util_packet_validate(struct cam_packet *packet) packet->patch_offset, packet->num_patches, packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); - if (cam_packet_util_validate_packet(packet)) { + if (cam_packet_util_validate_packet(packet, remain_len)) { CAM_ERR(CAM_FD, "invalid packet:%d %d %d %d %d", packet->kmd_cmd_buf_index, packet->num_cmd_buf, packet->cmd_buf_offset, @@ -162,8 +163,10 @@ static int cam_fd_mgr_util_put_frame_req( mutex_lock(&g_fd_hw_mgr.frame_req_mutex); req_ptr = *frame_req; - if (req_ptr) + if (req_ptr) { + list_del_init(&req_ptr->list); list_add_tail(&req_ptr->list, src_list); + } *frame_req = NULL; mutex_unlock(&g_fd_hw_mgr.frame_req_mutex); @@ -608,7 +611,13 @@ 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); + return -EINVAL; + } cpu_addr[plane] += io_cfg[i].offsets[plane]; } @@ -1444,6 +1453,16 @@ unlock_dev_flush_ctx: for (i = 0; i < flush_args->num_req_pending; i++) { flush_req = (struct cam_fd_mgr_frame_request *) flush_args->flush_req_pending[i]; + CAM_DBG(CAM_FD, "flush pending req %llu", + flush_req->request_id); + cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, + &flush_req); + } + + for (i = 0; i < flush_args->num_req_active; i++) { + flush_req = (struct cam_fd_mgr_frame_request *) + flush_args->flush_req_active[i]; + CAM_DBG(CAM_FD, "flush active req %llu", flush_req->request_id); cam_fd_mgr_util_put_frame_req(&hw_mgr->frame_free_list, &flush_req); } @@ -1559,7 +1578,8 @@ static int cam_fd_mgr_hw_prepare_update(void *hw_mgr_priv, goto error; } - rc = cam_fd_mgr_util_packet_validate(prepare->packet); + rc = cam_fd_mgr_util_packet_validate(prepare->packet, + prepare->remain_len); if (rc) { CAM_ERR(CAM_FD, "Error in packet validation %d", rc); goto error; diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile index 7fe5a4067d02..389ca4c66b8d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/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_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index 12d3c6bf1060..4084c43c2902 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -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 @@ -427,6 +427,7 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, unsigned long flags; int i; + mutex_lock(&fd_hw->hw_mutex); spin_lock_irqsave(&fd_core->spin_lock, flags); if ((fd_core->core_state != CAM_FD_CORE_STATE_IDLE) || (fd_core->results_valid == false) || @@ -436,6 +437,7 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, fd_core->core_state, fd_core->results_valid, fd_core->hw_req_private); spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); return -EINVAL; } fd_core->core_state = CAM_FD_CORE_STATE_READING_RESULTS; @@ -516,6 +518,7 @@ static int cam_fd_hw_util_processcmd_frame_done(struct cam_hw_info *fd_hw, fd_core->hw_req_private = NULL; fd_core->core_state = CAM_FD_CORE_STATE_IDLE; spin_unlock_irqrestore(&fd_core->spin_lock, flags); + mutex_unlock(&fd_hw->hw_mutex); return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index c7ef37c65659..d4c9326ed5ab 100644 --- a/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -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 @@ -206,6 +206,10 @@ static const struct of_device_id cam_fd_hw_dt_match[] = { .compatible = "qcom,fd501", .data = &cam_fd_wrapper200_core501_info, }, + { + .compatible = "qcom,fd501", + .data = &cam_fd_wrapper200_core501_info, + }, {} }; MODULE_DEVICE_TABLE(of, cam_fd_hw_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h index 38137b89295e..9f81c9c7feb0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/fw_inc/hfi_session_defs.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 @@ -472,7 +472,6 @@ struct ica_stab_params { 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; diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c index da1bf9e52ce8..bf80938985f1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/hfi.c @@ -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 @@ -42,6 +42,9 @@ #define HFI_MAX_POLL_TRY 5 +#define HFI_MAX_PC_POLL_TRY 150 +#define HFI_POLL_TRY_SLEEP 2 + static struct hfi_info *g_hfi; unsigned int g_icp_mmu_hdl; static DEFINE_MUTEX(hfi_cmd_q_mutex); @@ -513,8 +516,8 @@ void cam_hfi_disable_cpu(void __iomem *icp_base) 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); + while (try < HFI_MAX_PC_POLL_TRY) { + data = cam_io_r_mb(icp_base + HFI_REG_A5_CSR_A5_STATUS); CAM_DBG(CAM_HFI, "wfi status = %x\n", (int)data); if (data & ICP_CSR_A5_STATUS_WFI) @@ -523,7 +526,7 @@ void cam_hfi_disable_cpu(void __iomem *icp_base) * and Host can the proceed. No interrupt is expected from FW * at this time. */ - msleep(100); + msleep_interruptible(HFI_POLL_TRY_SLEEP); try++; } diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c index b969c92ccbc8..a330cff293d6 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/bps_hw/bps_core.c @@ -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 @@ -226,6 +226,13 @@ static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info, bool reset_bps_top_fail = false; CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET"); + + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_ICP, "BPS reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + /* Reset BPS CDM core*/ cam_io_w_mb((uint32_t)0xF, soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 73e42de3fa03..3a2d854fb1f4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -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 @@ -62,6 +62,8 @@ static struct cam_icp_hw_mgr icp_hw_mgr; +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl); + static int cam_icp_send_ubwc_cfg(struct cam_icp_hw_mgr *hw_mgr) { struct cam_hw_intf *a5_dev_intf = NULL; @@ -1834,12 +1836,13 @@ static int cam_icp_mgr_process_fatal_error( if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); rc = cam_icp_mgr_trigger_recovery(hw_mgr); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); } return rc; } -static void cam_icp_mgr_process_dbg_buf(void) +static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl) { uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; struct hfi_msg_debug *dbg_msg; @@ -1861,6 +1864,8 @@ static void cam_icp_mgr_process_dbg_buf(void) timestamp = ((((uint64_t)(dbg_msg->timestamp_hi) << 32) | dbg_msg->timestamp_lo) >> 16); trace_cam_icp_fw_dbg(dbg_buf, timestamp/2); + if (!debug_lvl) + CAM_INFO(CAM_ICP, "FW_DBG:%s", dbg_buf); } size_processed += (pkt_ptr[ICP_PACKET_SIZE] >> BYTE_WORD_SHIFT); @@ -1986,9 +1991,7 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data) } } - if (icp_hw_mgr.a5_debug_type == - HFI_DEBUG_MODE_QUEUE) - cam_icp_mgr_process_dbg_buf(); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); if ((task_data->irq_status & A5_WDT_0) || (task_data->irq_status & A5_WDT_1)) { @@ -2469,7 +2472,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_ipebps_async *abort_cmd; packet_size = @@ -2508,6 +2511,7 @@ static int cam_icp_mgr_abort_handle( if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -2519,7 +2523,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_ipebps_async *destroy_cmd; @@ -2562,9 +2566,7 @@ static int cam_icp_mgr_destroy_handle( 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(); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } kfree(destroy_cmd); @@ -2871,6 +2873,7 @@ static int cam_icp_mgr_send_fw_init(struct cam_icp_hw_mgr *hw_mgr) if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message"); @@ -3122,6 +3125,7 @@ static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -3333,12 +3337,32 @@ static int cam_icp_mgr_pkt_validation(struct cam_packet *packet) return 0; } +static int cam_icp_mgr_put_cmd_buf(struct cam_packet *packet) +{ + int i = 0; + struct cam_cmd_buf_desc *cmd_desc = NULL; + + 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].type == CAM_CMD_BUF_FW) { + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_ICP, "put cmd buf failed: 0x%x", + cmd_desc[i].mem_handle); + } + } + + 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; + int num_cmd_buf = 0; uint64_t addr; size_t len; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -3352,32 +3376,39 @@ 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); - return rc; + goto rel_cmd_buf; } *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) { + if (rc || !cpu_addr) { CAM_ERR(CAM_ICP, "get cmd buf failed %x", hw_mgr->iommu_hdl); *fw_cmd_buf_iova_addr = 0; - return rc; + goto rel_cmd_buf; + } + 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"); + goto rel_cmd_buf; } 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; } @@ -3425,6 +3456,18 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, } return rc; + +rel_cmd_buf: + for (i = num_cmd_buf; i >= 0; i--) { + if (cmd_desc[i].type == CAM_CMD_BUF_FW) { + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) { + CAM_WARN(CAM_ICP, "put cmd buf failed 0x%x", + cmd_desc[i].mem_handle); + } + } + } + + return rc; } static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, @@ -3847,9 +3890,12 @@ static void cam_icp_mgr_print_io_bufs(struct cam_packet *packet, } CAM_INFO(CAM_ICP, - "pln %d w %d h %d size %d addr 0x%x offset 0x%x memh %x", - j, io_cfg[i].planes[j].width, + "pln %d dir %d w %d h %d s %u sh %u sz %d addr 0x%x off 0x%x memh %x", + j, io_cfg[i].direction, + io_cfg[i].planes[j].width, io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, + io_cfg[i].planes[j].slice_height, (int32_t)src_buf_size, (unsigned int)iova_addr, io_cfg[i].offsets[j], @@ -3936,6 +3982,9 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, packet = prepare_args->packet; + if (cam_packet_util_validate_packet(packet, prepare_args->remain_len)) + return -EINVAL; + rc = cam_icp_mgr_pkt_validation(packet); if (rc) { mutex_unlock(&ctx_data->ctx_mutex); @@ -3992,6 +4041,7 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u", packet->header.request_id, ctx_data->ctx_id); + cam_icp_mgr_put_cmd_buf(packet); mutex_unlock(&ctx_data->ctx_mutex); return rc; } @@ -4300,6 +4350,7 @@ static int cam_icp_mgr_create_handle(uint32_t dev_type, if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -4346,6 +4397,7 @@ static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data) if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); cam_hfi_queue_dump(); } @@ -4619,6 +4671,7 @@ get_io_buf_failed: hw_mgr->ctx_data[ctx_id].icp_dev_acquire_info = NULL; acquire_info_failed: cam_icp_mgr_put_ctx(ctx_data); + cam_icp_mgr_process_dbg_buf(icp_hw_mgr.a5_dbg_lvl); mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); return rc; @@ -4898,6 +4951,7 @@ static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_mgr->iommu_sec_hdl, hw_cmd_args->u.pf_args.buf_info, hw_cmd_args->u.pf_args.mem_found); + break; default: CAM_ERR(CAM_ICP, "Invalid cmd"); diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 234643e3d105..5a93df33925f 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.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 @@ -128,11 +128,11 @@ struct clk_work_data { }; /** - * struct icp_frame_info - * @request_id: request id - * @io_config: the address of io config - * @hfi_cfg_io_cmd: command struct to be sent to hfi - */ + * struct icp_frame_info + * @request_id: request id + * @io_config: the address of io config + * @hfi_cfg_io_cmd: command struct to be sent to hfi + */ struct icp_frame_info { uint64_t request_id; uint64_t io_config; diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 7bb9b9ed18a2..2ebe41417d1d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/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 diff --git a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c index 142fcdc6017d..1f71c7d4cd36 100644 --- a/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -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 @@ -222,6 +222,12 @@ static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info, bool reset_ipe_top_fail = false; CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET"); + if (!core_info->clk_enable || !core_info->cpas_start) { + CAM_ERR(CAM_HFI, "IPE reset failed. clk_en %d cpas_start %d", + core_info->clk_enable, core_info->cpas_start); + return -EINVAL; + } + /* IPE CDM core reset*/ cam_io_w_mb((uint32_t)0xF, soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c index 113e1a8d5298..3e8fe117ac2d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.c @@ -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 @@ -29,16 +29,6 @@ static const char isp_dev_name[] = "isp"; -char *substate_name[8] = { - "CAM_ISP_CTX_ACTIVATED_SOF", - "CAM_ISP_CTX_ACTIVATED_APPLIED", - "CAM_ISP_CTX_ACTIVATED_EPOCH", - "CAM_ISP_CTX_ACTIVATED_BUBBLE", - "CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED", - "CAM_ISP_CTX_ACTIVATED_HW_ERROR", - "CAM_ISP_CTX_ACTIVATED_HALT", - "CAM_ISP_CTX_ACTIVATED_MAX", -}; #define INC_STATE_MONITOR_HEAD(head) \ (atomic64_add_return(1, head) % \ CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) @@ -139,6 +129,8 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) size_t len = 0; uint32_t *buf_addr; uint32_t *buf_start, *buf_end; + size_t remain_len = 0; + bool need_put = false; for (i = 0; i < req_isp->num_cfg; i++) { rc = cam_packet_util_get_cmd_mem_addr( @@ -148,17 +140,35 @@ static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) "Failed to get_cmd_mem_addr, rc=%d", rc); } else { + if (req_isp->cfg[i].offset >= len) { + CAM_ERR(CAM_ISP, "Invalid offset"); + need_put = true; + goto put; + } + remain_len = len - req_isp->cfg[i].offset; + + if (req_isp->cfg[i].len > remain_len) { + CAM_ERR(CAM_ISP, "Invalid offset"); + need_put = true; + } +put: + if (need_put) { + if (cam_mem_put_cpu_buf(req_isp->cfg[i].handle)) + CAM_WARN(CAM_ISP, + "Failed to put cpu buf: 0x%x", + req_isp->cfg[i].handle); + need_put = false; + continue; + } + buf_start = (uint32_t *)((uint8_t *) buf_addr + req_isp->cfg[i].offset); buf_end = (uint32_t *)((uint8_t *) buf_start + req_isp->cfg[i].len - 1); - if (len < (buf_end - buf_start + 1)) { - CAM_DBG(CAM_ISP, - "Invalid len %zu, buf_start-end=%d", - len, (buf_end - buf_start + 1)); - continue; - } cam_cdm_util_dump_cmd_buf(buf_start, buf_end); + if (cam_mem_put_cpu_buf(req_isp->cfg[i].handle)) + CAM_WARN(CAM_ISP, "Failed to put cpu buf: 0x%x", + req_isp->cfg[i].handle); } } } @@ -426,11 +436,12 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( } if (!req_isp->bubble_detected) { - CAM_INFO(CAM_ISP, - "Sync with success: req %lld res 0x%x fd 0x%x", + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, req_isp->fence_map_out[j].resource_handle, - req_isp->fence_map_out[j].sync_id); + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_SUCCESS); @@ -438,11 +449,12 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); } else if (!req_isp->bubble_report) { - CAM_INFO(CAM_ISP, - "Sync with failure: req %lld res 0x%x fd 0x%x", + CAM_ERR(CAM_ISP, + "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, req_isp->fence_map_out[j].resource_handle, - req_isp->fence_map_out[j].sync_id); + req_isp->fence_map_out[j].sync_id, + ctx->ctx_id); rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); @@ -463,9 +475,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( continue; } - CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x", + CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", req->request_id, - req_isp->fence_map_out[j].sync_id); + req_isp->fence_map_out[j].sync_id, ctx->ctx_id); if (!rc) { req_isp->num_acked++; req_isp->fence_map_out[j].sync_id = -1; @@ -475,9 +487,9 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( 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", + "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", req->request_id, req_isp->num_acked, - req_isp->num_fence_map_out); + req_isp->num_fence_map_out, ctx->ctx_id); WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); } @@ -491,17 +503,18 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( req_isp->bubble_detected = false; list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); CAM_DBG(CAM_REQ, - "Move active request %lld to pending list(cnt = %d) [bubble recovery]", - req->request_id, ctx_isp->active_req_cnt); + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_REQ, - "Move active request %lld to free list(cnt = %d) [all fences done]", - req->request_id, ctx_isp->active_req_cnt); + "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } end: @@ -571,7 +584,6 @@ static void __cam_isp_ctx_send_sof_timestamp( static int __cam_isp_ctx_reg_upd_in_epoch_state( struct cam_isp_context *ctx_isp, void *evt_data) { - CAM_INFO(CAM_ISP, "state = %s IRQ is RUP", substate_name[ctx_isp->substate_activated]); if (ctx_isp->frame_id == 1) CAM_DBG(CAM_ISP, "Reg update for early PCR"); else @@ -589,7 +601,6 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( struct cam_context *ctx = ctx_isp->base; struct cam_isp_ctx_req *req_isp; - CAM_INFO(CAM_ISP, "state = %s IRQ is RUP", substate_name[ctx_isp->substate_activated]); if (list_empty(&ctx->wait_req_list)) { CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); goto end; @@ -602,14 +613,15 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( if (req_isp->num_fence_map_out != 0) { list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", - req->request_id, ctx_isp->active_req_cnt); + CAM_DBG(CAM_REQ, + "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { /* no io config, so the request is completed. */ list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_ISP, - "move active request %lld to free list(cnt = %d)", - req->request_id, ctx_isp->active_req_cnt); + "move active request %lld to free list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } /* @@ -617,7 +629,6 @@ static int __cam_isp_ctx_reg_upd_in_activated_state( * state so change substate here. */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: @@ -633,7 +644,6 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( struct cam_ctx_request *req; uint64_t request_id = 0; - CAM_INFO(CAM_ISP, "state = %s IRQ is EPOCH", substate_name[ctx_isp->substate_activated]); /* * notify reqmgr with sof signal. Note, due to scheduling delay * we can run into situation that two active requests has already @@ -650,8 +660,8 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( 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); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); } list_for_each_entry(req, &ctx->active_req_list, list) { @@ -668,7 +678,9 @@ static int __cam_isp_ctx_notify_sof_in_activated_state( __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"); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify SOF to CRM for ctx %u", + ctx->ctx_id); rc = -EFAULT; } @@ -693,14 +705,14 @@ static int __cam_isp_ctx_notify_eof_in_activated_state( 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); + CAM_DBG(CAM_ISP, "Notify CRM EOF frame %lld ctx %u", + ctx_isp->frame_id, ctx->ctx_id); } else { - CAM_ERR(CAM_ISP, "Can not notify EOF to CRM"); + CAM_ERR(CAM_ISP, "Can not notify EOF to CRM for ctx %u", + ctx->ctx_id); rc = -EFAULT; } - CAM_INFO(CAM_ISP, "state = %s IRQ is EOF", substate_name[ctx_isp->substate_activated]); return rc; } @@ -708,7 +720,6 @@ 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; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return 0; } @@ -733,11 +744,8 @@ static int __cam_isp_ctx_sof_in_activated_state( ctx_isp->boot_timestamp = sof_event_data->boot_time; __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); - CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", - ctx_isp->frame_id, ctx_isp->sof_timestamp_val); - CAM_INFO(CAM_ISP, "state = %s IRQ is SOF frame_id = %lld", - substate_name[ctx_isp->substate_activated], ctx_isp->frame_id); - + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx, ctx %u", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val, ctx->ctx_id); return rc; } @@ -775,7 +783,6 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, req->request_id); } - CAM_INFO(CAM_ISP, "state = %s IRQ is RUP", substate_name[ctx_isp->substate_activated]); end: return rc; } @@ -788,7 +795,6 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; - CAM_INFO(CAM_ISP, "state = %s IRQ is EPOCH", substate_name[ctx_isp->substate_activated]); if (list_empty(&ctx->wait_req_list)) { /* * If no wait req in epoch, this is an error case. @@ -796,7 +802,6 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, */ CAM_ERR(CAM_ISP, "No wait request"); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* Send SOF event as empty frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, @@ -820,8 +825,9 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, 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); + atomic_set(&ctx_isp->process_bubble, 1); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld, ctx %u", + ctx_isp->frame_id, ctx->ctx_id); } else { req_isp->bubble_report = 0; } @@ -830,8 +836,8 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, * Always move the request to active list. Let buf done * function handles the rest. */ - CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", - req->request_id, ctx_isp->active_req_cnt); + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d), ctx %u", + req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); ctx_isp->active_req_cnt++; list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); @@ -844,7 +850,6 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, CAM_REQ_MGR_SOF_EVENT_ERROR); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: @@ -868,7 +873,6 @@ static int __cam_isp_ctx_buf_done_in_applied(struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); return rc; } @@ -882,9 +886,6 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; struct cam_ctx_request *req; - CAM_INFO(CAM_ISP, "SURESH: state = %s IRQ is SOF frame_id = %lld", - substate_name[ctx_isp->substate_activated], ctx_isp->frame_id); - if (!evt_data) { CAM_ERR(CAM_ISP, "in valid sof event data"); return -EINVAL; @@ -898,7 +899,6 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; else CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, list); @@ -919,7 +919,6 @@ static int __cam_isp_ctx_buf_done_in_epoch(struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); return rc; } @@ -931,7 +930,6 @@ static int __cam_isp_ctx_buf_done_in_bubble( struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); return rc; } @@ -944,7 +942,6 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( struct cam_context *ctx = ctx_isp->base; uint64_t request_id = 0; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); /* * This means we missed the reg upd ack. So we need to * transition to BUBBLE state again. @@ -960,7 +957,6 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); goto end; } @@ -979,8 +975,8 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( notify.error = CRM_KMD_ERR_BUBBLE; ctx->ctx_crm_intf->notify_err(¬ify); CAM_DBG(CAM_REQ, - "Notify CRM about Bubble req_id %llu frame %lld", - req->request_id, ctx_isp->frame_id); + "Notify CRM about Bubble req_id %llu frame %lld, ctx %u", + req->request_id, ctx_isp->frame_id, ctx->ctx_id); } else { req_isp->bubble_report = 0; } @@ -989,7 +985,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( * Always move the request to active list. Let buf done * function handles the rest. */ - CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d) ctx %u", req->request_id, ctx_isp->active_req_cnt); ctx_isp->active_req_cnt++; list_del_init(&req->list); @@ -1009,7 +1005,6 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: req = list_last_entry(&ctx->active_req_list, struct cam_ctx_request, @@ -1027,7 +1022,6 @@ static int __cam_isp_ctx_buf_done_in_bubble_applied( struct cam_isp_hw_done_event_data *done = (struct cam_isp_hw_done_event_data *) evt_data; - CAM_INFO(CAM_ISP, "state = %s IRQ is BUF_DONE", substate_name[ctx_isp->substate_activated]); rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 1); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, @@ -1050,6 +1044,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, struct cam_req_mgr_error_notify notify; uint64_t error_request_id = 0; struct cam_hw_fence_map_entry *fence_map_out = NULL; + struct cam_req_mgr_message req_msg; struct cam_context *ctx = ctx_isp->base; struct cam_isp_hw_error_event_data *error_event_data = @@ -1084,7 +1079,9 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, } req_isp = (struct cam_isp_ctx_req *) req_to_dump->req_priv; - cam_isp_ctx_dump_req(req_isp); + + if (error_event_data->enable_reg_dump) + cam_isp_ctx_dump_req(req_isp); __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_ERROR, req_to_dump->request_id); @@ -1096,9 +1093,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, for (i = 0; i < req_isp->num_fence_map_out; i++) { fence_map_out = &req_isp->fence_map_out[i]; - CAM_ERR(CAM_ISP, "req %llu, Sync fd %x", + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", req->request_id, - req_isp->fence_map_out[i].sync_id); + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); if (req_isp->fence_map_out[i].sync_id != -1) { rc = cam_sync_signal( fence_map_out->sync_id, @@ -1125,9 +1124,11 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, for (i = 0; i < req_isp->num_fence_map_out; i++) { fence_map_out = &req_isp->fence_map_out[i]; - CAM_ERR(CAM_ISP, "req %llu, Sync fd %x", + CAM_ERR(CAM_ISP, + "req %llu, Sync fd 0x%x ctx %u", req->request_id, - req_isp->fence_map_out[i].sync_id); + req_isp->fence_map_out[i].sync_id, + ctx->ctx_id); if (req_isp->fence_map_out[i].sync_id != -1) { rc = cam_sync_signal( fence_map_out->sync_id, @@ -1214,14 +1215,39 @@ end: notify.error = CRM_KMD_ERR_FATAL; } - CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld\n", - error_request_id, ctx_isp->frame_id); + CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld ctx %u", + error_request_id, ctx_isp->frame_id, ctx->ctx_id); ctx->ctx_crm_intf->notify_err(¬ify); + + /* + * Need to send error occurred in KMD + * This will help UMD to take necessary action + * and to dump relevant info + */ + + if (notify.error == CRM_KMD_ERR_OVERFLOW) { + req_msg.session_hdl = ctx_isp->base->session_hdl; + req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl; + req_msg.u.err_msg.error_type = + CAM_REQ_MGR_ERROR_TYPE_RECOVERY; + req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl; + req_msg.u.err_msg.request_id = error_request_id; + req_msg.u.err_msg.resource_size = 0x0; + + if (cam_req_mgr_notify_message(&req_msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, + V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_ISP, + "Error in notifying the error time for req id:%lld ctx %u", + ctx_isp->last_applied_req_id, + ctx->ctx_id); + } ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); } else { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM"); + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can not notify ERRROR to CRM for ctx %u", + ctx->ctx_id); rc = -EFAULT; } @@ -1230,6 +1256,236 @@ end: return rc; } +static int __cam_isp_ctx_fs2_sof_in_sof_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_sof_event_data *sof_event_data = evt_data; + struct cam_ctx_request *req; + struct cam_context *ctx = ctx_isp->base; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + + req = list_last_entry(&ctx->pending_req_list, + struct cam_ctx_request, list); + + if (!evt_data) { + CAM_ERR(CAM_ISP, "in valid sof event data"); + return -EINVAL; + } + + ctx_isp->frame_id++; + ctx_isp->sof_timestamp_val = sof_event_data->timestamp; + ctx_isp->boot_timestamp = sof_event_data->boot_time; + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_SOF, req->request_id); + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (!(list_empty(&ctx->wait_req_list))) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + +end: + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_isp_hw_done_event_data *done = + (struct cam_isp_hw_done_event_data *) evt_data; + struct cam_context *ctx = ctx_isp->base; + int prev_active_req_cnt = 0; + int curr_req_id = 0; + struct cam_ctx_request *req; + + prev_active_req_cnt = ctx_isp->active_req_cnt; + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + if (req) + curr_req_id = req->request_id; + + rc = __cam_isp_ctx_handle_buf_done_in_activated_state(ctx_isp, done, 0); + + if (prev_active_req_cnt == ctx_isp->active_req_cnt + 1) { + if (list_empty(&ctx->wait_req_list) && + list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "No request, move to SOF"); + ctx_isp->substate_activated = + CAM_ISP_CTX_ACTIVATED_SOF; + if (ctx_isp->reported_req_id < curr_req_id) { + ctx_isp->reported_req_id = curr_req_id; + __cam_isp_ctx_send_sof_timestamp(ctx_isp, + curr_req_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + } + } + } + + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_epoch(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_buf_done_in_applied( + struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + + rc = __cam_isp_ctx_fs2_buf_done(ctx_isp, evt_data); + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_sof(struct cam_isp_context *ctx_isp, + void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED && ctx_isp->frame_id > 1) { + CAM_DBG(CAM_ISP, "invalid RUP"); + goto end; + } + + /* + * This is for the first update. The initial setting will + * cause the reg_upd in the first frame. + */ + if (!list_empty(&ctx->wait_req_list)) { + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out == req_isp->num_acked) + list_add_tail(&req->list, &ctx->free_req_list); + else + CAM_ERR(CAM_ISP, + "receive rup in unexpected state"); + } + if (req != NULL) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_REG_UPDATE, + req->request_id); + } +end: + return rc; +} + +static int __cam_isp_ctx_fs2_reg_upd_in_applied_state( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_context *ctx = ctx_isp->base; + struct cam_isp_ctx_req *req_isp; + struct cam_req_mgr_trigger_notify notify; + uint64_t request_id = 0; + + if (list_empty(&ctx->wait_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no waiting request"); + goto end; + } + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + list_del_init(&req->list); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + if (req_isp->num_fence_map_out != 0) { + list_add_tail(&req->list, &ctx->active_req_list); + ctx_isp->active_req_cnt++; + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + } else { + /* no io config, so the request is completed. */ + list_add_tail(&req->list, &ctx->free_req_list); + } + + /* + * This function only called directly from applied and bubble applied + * state so change substate here. + */ + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + if (req_isp->num_fence_map_out != 1) + goto end; + + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger && + ctx_isp->active_req_cnt <= 2) { + list_for_each_entry(req, &ctx->active_req_list, list) { + if (req->request_id > ctx_isp->reported_req_id) { + request_id = req->request_id; + ctx_isp->reported_req_id = request_id; + break; + } + } + + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + if (ctx_isp->subscribe_event & CAM_TRIGGER_POINT_SOF) { + notify.link_hdl = ctx->link_hdl; + notify.dev_hdl = ctx->dev_hdl; + notify.frame_id = ctx_isp->frame_id; + notify.trigger = CAM_TRIGGER_POINT_SOF; + + ctx->ctx_crm_intf->notify_trigger(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM SOF frame %lld", + ctx_isp->frame_id); + } + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); +end: + if (req != NULL && !rc) { + __cam_isp_ctx_update_state_monitor_array(ctx_isp, + CAM_ISP_STATE_CHANGE_TRIGGER_EPOCH, + req->request_id); + } + return rc; +} + static struct cam_isp_ctx_irq_ops cam_isp_ctx_activated_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { /* SOF */ @@ -1303,6 +1559,79 @@ static struct cam_isp_ctx_irq_ops }, }; +static struct cam_isp_ctx_irq_ops + cam_isp_ctx_fs2_state_machine_irq[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_fs2_reg_upd_in_sof, + __cam_isp_ctx_fs2_sof_in_sof_state, + __cam_isp_ctx_notify_eof_in_activated_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_fs2_reg_upd_in_applied_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + __cam_isp_ctx_reg_upd_in_epoch_state, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_fs2_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + NULL, + __cam_isp_ctx_notify_sof_in_activated_state, + __cam_isp_ctx_notify_eof_in_activated_state, + __cam_isp_ctx_buf_done_in_bubble, + }, + }, + /* Bubble Applied */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_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 */ + { + }, +}; + 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) @@ -1330,6 +1659,14 @@ static int __cam_isp_ctx_apply_req_in_activated_state( */ ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + if (atomic_read(&ctx_isp->process_bubble)) { + CAM_DBG(CAM_ISP, + "Processing bubble cannot apply Request Id %llu", + apply->request_id); + rc = -EAGAIN; + goto end; + } + spin_lock_bh(&ctx->lock); req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, list); @@ -1347,15 +1684,16 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } - CAM_DBG(CAM_REQ, "Apply request %lld in substate %d", req->request_id, - ctx_isp->substate_activated); + CAM_DBG(CAM_REQ, "Apply request %lld in substate %d ctx %u", + req->request_id, ctx_isp->substate_activated, ctx->ctx_id); req_isp = (struct cam_isp_ctx_req *) req->req_priv; if (ctx_isp->active_req_cnt >= 2) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "Reject apply request (id %lld) due to congestion(cnt = %d)", + "Reject apply request (id %lld) due to congestion(cnt = %d) ctx %u", req->request_id, - ctx_isp->active_req_cnt); + ctx_isp->active_req_cnt, + ctx->ctx_id); spin_lock_bh(&ctx->lock); if (!list_empty(&ctx->active_req_list)) @@ -1391,7 +1729,6 @@ static int __cam_isp_ctx_apply_req_in_activated_state( } else { spin_lock_bh(&ctx->lock); ctx_isp->substate_activated = next_state; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); ctx_isp->last_applied_req_id = apply->request_id; list_del_init(&req->list); list_add_tail(&req->list, &ctx->wait_req_list); @@ -1420,7 +1757,6 @@ static int __cam_isp_ctx_apply_req_in_sof( 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); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -1437,7 +1773,6 @@ static int __cam_isp_ctx_apply_req_in_epoch( 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); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -1454,7 +1789,6 @@ static int __cam_isp_ctx_apply_req_in_bubble( 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); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -1528,13 +1862,10 @@ static int __cam_isp_ctx_flush_req_in_top_state( struct cam_context *ctx, struct cam_req_mgr_flush_request *flush_req) { - struct cam_isp_context *ctx_isp = - (struct cam_isp_context *) ctx->ctx_priv; - struct cam_isp_stop_args stop_isp; - struct cam_hw_stop_args stop_args; - struct cam_isp_start_args start_isp; int rc = 0; + struct cam_isp_context *ctx_isp; + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { CAM_INFO(CAM_ISP, "Last request id to flush is %lld", flush_req->req_id); @@ -1546,47 +1877,7 @@ static int __cam_isp_ctx_flush_req_in_top_state( rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); spin_unlock_bh(&ctx->lock); - if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { - /* if active and wait list are empty, return */ - spin_lock_bh(&ctx->lock); - if ((list_empty(&ctx->wait_req_list)) && - (list_empty(&ctx->active_req_list))) { - spin_unlock_bh(&ctx->lock); - CAM_DBG(CAM_ISP, "active and wait list are empty"); - goto end; - } - spin_unlock_bh(&ctx->lock); - - /* Stop hw first before active list flush */ - stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx; - stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_AT_FRAME_BOUNDARY; - stop_isp.stop_only = true; - stop_args.args = (void *)&stop_isp; - ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv, - &stop_args); - - spin_lock_bh(&ctx->lock); - CAM_DBG(CAM_ISP, "try to flush wait list"); - rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list, - flush_req); - CAM_DBG(CAM_ISP, "try to flush active list"); - rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list, - flush_req); - ctx_isp->active_req_cnt = 0; - spin_unlock_bh(&ctx->lock); - - /* Start hw */ - start_isp.hw_config.ctxt_to_hw_map = ctx_isp->hw_ctx; - start_isp.start_only = true; - start_isp.hw_config.priv = NULL; - - rc = ctx->hw_mgr_intf->hw_start(ctx->hw_mgr_intf->hw_mgr_priv, - &start_isp); - } - -end: - CAM_DBG(CAM_ISP, "Flush request in top state %d", - ctx->state); + atomic_set(&ctx_isp->process_bubble, 0); return rc; } @@ -1664,6 +1955,58 @@ static struct cam_ctx_ops }, }; +static struct cam_ctx_ops + cam_isp_ctx_fs2_state_machine[CAM_ISP_CTX_ACTIVATED_MAX] = { + /* SOF */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_sof, + }, + .irq_ops = NULL, + }, + /* APPLIED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* EPOCH */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_epoch, + }, + .irq_ops = NULL, + }, + /* BUBBLE */ + { + .ioctl_ops = {}, + .crm_ops = { + .apply_req = __cam_isp_ctx_apply_req_in_bubble, + }, + .irq_ops = NULL, + }, + /* Bubble Applied */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HW ERROR */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, + /* HALT */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + static int __cam_isp_ctx_rdi_only_sof_in_top_state( struct cam_isp_context *ctx_isp, void *evt_data) { @@ -1718,7 +2061,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_top_state( else CAM_DBG(CAM_ISP, "Still need to wait for the buf done"); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); return rc; @@ -1741,7 +2083,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_applied_state( ctx_isp->frame_id, ctx_isp->sof_timestamp_val); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); return 0; @@ -1780,7 +2121,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( */ CAM_ERR(CAM_ISP, "No wait request"); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* Send SOF event as empty frame*/ __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, @@ -1835,7 +2175,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied( /* change the state to bubble, as reg update has not come */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_BUBBLE; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); end: return 0; @@ -1906,7 +2245,6 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state( CAM_REQ_MGR_SOF_EVENT_SUCCESS); ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); CAM_DBG(CAM_ISP, "next substate %d", ctx_isp->substate_activated); @@ -1924,7 +2262,6 @@ static int __cam_isp_ctx_rdi_only_reg_upd_in_bubble_applied_state( uint64_t request_id = 0; ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* notify reqmgr with sof signal*/ if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { if (list_empty(&ctx->wait_req_list)) { @@ -1986,7 +2323,6 @@ error: * to SOF sub state */ ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return 0; } @@ -2069,7 +2405,6 @@ static int __cam_isp_ctx_rdi_only_apply_req_top_state( 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); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); return rc; } @@ -2125,9 +2460,8 @@ static struct cam_ctx_ops }, }; -/* top level state machine */ -static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, - struct cam_release_dev_cmd *cmd) +static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, + void *cmd) { int rc = 0; struct cam_hw_release_args rel_arg; @@ -2135,28 +2469,16 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, (struct cam_isp_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; - if (ctx->link_hdl != -1) { - CAM_ERR(CAM_ISP, "ctx expects release dev after unlink"); - rc = -EAGAIN; - return rc; - } - - if (cmd && ctx_isp->hw_ctx && ctx_isp->split_acquire) { - CAM_ERR(CAM_ISP, "ctx expects release HW before release dev"); - return rc; - } - if (ctx_isp->hw_ctx) { rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &rel_arg); ctx_isp->hw_ctx = NULL; + } else { + CAM_ERR(CAM_ISP, "No hw resources acquired for this ctx"); } - ctx->session_hdl = -1; - ctx->dev_hdl = -1; - ctx->link_hdl = -1; - ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -2168,7 +2490,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, * 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"); + CAM_WARN(CAM_ISP, "Active list is not empty"); /* Flush all the pending request list */ flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; @@ -2179,7 +2501,7 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); spin_unlock_bh(&ctx->lock); - ctx->state = CAM_CTX_AVAILABLE; + ctx->state = CAM_CTX_ACQUIRED; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", @@ -2187,8 +2509,9 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, return rc; } -static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, - void *cmd) +/* 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; @@ -2196,15 +2519,23 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, (struct cam_isp_context *) ctx->ctx_priv; struct cam_req_mgr_flush_request flush_req; + if (cmd && ctx_isp->hw_ctx) { + CAM_ERR(CAM_ISP, "releasing hw"); + __cam_isp_ctx_release_hw_in_top_state(ctx, NULL); + } + if (ctx_isp->hw_ctx) { rel_arg.ctxt_to_hw_map = ctx_isp->hw_ctx; ctx->hw_mgr_intf->hw_release(ctx->hw_mgr_intf->hw_mgr_priv, &rel_arg); ctx_isp->hw_ctx = NULL; - } else { - CAM_ERR(CAM_ISP, "No hw resources acquired for this ctx"); } + ctx->session_hdl = -1; + ctx->dev_hdl = -1; + ctx->link_hdl = -1; + ctx->ctx_crm_intf = NULL; + ctx->last_flush_req = 0; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -2216,7 +2547,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, * But we still add some sanity check code here to help the debug */ if (!list_empty(&ctx->active_req_list)) - CAM_WARN(CAM_ISP, "Active list is not empty"); + CAM_ERR(CAM_ISP, "Active list is not empty"); /* Flush all the pending request list */ flush_req.type = CAM_REQ_MGR_FLUSH_TYPE_ALL; @@ -2227,7 +2558,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, spin_lock_bh(&ctx->lock); rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); spin_unlock_bh(&ctx->lock); - ctx->state = CAM_CTX_ACQUIRED; + ctx->state = CAM_CTX_AVAILABLE; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", @@ -2244,6 +2575,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; + size_t remain_len = 0; struct cam_hw_prepare_update_args cfg; struct cam_req_mgr_add_request add_req; struct cam_isp_context *ctx_isp = @@ -2262,8 +2594,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; @@ -2278,6 +2609,15 @@ static int __cam_isp_ctx_config_dev_in_top_state( goto free_req; } + remain_len = len; + if ((len < sizeof(struct cam_packet)) || + ((size_t)cmd->offset >= len - sizeof(struct cam_packet))) { + CAM_ERR(CAM_ISP, "invalid buff length: %zu or offset", len); + rc = -EINVAL; + goto free_cpu_buf; + } + + remain_len -= (size_t)cmd->offset; packet = (struct cam_packet *)(packet_addr + (uint32_t)cmd->offset); CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle); CAM_DBG(CAM_ISP, "packet address is 0x%zx", packet_addr); @@ -2288,20 +2628,19 @@ static int __cam_isp_ctx_config_dev_in_top_state( CAM_DBG(CAM_ISP, "Packet size 0x%x", packet->header.size); CAM_DBG(CAM_ISP, "packet op %d", packet->header.op_code); - if (packet->header.request_id <= ctx->last_flush_req) { + if ((((packet->header.op_code + 1) & 0xF) == CAM_ISP_PACKET_UPDATE_DEV) + && (packet->header.request_id <= ctx->last_flush_req)) { CAM_INFO(CAM_ISP, "request %lld has been flushed, reject packet", packet->header.request_id); rc = -EINVAL; - goto free_req; + goto free_cpu_buf; } - if (packet->header.request_id > ctx->last_flush_req) - ctx->last_flush_req = 0; - /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); cfg.packet = packet; + cfg.remain_len = remain_len; cfg.ctxt_to_hw_map = ctx_isp->hw_ctx; cfg.max_hw_update_entries = CAM_ISP_CTX_CFG_MAX; cfg.hw_update_entries = req_isp->cfg; @@ -2319,7 +2658,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( if (rc != 0) { CAM_ERR(CAM_ISP, "Prepare config packet failed in HW layer"); rc = -EFAULT; - goto free_req; + goto free_cpu_buf; } req_isp->num_cfg = cfg.num_hw_update_entries; req_isp->num_fence_map_out = cfg.num_out_map_entries; @@ -2380,6 +2719,10 @@ static int __cam_isp_ctx_config_dev_in_top_state( if (rc) goto put_ref; + if (cam_mem_put_cpu_buf((int32_t) cmd->packet_handle)) + CAM_WARN(CAM_ISP, "Can not put packet address : %llu", + cmd->packet_handle); + CAM_DBG(CAM_REQ, "Preprocessing Config req_id %lld successful on ctx %u", req->request_id, ctx->ctx_id); @@ -2388,16 +2731,19 @@ static int __cam_isp_ctx_config_dev_in_top_state( put_ref: for (--i; i >= 0; i--) { - rc = cam_sync_put_obj_ref(req_isp->fence_map_out[i].sync_id); - if (rc) + 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_cpu_buf: + if (cam_mem_put_cpu_buf((int32_t) cmd->packet_handle)) + CAM_WARN(CAM_ISP, "Can not put packet address: %llu", + cmd->packet_handle); free_req: spin_lock_bh(&ctx->lock); list_add_tail(&req->list, &ctx->free_req_list); spin_unlock_bh(&ctx->lock); -end: + return rc; } @@ -2476,7 +2822,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; - isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, &hw_cmd_args); @@ -2485,7 +2831,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, goto free_hw; } - if (isp_hw_cmd_args.u.is_rdi_only_context) { + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { /* * this context has rdi only resource assign rdi only * state machine @@ -2496,6 +2842,13 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -2504,7 +2857,6 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, cam_isp_ctx_activated_state_machine; } - ctx_isp->rdi_only_context = isp_hw_cmd_args.u.is_rdi_only_context; ctx_isp->hw_ctx = param.ctxt_to_hw_map; ctx_isp->hw_acquired = true; ctx_isp->split_acquire = false; @@ -2622,7 +2974,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL; - isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT; + isp_hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_CTX_TYPE; hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args; rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, &hw_cmd_args); @@ -2631,7 +2983,7 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, goto free_hw; } - if (isp_hw_cmd_args.u.is_rdi_only_context) { + if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_RDI) { /* * this context has rdi only resource assign rdi only * state machine @@ -2642,6 +2994,13 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, cam_isp_ctx_rdi_only_activated_state_machine_irq; ctx_isp->substate_machine = cam_isp_ctx_rdi_only_activated_state_machine; + ctx_isp->rdi_only_context = true; + } else if (isp_hw_cmd_args.u.ctx_type == CAM_ISP_CTX_FS2) { + CAM_DBG(CAM_ISP, "FS2 Session has PIX ,RD and RDI"); + ctx_isp->substate_machine_irq = + cam_isp_ctx_fs2_state_machine_irq; + ctx_isp->substate_machine = + cam_isp_ctx_fs2_state_machine; } else { CAM_DBG(CAM_ISP, "Session has PIX or PIX and RDI resources"); ctx_isp->substate_machine_irq = @@ -2650,16 +3009,14 @@ static int __cam_isp_ctx_acquire_hw_v1(struct cam_context *ctx, cam_isp_ctx_activated_state_machine; } - ctx_isp->rdi_only_context = isp_hw_cmd_args.u.is_rdi_only_context; ctx_isp->hw_ctx = param.ctxt_to_hw_map; ctx_isp->hw_acquired = true; ctx->ctxt_to_hw_map = param.ctxt_to_hw_map; trace_cam_context_state("ISP", ctx); CAM_DBG(CAM_ISP, - "Acquire success on session_hdl 0x%xs RDI only %d ctx %u", - ctx->session_hdl, - (isp_hw_cmd_args.u.is_rdi_only_context ? 1 : 0), ctx->ctx_id); + "Acquire success on session_hdl 0x%xs ctx_type %d ctx_id %u", + ctx->session_hdl, isp_hw_cmd_args.u.ctx_type, ctx->ctx_id); kfree(acquire_hw_info); return rc; @@ -2807,6 +3164,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, start_isp.hw_config.init_packet = 1; start_isp.start_only = false; + atomic_set(&ctx_isp->process_bubble, 0); ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; @@ -2814,7 +3172,6 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, CAM_ISP_CTX_ACTIVATED_APPLIED : (req_isp->num_fence_map_out) ? CAM_ISP_CTX_ACTIVATED_EPOCH : CAM_ISP_CTX_ACTIVATED_SOF; - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* * Only place to change state before calling the hw due to @@ -2876,7 +3233,6 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( 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); - CAM_INFO(CAM_ISP, "state changed to %s", substate_name[ctx_isp->substate_activated]); /* stop hw first */ if (ctx_isp->hw_ctx) { @@ -2944,9 +3300,16 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; + atomic_set(&ctx_isp->process_bubble, 0); CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", ctx->state, ctx->ctx_id); + + if (!stop_cmd) { + rc = __cam_isp_ctx_unlink_in_ready(ctx, NULL); + if (rc) + CAM_ERR(CAM_ISP, "Unlink failed rc=%d", rc); + } return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h index 5ebd82ead470..4954f2034144 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_context.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 @@ -144,6 +144,8 @@ struct cam_isp_context_state_monitor { * @base: Common context object pointer * @frame_id: Frame id tracking for the isp context * @substate_actiavted: Current substate for the activated state. + * @process_bubble: Atomic variable to check if ctx is still + * processing bubble. * @substate_machine: ISP substate machine for external interface * @substate_machine_irq: ISP substate machine for irq handling * @req_base: Common request object storage @@ -170,6 +172,7 @@ struct cam_isp_context { int64_t frame_id; uint32_t substate_activated; + atomic_t process_bubble; struct cam_ctx_ops *substate_machine; struct cam_isp_ctx_irq_ops *substate_machine_irq; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index a6c96bd8929c..582d4858e18b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -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 @@ -43,7 +43,7 @@ (CAM_ISP_PACKET_META_GENERIC_BLOB_COMMON + 1) #define CAM_ISP_GENERIC_BLOB_TYPE_MAX \ - (CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG + 1) + (CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG + 1) static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_GET_HFR_UPDATE, @@ -51,6 +51,7 @@ static uint32_t blob_type_hw_cmd_map[CAM_ISP_GENERIC_BLOB_TYPE_MAX] = { CAM_ISP_HW_CMD_BW_UPDATE, CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG, }; static struct cam_ife_hw_mgr g_ife_hw_mgr; @@ -316,6 +317,11 @@ static void cam_ife_hw_mgr_deinit_hw( cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); } + /* Deint IFE RD */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_deinit_hw_res(hw_mgr_res); + } + /* Deinit IFE OUT */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); @@ -366,6 +372,18 @@ static int cam_ife_hw_mgr_init_hw( } } + /* INIT IFE BUS RD */ + CAM_DBG(CAM_ISP, "INIT IFE BUS RD in ctx id:%d", + ctx->ctx_index); + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_init_hw_res(hw_mgr_res); + if (rc) { + CAM_ERR(CAM_ISP, "Can not IFE BUS RD (%d)", + hw_mgr_res->res_id); + return rc; + } + } + /* INIT IFE OUT */ CAM_DBG(CAM_ISP, "INIT IFE OUT RESOURCES in ctx id:%d", ctx->ctx_index); @@ -500,6 +518,13 @@ static int cam_ife_hw_mgr_release_hw_for_ctx( for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_free_hw_res(&ife_ctx->res_list_ife_out[i]); + /* ife bus rd resource */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &ife_ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_free_hw_res(hw_mgr_res); + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &hw_mgr_res); + } + /* ife source resource */ list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, &ife_ctx->res_list_ife_src, list) { @@ -645,6 +670,91 @@ static int cam_ife_mgr_process_base_info( return 0; } +static int cam_ife_hw_mgr_acquire_res_bus_rd( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_ife_hw_mgr_res *ife_in_rd_res; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *ife_src_res; + int i; + + CAM_DBG(CAM_ISP, "Enter"); + + list_for_each_entry(ife_src_res, &ife_ctx->res_list_ife_src, list) { + if (ife_src_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_in_rd_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_in_rd, + &ife_in_rd_res); + + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_out.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_out.ctx = ife_ctx; + vfe_acquire.vfe_out.unique_id = ife_ctx->ctx_index; + vfe_acquire.vfe_out.is_dual = ife_src_res->is_dual_vfe; + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!ife_src_res->hw_res[i]) + continue; + + hw_intf = ife_src_res->hw_res[i]->hw_intf; + if (i == CAM_ISP_HW_SPLIT_LEFT) { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_LEFT; + if (ife_src_res->is_dual_vfe) { + /*TBD */ + vfe_acquire.vfe_out.is_master = 1; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } else { + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + 0; + } + } else { + vfe_acquire.vfe_out.split_id = + CAM_ISP_HW_SPLIT_RIGHT; + vfe_acquire.vfe_out.is_master = 0; + vfe_acquire.vfe_out.dual_slave_core = + (hw_intf->hw_idx == 0) ? 1 : 0; + } + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire out resource 0x%x", + vfe_acquire.rsrc_type); + goto err; + } + + ife_in_rd_res->hw_res[i] = + vfe_acquire.vfe_out.rsrc_node; + CAM_DBG(CAM_ISP, "resource type :0x%x res id:0x%x", + ife_in_rd_res->hw_res[i]->res_type, + ife_in_rd_res->hw_res[i]->res_id); + + } + ife_in_rd_res->is_dual_vfe = in_port->usage_type; + ife_in_rd_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_VFE_BUS_RD; + } + + return 0; +err: + CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); + return rc; +} + static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_ife_hw_mgr_res *ife_src_res, @@ -724,6 +834,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( ife_out_res->res_type = (enum cam_ife_hw_mgr_res_type) CAM_ISP_RESOURCE_VFE_OUT; ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); return 0; err: @@ -817,6 +929,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( ife_out_res->res_id = out_port->res_type; ife_out_res->parent = ife_src_res; ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + CAM_DBG(CAM_ISP, "IFE SRC num_children = %d", + ife_src_res->num_children); } return 0; @@ -839,6 +953,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_out( switch (ife_src_res->res_id) { case CAM_ISP_HW_VFE_IN_CAMIF: case CAM_ISP_HW_VFE_IN_CAMIF_LITE: + case CAM_ISP_HW_VFE_IN_RD: rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, ife_src_res, in_port); break; @@ -864,6 +979,132 @@ err: return rc; } +static int cam_ife_hw_mgr_acquire_res_ife_rd_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port) +{ + int rc = -1; + struct cam_ife_hw_mgr_res *csid_res; + struct cam_ife_hw_mgr_res *ife_src_res; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr *ife_hw_mgr; + int vfe_idx = -1, i = 0; + + ife_hw_mgr = ife_ctx->hw_mgr; + + CAM_DBG(CAM_ISP, "Enter"); + list_for_each_entry(csid_res, &ife_ctx->res_list_ife_csid, list) { + if (csid_res->res_id != CAM_IFE_PIX_PATH_RES_RDI_0) { + CAM_DBG(CAM_ISP, "not RDI0: %d", csid_res->res_id); + continue; + } + + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, + &ife_src_res); + if (rc) { + CAM_ERR(CAM_ISP, "No more free hw mgr resource"); + goto err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_src, + &ife_src_res); + + CAM_DBG(CAM_ISP, "csid_res_id %d", csid_res->res_id); + vfe_acquire.rsrc_type = CAM_ISP_RESOURCE_VFE_IN; + vfe_acquire.tasklet = ife_ctx->common.tasklet_info; + vfe_acquire.vfe_in.cdm_ops = ife_ctx->cdm_ops; + vfe_acquire.vfe_in.in_port = in_port; + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_RD; + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_NONE; + + ife_src_res->res_type = + (enum cam_ife_hw_mgr_res_type)vfe_acquire.rsrc_type; + ife_src_res->res_id = vfe_acquire.vfe_in.res_id; + ife_src_res->is_dual_vfe = csid_res->is_dual_vfe; + + hw_intf = + ife_hw_mgr->ife_devices[csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx]; + + vfe_idx = csid_res->hw_res[ + CAM_ISP_HW_SPLIT_LEFT]->hw_intf->hw_idx; + + /* + * fill in more acquire information as needed + */ + if (ife_src_res->is_dual_vfe) + vfe_acquire.vfe_in.sync_mode = CAM_ISP_HW_SYNC_MASTER; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT] = + vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_type, + ife_src_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]->res_id); + + if (!ife_src_res->is_dual_vfe) + goto acq; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + CAM_DBG(CAM_ISP, "vfe_idx %d is acquired", + vfe_idx); + continue; + } + + hw_intf = ife_hw_mgr->ife_devices[i]; + + /* fill in more acquire information as needed */ + if (i == CAM_ISP_HW_SPLIT_RIGHT) + vfe_acquire.vfe_in.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &vfe_acquire, + sizeof(struct cam_vfe_acquire_args)); + if (rc) { + CAM_ERR(CAM_ISP, + "Can not acquire IFE HW res %d", + csid_res->res_id); + goto err; + } + ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; + CAM_DBG(CAM_ISP, + "acquire success IFE:%d res type :0x%x res id:0x%x", + hw_intf->hw_idx, + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + } +acq: + /* + * It should be one to one mapping between + * csid resource and ife source resource + */ + csid_res->child[0] = ife_src_res; + ife_src_res->parent = csid_res; + csid_res->child[csid_res->num_children++] = ife_src_res; + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", + csid_res->res_id, csid_res->num_children, + ife_src_res->res_id); + } + +err: + /* release resource at the entry function */ + CAM_DBG(CAM_ISP, "Exit rc(0x%x)", rc); + 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) @@ -976,7 +1217,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( 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", + CAM_DBG(CAM_ISP, + "csid_res=%d CSID num_children=%d ife_src_res=%d", csid_res->res_id, csid_res->num_children, ife_src_res->res_id); } @@ -991,7 +1233,7 @@ static int cam_ife_mgr_acquire_cid_res( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port, struct cam_ife_hw_mgr_res **cid_res, - enum cam_ife_pix_path_res_id csid_path) + enum cam_ife_pix_path_res_id path_res_id) { int rc = -1; int i, j; @@ -1015,8 +1257,8 @@ static int cam_ife_mgr_acquire_cid_res( csid_acquire.res_type = CAM_ISP_RESOURCE_CID; csid_acquire.in_port = in_port; - csid_acquire.res_id = csid_path; - CAM_DBG(CAM_ISP, "path %d", csid_path); + csid_acquire.res_id = path_res_id; + CAM_DBG(CAM_ISP, "path_res_id %d", path_res_id); if (in_port->num_out_res) out_port = &(in_port->data[0]); @@ -1049,12 +1291,12 @@ static int cam_ife_mgr_acquire_cid_res( csid_acquire.node_res; CAM_DBG(CAM_ISP, - "acquired csid(%s)=%d CID rsrc successfully", + "acquired from old csid(%s)=%d CID rsrc successfully", (i == 0) ? "left" : "right", hw_intf->hw_idx); if (in_port->usage_type && acquired_cnt == 1 && - csid_path == CAM_IFE_PIX_PATH_RES_IPP) + path_res_id == CAM_IFE_PIX_PATH_RES_IPP) /* * Continue to acquire Right for IPP. * Dual IFE for RDI and PPP is not currently @@ -1074,28 +1316,53 @@ static int cam_ife_mgr_acquire_cid_res( } /* Acquire Left if not already acquired */ - for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { - if (!ife_hw_mgr->csid_devices[i]) - continue; + if (ife_ctx->is_fe_enable) { + for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { + if (!ife_hw_mgr->csid_devices[i]) + continue; - hw_intf = ife_hw_mgr->csid_devices[i]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire, - sizeof(csid_acquire)); - if (rc) - continue; - else { - cid_res_temp->hw_res[acquired_cnt++] = - csid_acquire.node_res; - break; + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } } - } + if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } + } else { + for (i = CAM_IFE_CSID_HW_NUM_MAX - 1; i >= 0; i--) { + if (!ife_hw_mgr->csid_devices[i]) + continue; - if (i == -1 || !csid_acquire.node_res) { - CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d", - csid_path); - goto put_res; + hw_intf = ife_hw_mgr->csid_devices[i]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) + continue; + else { + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + break; + } + } + if (i == -1 || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, + "Can not acquire ife cid resource for path %d", + path_res_id); + goto put_res; + } } + acquire_successful: CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", in_port->usage_type); @@ -1114,7 +1381,7 @@ acquire_successful: * Acquire Right if not already acquired. * Dual IFE for RDI and PPP is not currently supported. */ - if (cid_res_temp->is_dual_vfe && csid_path + if (cid_res_temp->is_dual_vfe && path_res_id == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { csid_acquire.node_res = NULL; csid_acquire.res_type = CAM_ISP_RESOURCE_CID; @@ -1147,6 +1414,8 @@ acquire_successful: cid_res_temp->parent = &ife_ctx->res_list_ife_in; ife_ctx->res_list_ife_in.child[ ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; + CAM_DBG(CAM_ISP, "IFE IN num_children = %d", + ife_ctx->res_list_ife_in.num_children); return 0; put_res: @@ -1205,6 +1474,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; } + CAM_DBG(CAM_ISP, "CSID Acq: E"); /* IPP resource needs to be from same HW as CID resource */ for (i = 0; i <= csid_res->is_dual_vfe; i++) { CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); @@ -1255,8 +1525,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl( 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); - + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); return 0; put_res: cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); @@ -1269,6 +1539,7 @@ static enum cam_ife_pix_path_res_id uint32_t out_port_type) { enum cam_ife_pix_path_res_id path_id; + CAM_DBG(CAM_ISP, "out_port_type %x", out_port_type); switch (out_port_type) { case CAM_ISP_IFE_OUT_RES_RDI_0: @@ -1289,7 +1560,7 @@ static enum cam_ife_pix_path_res_id break; } - CAM_DBG(CAM_ISP, "out_port %d path_id %d", out_port_type, path_id); + CAM_DBG(CAM_ISP, "out_port %x path_id %d", out_port_type, path_id); return path_id; } @@ -1307,20 +1578,20 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( struct cam_hw_intf *hw_intf; struct cam_isp_out_port_info *out_port; struct cam_csid_hw_reserve_resource_args csid_acquire; - enum cam_ife_pix_path_res_id path_type; + enum cam_ife_pix_path_res_id path_res_id; ife_hw_mgr = ife_ctx->hw_mgr; for (i = 0; i < in_port->num_out_res; i++) { out_port = &in_port->data[i]; - path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + path_res_id = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( out_port->res_type); - if (path_type == CAM_IFE_PIX_PATH_RES_MAX) + if (path_res_id == CAM_IFE_PIX_PATH_RES_MAX) continue; /* get cid resource */ rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, - path_type); + path_res_id); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); goto end; @@ -1335,8 +1606,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( } memset(&csid_acquire, 0, sizeof(csid_acquire)); - csid_acquire.res_id = path_type; - + csid_acquire.res_id = path_res_id; csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_acquire.cid = cid_res->hw_res[0]->res_id; csid_acquire.in_port = in_port; @@ -1368,11 +1638,11 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( 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; + CAM_DBG(CAM_ISP, "acquire res %d CID children = %d", + csid_acquire.res_id, cid_res->num_children); cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); } @@ -1395,7 +1665,8 @@ static int cam_ife_hw_mgr_acquire_res_root( 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) { + } else if ((ife_ctx->res_list_ife_in.res_id != + in_port->res_type) && (!ife_ctx->is_fe_enable)) { CAM_ERR(CAM_ISP, "No Free resource for this context"); goto err; } else { @@ -1407,35 +1678,85 @@ err: return rc; } -static int cam_ife_hw_mgr_preprocess_out_port( +static int cam_ife_mgr_check_and_update_fe( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_acquire_hw_info *acquire_hw_info) +{ + int i; + struct cam_isp_in_port_info *in_port = NULL; + uint32_t in_port_length = 0; + uint32_t total_in_port_length = 0; + + in_port = (struct cam_isp_in_port_info *) + ((uint8_t *)&acquire_hw_info->data + + acquire_hw_info->input_info_offset); + for (i = 0; i < acquire_hw_info->num_inputs; i++) { + in_port_length = sizeof(struct cam_isp_in_port_info) + + (in_port->num_out_res - 1) * + sizeof(struct cam_isp_out_port_info); + total_in_port_length += in_port_length; + + if (total_in_port_length > acquire_hw_info->input_info_size) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + return -EINVAL; + } + CAM_DBG(CAM_ISP, "in_port%d res_type %d", i, + in_port->res_type); + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_ctx->is_fe_enable = true; + break; + } + + in_port = (struct cam_isp_in_port_info *)((uint8_t *)in_port + + in_port_length); + } + CAM_DBG(CAM_ISP, "is_fe_enable %d", ife_ctx->is_fe_enable); + + return 0; +} + +static int cam_ife_hw_mgr_preprocess_port( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port, int *ipp_count, int *rdi_count, - int *ppp_count) + int *ppp_count, + int *ife_rd_count) { int ipp_num = 0; int rdi_num = 0; int ppp_num = 0; + int ife_rd_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 if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) - ppp_num++; - else - ipp_num++; + if (in_port->res_type == CAM_ISP_IFE_IN_RES_RD) { + ife_rd_num++; + } else { + for (i = 0; i < in_port->num_out_res; i++) { + out_port = &in_port->data[i]; + if (cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) + rdi_num++; + else if (out_port->res_type == CAM_ISP_IFE_OUT_RES_2PD) + ppp_num++; + else { + CAM_DBG(CAM_ISP, "out_res_type %d", + out_port->res_type); + ipp_num++; + } + } } *ipp_count = ipp_num; *rdi_count = rdi_num; *ppp_count = ppp_num; + *ife_rd_count = ife_rd_num; + + CAM_DBG(CAM_ISP, "rdi: %d ipp: %d ppp: %d ife_rd: %d", + rdi_num, ipp_num, ppp_num, ife_rd_num); return 0; } @@ -1450,6 +1771,7 @@ static int cam_ife_mgr_acquire_hw_for_ctx( int ipp_count = 0; int rdi_count = 0; int ppp_count = 0; + int ife_rd_count = 0; is_dual_vfe = in_port->usage_type; @@ -1460,11 +1782,11 @@ static int cam_ife_mgr_acquire_hw_for_ctx( goto err; } - cam_ife_hw_mgr_preprocess_out_port(ife_ctx, in_port, - &ipp_count, &rdi_count, &ppp_count); + cam_ife_hw_mgr_preprocess_port(ife_ctx, in_port, + &ipp_count, &rdi_count, &ppp_count, &ife_rd_count); - if (!ipp_count && !rdi_count && !ppp_count) { - CAM_ERR(CAM_ISP, "No PIX or RDI or PPP resource"); + if (!ipp_count && !rdi_count && !ppp_count && !ife_rd_count) { + CAM_ERR(CAM_ISP, "No PIX or RDI or PPP or IFE RD resource"); return -EINVAL; } @@ -1502,19 +1824,26 @@ static int cam_ife_mgr_acquire_hw_for_ctx( /* get ife src resource */ - rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port); + if (ife_rd_count) { + rc = cam_ife_hw_mgr_acquire_res_ife_rd_src(ife_ctx, in_port); + rc = cam_ife_hw_mgr_acquire_res_bus_rd(ife_ctx, in_port); + } else { + 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; } + CAM_DBG(CAM_ISP, "Acquiring IFE OUT resource..."); rc = cam_ife_hw_mgr_acquire_res_ife_out(ife_ctx, in_port); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE OUT resource Failed"); goto err; } - *num_pix_port += ipp_count + ppp_count; + *num_pix_port += ipp_count + ppp_count + ife_rd_count; *num_rdi_port += rdi_count; return 0; @@ -1538,8 +1867,8 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *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); + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu ctx_index=%d", + handle, userdata, status, cookie, ctx->ctx_index); } else { CAM_WARN(CAM_ISP, "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", @@ -1618,8 +1947,22 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) ((uint8_t *)&acquire_hw_info->data + acquire_hw_info->input_info_offset); + rc = cam_ife_mgr_check_and_update_fe(ife_ctx, acquire_hw_info); + if (rc) { + CAM_ERR(CAM_ISP, "buffer size is not enough"); + goto free_ctx; + } + /* acquire HW resources */ for (i = 0; i < acquire_hw_info->num_inputs; i++) { + + if (in_port->num_out_res > CAM_IFE_HW_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "too many output res %d", + in_port->num_out_res); + rc = -EINVAL; + goto free_res; + } + in_port_length = sizeof(struct cam_isp_in_port_info) + (in_port->num_out_res - 1) * sizeof(struct cam_isp_out_port_info); @@ -1630,6 +1973,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) rc = -EINVAL; goto free_res; } + CAM_DBG(CAM_ISP, "in_res_type %x", in_port->res_type); rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, &num_pix_port_per_in, &num_rdi_port_per_in); total_pix_port += num_pix_port_per_in; @@ -1745,6 +2089,8 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) if (isp_resource[i].resource_id != CAM_ISP_RES_ID_PORT) continue; + CAM_DBG(CAM_ISP, "acquire no = %d total = %d", i, + acquire_args->num_acq); CAM_DBG(CAM_ISP, "start copy from user handle %lld with len = %d", isp_resource[i].res_hdl, @@ -1882,7 +2228,8 @@ static int cam_isp_blob_bw_update( if (!hw_mgr_res->hw_res[i]) continue; - if (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + if ((hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) + || (hw_mgr_res->res_id == CAM_ISP_HW_VFE_IN_RD)) if (i == CAM_ISP_HW_SPLIT_LEFT) { if (camif_l_bw_updated) continue; @@ -2013,8 +2360,9 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, } } - CAM_DBG(CAM_ISP, "Enter ctx id:%d num_hw_upd_entries %d", - ctx->ctx_index, cfg->num_hw_update_entries); + CAM_DBG(CAM_ISP, + "Enter ctx id:%d num_hw_upd_entries %d request id: %llu", + ctx->ctx_index, cfg->num_hw_update_entries, cfg->request_id); if (cfg->num_hw_update_entries > 0) { cdm_cmd = ctx->cdm_cmd; @@ -2047,21 +2395,21 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, 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); + "config done completion timeout for req_id=%llu rc=%d ctx_index %d", + cfg->request_id, rc, ctx->ctx_index); if (rc == 0) rc = -ETIMEDOUT; } else { rc = 0; CAM_DBG(CAM_ISP, - "config done Success for req_id=%llu", - cfg->request_id); + "config done Success for req_id=%llu ctx_index %d", + cfg->request_id, ctx->ctx_index); } } } else { CAM_ERR(CAM_ISP, "No commands to config"); } - CAM_DBG(CAM_ISP, "Exit"); + CAM_DBG(CAM_ISP, "Exit: Config Done: %llu", cfg->request_id); return rc; } @@ -2134,6 +2482,11 @@ static int cam_ife_mgr_stop_hw_in_overflow(void *stop_hw_args) cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); } + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + /* IFE out resources */ for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); @@ -2236,11 +2589,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) CAM_DBG(CAM_ISP, "Halting CSIDs"); - 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) { @@ -2249,15 +2597,6 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) } } - CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); - - /* IFE mux in resources */ - list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { - cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); - } - - cam_tasklet_stop(ctx->common.tasklet_info); - /* * If Context does not have PIX resources and has only RDI resource * then take the first base index. @@ -2297,6 +2636,26 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) ctx->base[i].idx, csid_halt_type); } + CAM_DBG(CAM_ISP, "Going to stop IFE Out"); + + /* IFE out resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) + cam_ife_hw_mgr_stop_hw_res(&ctx->res_list_ife_out[i]); + + /* IFE bus rd resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + CAM_DBG(CAM_ISP, "Going to stop IFE Mux"); + + /* IFE mux in resources */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + cam_ife_hw_mgr_stop_hw_res(hw_mgr_res); + } + + cam_tasklet_stop(ctx->common.tasklet_info); + cam_ife_mgr_pause_hw(ctx); if (stop_isp->stop_only) @@ -2386,6 +2745,17 @@ static int cam_ife_mgr_restart_hw(void *start_hw_args) } CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); + + /* Start IFE BUS RD device */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + /* Start the IFE mux in devices */ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); @@ -2536,6 +2906,18 @@ start_only: } } + CAM_DBG(CAM_ISP, "START IFE BUS RD ... in ctx id:%d", + ctx->ctx_index); + /* Start the IFE mux in devices */ + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + rc = cam_ife_hw_mgr_start_hw_res(hw_mgr_res, ctx); + if (rc) { + CAM_ERR(CAM_ISP, "Can not start IFE BUS RD (%d)", + hw_mgr_res->res_id); + goto err; + } + } + CAM_DBG(CAM_ISP, "START IFE SRC ... in ctx id:%d", ctx->ctx_index); /* Start the IFE mux in devices */ @@ -2595,7 +2977,6 @@ safe_disable: deinit_hw: cam_ife_hw_mgr_deinit_hw(ctx); - ctx->init_done = false; tasklet_stop: cam_tasklet_stop(ctx->common.tasklet_info); @@ -2667,6 +3048,78 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, return rc; } +static int cam_isp_blob_fe_update( + uint32_t blob_type, + struct cam_isp_generic_blob_info *blob_info, + struct cam_fe_config *fe_config, + struct cam_hw_prepare_update_args *prepare) +{ + struct cam_ife_hw_mgr_ctx *ctx = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res; + struct cam_hw_intf *hw_intf; + int rc = -EINVAL; + uint32_t i; + struct cam_vfe_fe_update_args fe_upd_args; + + ctx = prepare->ctxt_to_hw_map; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, + &fe_upd_args, + sizeof( + struct cam_fe_config)); + if (rc) + CAM_ERR(CAM_ISP, "fs Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + if (hw_mgr_res->res_id != CAM_ISP_HW_VFE_IN_RD) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf && hw_intf->hw_ops.process_cmd) { + fe_upd_args.node_res = + hw_mgr_res->hw_res[i]; + + memcpy(&fe_upd_args.fe_config, fe_config, + sizeof(struct cam_fe_config)); + + rc = hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + &fe_upd_args, + sizeof( + struct cam_vfe_fe_update_args)); + if (rc) + CAM_ERR(CAM_ISP, "fe Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + return rc; +} + static int cam_isp_blob_ubwc_update( uint32_t blob_type, struct cam_isp_generic_blob_info *blob_info, @@ -3004,7 +3457,7 @@ static int cam_isp_blob_clock_update( camif_r_clk_updated = true; } } else if ((hw_mgr_res->res_id >= - CAM_ISP_HW_VFE_IN_RDI0) && (hw_mgr_res->res_id + CAM_ISP_HW_VFE_IN_RD) && (hw_mgr_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3)) for (j = 0; j < clock_config->num_rdi; j++) clk_rate = max(clock_config->rdi_hz[j], @@ -3043,6 +3496,53 @@ static int cam_isp_blob_clock_update( return rc; } +void fill_res_bitmap(uint32_t resource_type, unsigned long *res_bitmap) +{ + + switch (resource_type) { + case CAM_ISP_IFE_OUT_RES_FULL: + case CAM_ISP_IFE_OUT_RES_DS4: + case CAM_ISP_IFE_OUT_RES_DS16: + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + case CAM_ISP_IFE_OUT_RES_FD: + case CAM_ISP_IFE_OUT_RES_PDAF: + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + case CAM_ISP_IFE_OUT_RES_STATS_BF: + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + case CAM_ISP_IFE_OUT_RES_STATS_RS: + case CAM_ISP_IFE_OUT_RES_STATS_CS: + case CAM_ISP_IFE_OUT_RES_STATS_IHIST: + case CAM_ISP_IFE_OUT_RES_FULL_DISP: + case CAM_ISP_IFE_OUT_RES_DS4_DISP: + case CAM_ISP_IFE_OUT_RES_DS16_DISP: + case CAM_ISP_IFE_IN_RES_RD: + set_bit(CAM_IFE_REG_UPD_CMD_PIX_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_0: + set_bit(CAM_IFE_REG_UPD_CMD_RDI0_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_1: + set_bit(CAM_IFE_REG_UPD_CMD_RDI1_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_2: + set_bit(CAM_IFE_REG_UPD_CMD_RDI2_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_RDI_3: + set_bit(CAM_IFE_REG_UPD_CMD_RDI3_BIT, res_bitmap); + break; + case CAM_ISP_IFE_OUT_RES_2PD: + set_bit(CAM_IFE_REG_UPD_CMD_DUAL_PD_BIT, + res_bitmap); + break; + default: + CAM_ERR(CAM_ISP, "Invalid resource"); + break; + } +} + static int cam_isp_packet_generic_blob_handler(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data) { @@ -3051,8 +3551,8 @@ static int cam_isp_packet_generic_blob_handler(void *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); + CAM_ERR(CAM_ISP, "Invalid args data %pK size %d info %pK", + blob_data, blob_size, blob_info); return -EINVAL; } @@ -3069,10 +3569,32 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, return -EINVAL; } + CAM_DBG(CAM_ISP, "FS2: BLOB Type: %d", blob_type); 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; + struct cam_isp_resource_hfr_config *hfr_config; + + if (blob_size < sizeof(struct cam_isp_resource_hfr_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + hfr_config = (struct cam_isp_resource_hfr_config *)blob_data; + + if (hfr_config->num_ports > CAM_ISP_IFE_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in hfr config", + hfr_config->num_ports); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + hfr_config->num_ports * + sizeof(struct cam_isp_port_hfr_config))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(uint32_t) * 2 + + sizeof(struct cam_isp_port_hfr_config) * + hfr_config->num_ports); + return -EINVAL; + } rc = cam_isp_blob_hfr_update(blob_type, blob_info, hfr_config, prepare); @@ -3081,8 +3603,29 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_CLOCK_CONFIG: { - struct cam_isp_clock_config *clock_config = - (struct cam_isp_clock_config *)blob_data; + struct cam_isp_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + clock_config = (struct cam_isp_clock_config *)blob_data; + + if (clock_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in clock config", + clock_config->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + sizeof(uint64_t) * + (clock_config->num_rdi + 2)); + return -EINVAL; + } rc = cam_isp_blob_clock_update(blob_type, blob_info, clock_config, prepare); @@ -3091,10 +3634,31 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } 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_bw_config *bw_config; struct cam_isp_prepare_hw_update_data *prepare_hw_data; + if (blob_size < sizeof(struct cam_isp_bw_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u", blob_size); + return -EINVAL; + } + + bw_config = (struct cam_isp_bw_config *)blob_data; + + if (bw_config->num_rdi > CAM_IFE_RDI_NUM_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_rdi %u in bw config", + bw_config->num_rdi); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + (bw_config->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote))) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + (bw_config->num_rdi + 2) + * sizeof(struct cam_isp_bw_vote)); + return -EINVAL; + } + if (!prepare || !prepare->priv || (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { CAM_ERR(CAM_ISP, "Invalid inputs"); @@ -3112,8 +3676,29 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_UBWC_CONFIG: { - struct cam_ubwc_config *ubwc_config = - (struct cam_ubwc_config *)blob_data; + struct cam_ubwc_config *ubwc_config; + + if (blob_size < sizeof(struct cam_ubwc_config)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u", blob_size); + return -EINVAL; + } + + ubwc_config = (struct cam_ubwc_config *)blob_data; + + if (ubwc_config->num_ports > CAM_ISP_IFE_OUT_RES_MAX) { + CAM_ERR(CAM_ISP, "Invalid num_ports %u in ubwc config", + ubwc_config->num_ports); + return -EINVAL; + } + + if (blob_size < (sizeof(uint32_t) * 2 + ubwc_config->num_ports * + sizeof(struct cam_ubwc_plane_cfg_v1) * 2)) { + CAM_ERR(CAM_ISP, "Invalid blob_size %u expected %lu", + blob_size, + sizeof(uint32_t) * 2 + ubwc_config->num_ports * + sizeof(struct cam_ubwc_plane_cfg_v1) * 2); + return -EINVAL; + } rc = cam_isp_blob_ubwc_update(blob_type, blob_info, ubwc_config, prepare); @@ -3122,8 +3707,16 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, } break; case CAM_ISP_GENERIC_BLOB_TYPE_CSID_CLOCK_CONFIG: { - struct cam_isp_csid_clock_config *clock_config = - (struct cam_isp_csid_clock_config *)blob_data; + struct cam_isp_csid_clock_config *clock_config; + + if (blob_size < sizeof(struct cam_isp_csid_clock_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, + sizeof(struct cam_isp_csid_clock_config)); + return -EINVAL; + } + + clock_config = (struct cam_isp_csid_clock_config *)blob_data; rc = cam_isp_blob_csid_clock_update(blob_type, blob_info, clock_config, prepare); @@ -3131,6 +3724,24 @@ static int cam_isp_packet_generic_blob_handler(void *user_data, CAM_ERR(CAM_ISP, "Clock Update Failed"); } break; + case CAM_ISP_GENERIC_BLOB_TYPE_FE_CONFIG: { + struct cam_fe_config *fe_config; + + if (blob_size < sizeof(struct cam_fe_config)) { + CAM_ERR(CAM_ISP, "Invalid blob size %u expected %lu", + blob_size, sizeof(struct cam_fe_config)); + return -EINVAL; + } + + fe_config = (struct cam_fe_config *)blob_data; + + rc = cam_isp_blob_fe_update(blob_type, blob_info, + fe_config, prepare); + if (rc) + CAM_ERR(CAM_ISP, "FS Update Failed rc: %d", rc); + } + break; + default: CAM_WARN(CAM_ISP, "Invalid blob type %d", blob_type); break; @@ -3166,7 +3777,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_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); + rc = cam_packet_util_validate_packet(prepare->packet, + prepare->remain_len); if (rc) return rc; @@ -3227,7 +3839,10 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, 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); + &ctx->res_list_ife_in_rd, + CAM_IFE_HW_OUT_RES_MAX, fill_fence, + &ctx->res_bitmap, + fill_res_bitmap); if (rc) { CAM_ERR(CAM_ISP, @@ -3268,7 +3883,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, /*Add reg update */ rc = cam_isp_add_reg_update(prepare, &ctx->res_list_ife_src, - ctx->base[i].idx, &kmd_buf); + ctx->base[i].idx, &kmd_buf, ctx->is_fe_enable, + ctx->res_bitmap); if (rc) { CAM_ERR(CAM_ISP, "Add Reg_update cmd Failed i=%d, idx=%d, rc=%d", @@ -3276,6 +3892,7 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, goto end; } } + ctx->res_bitmap = 0; end: return rc; @@ -3356,7 +3973,8 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, if (!io_cfg[i].mem_handle[j]) break; - if (GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == + if (pf_buf_info && + GET_FD_FROM_HANDLE(io_cfg[i].mem_handle[j]) == GET_FD_FROM_HANDLE(pf_buf_info)) { CAM_INFO(CAM_ISP, "Found PF at port: 0x%x mem 0x%x fd: 0x%x", @@ -3391,9 +4009,10 @@ static void cam_ife_mgr_print_io_bufs(struct cam_packet *packet, } CAM_INFO(CAM_ISP, - "pln %d w %d h %d s 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", + "pln %d w %d h %d s %u size 0x%x addr 0x%x end_addr 0x%x offset %x memh %x", j, io_cfg[i].planes[j].width, io_cfg[i].planes[j].height, + io_cfg[i].planes[j].plane_stride, (unsigned int)src_buf_size, (unsigned int)iova_addr, (unsigned int)iova_addr + @@ -3434,12 +4053,6 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) hw_cmd_args->u.internal_args; switch (isp_hw_cmd_args->cmd_type) { - case CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT: - if (ctx->is_rdi_only_context) - isp_hw_cmd_args->u.is_rdi_only_context = 1; - else - isp_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; @@ -3450,6 +4063,14 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) cam_ife_mgr_sof_irq_debug(ctx, isp_hw_cmd_args->u.sof_irq_enable); break; + case CAM_ISP_HW_MGR_CMD_CTX_TYPE: + if (ctx->is_fe_enable) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_FS2; + else if (ctx->is_rdi_only_context) + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_RDI; + else + isp_hw_cmd_args->u.ctx_type = CAM_ISP_CTX_PIX; + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); @@ -3485,17 +4106,25 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( 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)) + if (!hw_mgr_res->hw_res[i]) continue; + /* * Get the SOF time stamp from left resource only. * Left resource is master for dual vfe case and * Rdi only context case left resource only hold * the RDI resource */ + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; if (hw_intf->hw_ops.process_cmd) { + /* + * Single VFE case, Get the time stamp from + * available one csid hw in the context + * Dual VFE case, get the time stamp from + * master(left) would be sufficient + */ + csid_get_time.node_res = hw_mgr_res->hw_res[i]; rc = hw_intf->hw_ops.process_cmd( @@ -3504,23 +4133,16 @@ static int cam_ife_mgr_cmd_get_sof_timestamp( &csid_get_time, sizeof( struct cam_csid_get_time_stamp_args)); - if (!rc) { + if (!rc && (i == CAM_ISP_HW_SPLIT_LEFT)) { *time_stamp = csid_get_time.time_stamp_val; *boot_time_stamp = csid_get_time.boot_timestamp; } - /* - * 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"); @@ -3790,6 +4412,8 @@ static int cam_ife_hw_mgr_get_err_type( core_idx = evt_payload->core_index; evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + evt_payload->enable_reg_dump = + g_ife_hw_mgr.debug_cfg.enable_reg_dump; list_for_each_entry(isp_ife_camif_res, &ife_hwr_mgr_ctx->res_list_ife_src, list) { @@ -3860,23 +4484,26 @@ static int cam_ife_hw_mgr_handle_camif_error( 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; + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) { + rc = error_status; + goto end; + } 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); - rc = -EFAULT; - + rc = error_status; if (g_ife_hw_mgr.debug_cfg.enable_recovery) error_event_data.recovery_enabled = true; error_event_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + error_event_data.enable_reg_dump = + g_ife_hw_mgr.debug_cfg.enable_reg_dump; + cam_ife_hw_mgr_find_affected_ctx(ife_hwr_mgr_ctx, &error_event_data, core_idx, @@ -3897,6 +4524,7 @@ static int cam_ife_hw_mgr_handle_camif_error( break; } +end: return rc; } @@ -3946,6 +4574,7 @@ static int cam_ife_hw_mgr_handle_reg_update( case CAM_ISP_HW_VFE_IN_CAMIF_LITE: break; case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_RD: if (ife_src_res->is_dual_vfe) /* It checks for slave core RUP ACK*/ hw_res = ife_src_res->hw_res[1]; @@ -3999,7 +4628,8 @@ static int cam_ife_hw_mgr_handle_reg_update( rup_status = hw_res->bottom_half_handler( hw_res, evt_payload); - if (!ife_hwr_mgr_ctx->is_rdi_only_context) + if (ife_hwr_mgr_ctx->is_rdi_only_context == 0 && + ife_hwr_mgr_ctx->is_fe_enable == false) continue; if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) @@ -4106,9 +4736,10 @@ static int cam_ife_hw_mgr_handle_epoch_for_camif_hw_res( 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)) + || (isp_ife_camif_res->res_id > + CAM_ISP_HW_VFE_IN_RD)) { continue; + } hw_res_l = isp_ife_camif_res->hw_res[0]; hw_res_r = isp_ife_camif_res->hw_res[1]; @@ -4341,7 +4972,8 @@ static int cam_ife_hw_mgr_handle_sof( hw_res, evt_payload); /* check if it is rdi only context */ - if (ife_hw_mgr_ctx->is_rdi_only_context) { + if (ife_hw_mgr_ctx->is_fe_enable || + ife_hw_mgr_ctx->is_rdi_only_context) { if (!sof_status && !sof_sent) { cam_ife_mgr_cmd_get_sof_timestamp( ife_hw_mgr_ctx, @@ -4352,7 +4984,7 @@ static int cam_ife_hw_mgr_handle_sof( ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_SOF, &sof_done_event_data); - CAM_DBG(CAM_ISP, "sof_status = %d", + CAM_DBG(CAM_ISP, "RDI sof_status = %d", sof_status); sof_sent = true; @@ -4362,6 +4994,7 @@ static int cam_ife_hw_mgr_handle_sof( break; case CAM_ISP_HW_VFE_IN_CAMIF: + case CAM_ISP_HW_VFE_IN_RD: sof_status = cam_ife_hw_mgr_process_camif_sof( ife_src_res, ife_hw_mgr_ctx, evt_payload); if (!sof_status && !sof_sent) { @@ -4832,6 +5465,14 @@ static int cam_ife_hw_mgr_debug_register(void) return -ENOMEM; } + if (!debugfs_create_u32("enable_reg_dump", + 0644, + g_ife_hw_mgr.debug_cfg.dentry, + &g_ife_hw_mgr.debug_cfg.enable_reg_dump)) { + CAM_ERR(CAM_ISP, "failed to create enable_reg_dump"); + goto err; + } + if (!debugfs_create_file("ife_csid_debug", 0644, g_ife_hw_mgr.debug_cfg.dentry, NULL, @@ -4975,6 +5616,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_cid); INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_csid); INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_src); + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i].res_list_ife_in_rd); ctx_pool = &g_ife_hw_mgr.ctx_pool[i]; for (j = 0; j < CAM_IFE_HW_OUT_RES_MAX; j++) { res_list_ife_out = &ctx_pool->res_list_ife_out[j]; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index cf1e425558f3..bf5f1527caa4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.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 @@ -26,6 +26,7 @@ enum cam_ife_hw_mgr_res_type { CAM_IFE_HW_MGR_RES_CID, CAM_IFE_HW_MGR_RES_CSID, CAM_IFE_HW_MGR_RES_IFE_SRC, + CAM_IFE_HW_MGR_RES_IFE_IN_RD, CAM_IFE_HW_MGR_RES_IFE_OUT, }; @@ -87,6 +88,7 @@ struct ctx_base_info { * @csid_debug: csid debug information * @enable_recovery: enable recovery * @enable_diag_sensor_status: enable sensor diagnosis status + * @enable_reg_dump: enable register dump on error * */ struct cam_ife_hw_mgr_debug { @@ -94,6 +96,7 @@ struct cam_ife_hw_mgr_debug { uint64_t csid_debug; uint32_t enable_recovery; uint32_t camif_debug; + uint32_t enable_reg_dump; }; /** @@ -108,6 +111,7 @@ struct cam_ife_hw_mgr_debug { * one. * @res_list_csid: CSID resource list * @res_list_ife_src: IFE input resource list + * @res_list_ife_in_rd IFE input resource list for read path * @res_list_ife_out: IFE output resoruces array * @free_res_list: Free resources list for the branch node * @res_pool: memory storage for the free resource list @@ -128,6 +132,8 @@ struct cam_ife_hw_mgr_debug { * @is_rdi_only_context flag to specify the context has only rdi resource * @config_done_complete indicator for configuration complete * @init_done indicate whether init hw is done + * @is_fe_enable indicate whether fetch engine\read path is enabled + * @res_bitmap fill resource bitmap for which rup to be set */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -141,6 +147,7 @@ struct cam_ife_hw_mgr_ctx { struct list_head res_list_ife_cid; struct list_head res_list_ife_csid; struct list_head res_list_ife_src; + struct list_head res_list_ife_in_rd; struct cam_ife_hw_mgr_res res_list_ife_out[ CAM_IFE_HW_OUT_RES_MAX]; @@ -162,6 +169,8 @@ struct cam_ife_hw_mgr_ctx { uint32_t is_rdi_only_context; struct completion config_done_complete; bool init_done; + bool is_fe_enable; + unsigned long res_bitmap; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index cd1d024148ff..0b3c3874a704 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -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 @@ -105,7 +105,7 @@ static int cam_isp_update_dual_config( 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; + size_t len = 0, remain_len = 0; uint32_t *cpu_addr; uint32_t i, j; @@ -117,9 +117,22 @@ static int cam_isp_update_dual_config( if (rc) return rc; + if ((len < sizeof(struct cam_isp_dual_config)) || + (cmd_desc->offset >= + (len - sizeof(struct cam_isp_dual_config)))) { + CAM_ERR(CAM_UTIL, "not enough buffer provided"); + return -EINVAL; + } + remain_len = len - cmd_desc->offset; cpu_addr += (cmd_desc->offset / 4); dual_config = (struct cam_isp_dual_config *)cpu_addr; + if ((dual_config->num_ports * + sizeof(struct cam_isp_dual_stripe_config)) > + (remain_len - offsetof(struct cam_isp_dual_config, stripes))) { + CAM_ERR(CAM_UTIL, "not enough buffer for all the dual configs"); + return -EINVAL; + } for (i = 0; i < dual_config->num_ports; i++) { if (i >= CAM_ISP_IFE_OUT_RES_MAX) { @@ -430,8 +443,11 @@ int cam_isp_add_io_buffers( uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info, struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, - bool fill_fence) + bool fill_fence, + unsigned long *res_bitmap, + cam_fill_res_bitmap fill_res_bitmap) { int rc = 0; uint64_t io_addr[CAM_PACKET_MAX_PLANES]; @@ -440,6 +456,7 @@ int cam_isp_add_io_buffers( struct cam_ife_hw_mgr_res *hw_mgr_res; struct cam_isp_hw_get_cmd_update update_buf; struct cam_isp_hw_get_wm_update wm_update; + struct cam_isp_hw_get_wm_update bus_rd_update; struct cam_hw_fence_map_entry *out_map_entries; struct cam_hw_fence_map_entry *in_map_entries; uint32_t kmd_buf_remain_size; @@ -517,6 +534,15 @@ int cam_isp_add_io_buffers( CAM_DBG(CAM_ISP, "configure input io with fill fence %d", fill_fence); + if (!list_empty(res_list_ife_in_rd)) { + hw_mgr_res = + list_first_entry(res_list_ife_in_rd, + struct cam_ife_hw_mgr_res, list); + } else { + CAM_ERR(CAM_ISP, + "No IFE in Read resource"); + return -EINVAL; + } in_map_entries = &prepare->in_map_entries[num_in_buf]; if (fill_fence) { @@ -533,7 +559,6 @@ int cam_isp_add_io_buffers( return -EINVAL; } } - continue; } else { CAM_ERR(CAM_ISP, "Invalid io config direction :%d", io_cfg[i].direction); @@ -541,7 +566,8 @@ int cam_isp_add_io_buffers( } CAM_DBG(CAM_ISP, "setup mem io"); - for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_OUTPUT; j++) { if (!hw_mgr_res->hw_res[j]) continue; @@ -656,6 +682,118 @@ int cam_isp_add_io_buffers( } io_cfg_used_bytes += update_buf.cmd.used_bytes; } + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX && + io_cfg[i].direction == CAM_BUF_INPUT; j++) { + if (!hw_mgr_res->hw_res[j]) + continue; + + if (hw_mgr_res->hw_res[j]->hw_intf->hw_idx != base_idx) + continue; + + res = hw_mgr_res->hw_res[j]; + + memset(io_addr, 0, sizeof(io_addr)); + + for (plane_id = 0; plane_id < CAM_PACKET_MAX_PLANES; + plane_id++) { + if (!io_cfg[i].mem_handle[plane_id]) + break; + + hdl = io_cfg[i].mem_handle[plane_id]; + if (res->process_cmd(res, + CAM_ISP_HW_CMD_GET_SECURE_MODE, + &mode, + sizeof(bool))) + return -EINVAL; + + is_buf_secure = cam_mem_is_secure_buf(hdl); + if ((mode == CAM_SECURE_MODE_SECURE) && + is_buf_secure) { + mmu_hdl = sec_iommu_hdl; + } else if ( + (mode == CAM_SECURE_MODE_NON_SECURE) && + (!is_buf_secure)) { + mmu_hdl = iommu_hdl; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Invalid hdl: port mode[%u], buf mode[%u]", + mode, is_buf_secure); + return -EINVAL; + } + + rc = cam_mem_get_io_buf( + io_cfg[i].mem_handle[plane_id], + mmu_hdl, &io_addr[plane_id], &size); + if (rc) { + CAM_ERR(CAM_ISP, + "no io addr for plane%d", + plane_id); + rc = -ENOMEM; + return rc; + } + + /* need to update with offset */ + io_addr[plane_id] += + io_cfg[i].offsets[plane_id]; + CAM_DBG(CAM_ISP, + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + + } + if (!plane_id) { + CAM_ERR(CAM_ISP, "No valid planes for res%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + + if ((kmd_buf_info->used_bytes + io_cfg_used_bytes) < + kmd_buf_info->size) { + kmd_buf_remain_size = kmd_buf_info->size - + (kmd_buf_info->used_bytes + + io_cfg_used_bytes); + } else { + CAM_ERR(CAM_ISP, + "no free kmd memory for base %d", + base_idx); + rc = -ENOMEM; + return rc; + } + update_buf.res = res; + update_buf.cmd_type = CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM; + update_buf.cmd.cmd_buf_addr = kmd_buf_info->cpu_addr + + kmd_buf_info->used_bytes/4 + + io_cfg_used_bytes/4; + bus_rd_update.image_buf = io_addr; + bus_rd_update.num_buf = plane_id; + bus_rd_update.io_cfg = &io_cfg[i]; + update_buf.cmd.size = kmd_buf_remain_size; + update_buf.rm_update = &bus_rd_update; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + update_buf.cmd.cmd_buf_addr, + update_buf.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( + res->hw_intf->hw_priv, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, &update_buf, + sizeof(struct cam_isp_hw_get_cmd_update)); + + if (rc) { + CAM_ERR(CAM_ISP, "get buf cmd error:%d", + res->res_id); + rc = -ENOMEM; + return rc; + } + io_cfg_used_bytes += update_buf.cmd.used_bytes; + } + + fill_res_bitmap(io_cfg[i].resource_type, res_bitmap); } CAM_DBG(CAM_ISP, "io_cfg_used_bytes %d, fill_fence %d", @@ -694,13 +832,16 @@ 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) + struct cam_kmd_buf_info *kmd_buf_info, + bool is_fe_en, + unsigned long res_bitmap) { 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; + struct cam_isp_hw_rup_data rup_data; uint32_t kmd_buf_remain_size, num_ent, i, reg_update_size; hw_entry = prepare->hw_update_entries; @@ -746,6 +887,9 @@ int cam_isp_add_reg_update( get_regup.cmd.size = kmd_buf_remain_size; get_regup.cmd_type = CAM_ISP_HW_CMD_GET_REG_UPDATE; get_regup.res = res; + rup_data.is_fe_enable = is_fe_en; + rup_data.res_bitmap = res_bitmap; + get_regup.rup_data = &rup_data; rc = res->hw_intf->hw_ops.process_cmd( res->hw_intf->hw_priv, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h index 9c1caa03e06c..806c2c657165 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.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 @@ -123,8 +123,11 @@ int cam_isp_add_command_buffers( * @base_idx: Base or dev index of the IFE/VFE HW instance * @kmd_buf_info: Kmd buffer to store the change base command * @res_list_isp_out: IFE /VFE out resource list + * @res_list_ife_in_rd: IFE /VFE in rd resource list * @size_isp_out: Size of the res_list_isp_out array * @fill_fence: If true, Fence map table will be filled + * @res_bitmap resource bitmap to be set for rup + * @fill_res_bitmap callback function to set resource bitmap * * @return: 0 for success * -EINVAL for Fail @@ -136,8 +139,11 @@ int cam_isp_add_io_buffers( uint32_t base_idx, struct cam_kmd_buf_info *kmd_buf_info, struct cam_ife_hw_mgr_res *res_list_isp_out, + struct list_head *res_list_ife_in_rd, uint32_t size_isp_out, - bool fill_fence); + bool fill_fence, + unsigned long *res_bitmap, + cam_fill_res_bitmap fill_res_bitmap); /* * cam_isp_add_reg_update() @@ -150,6 +156,9 @@ int cam_isp_add_io_buffers( * @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 + * @is_fe_enable If fetch engine enable + * @res_bitmap resource bitmap to be set for rup + * * @return: 0 for success * -EINVAL for Fail */ @@ -157,6 +166,8 @@ 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); + struct cam_kmd_buf_info *kmd_buf_info, + bool is_fe_enable, + unsigned long res_bitmap); #endif /*_CAM_ISP_HW_PARSER_H */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index e418fa97081d..c5808d45b0b1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -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 @@ -617,7 +617,7 @@ static void cam_irq_controller_th_processing( evt_handler->bottom_half, &bh_cmd); if (rc || !bh_cmd) { CAM_ERR_RATE_LIMIT(CAM_ISP, - "Can't get bh payload"); + "No payload, IRQ handling frozen"); continue; } } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 1a0f1ecab7b6..e9bcc98a8956 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -19,6 +19,16 @@ #include <uapi/media/cam_isp.h> #include "cam_hw_mgr_intf.h" +/* + * bit position in resource bitmap + */ +#define CAM_IFE_REG_UPD_CMD_PIX_BIT 0 +#define CAM_IFE_REG_UPD_CMD_RDI0_BIT 1 +#define CAM_IFE_REG_UPD_CMD_RDI1_BIT 2 +#define CAM_IFE_REG_UPD_CMD_RDI2_BIT 3 +#define CAM_IFE_REG_UPD_CMD_RDI3_BIT 4 +#define CAM_IFE_REG_UPD_CMD_DUAL_PD_BIT 5 + /* MAX IFE instance */ #define CAM_IFE_HW_NUM_MAX 4 #define CAM_IFE_RDI_NUM_MAX 4 @@ -186,11 +196,13 @@ struct cam_isp_hw_eof_event_data { * @timestamp: Timestamp for the error event * @recovery_enabled: Identifies if the context needs to recover & reapply * this request + * @enable_reg_dump: enable register dump */ struct cam_isp_hw_error_event_data { uint32_t error_type; uint64_t timestamp; bool recovery_enabled; + bool enable_reg_dump; }; /* enum cam_isp_hw_mgr_command - Hardware manager command type */ @@ -199,20 +211,28 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_PAUSE_HW, CAM_ISP_HW_MGR_CMD_RESUME_HW, CAM_ISP_HW_MGR_CMD_SOF_DEBUG, + CAM_ISP_HW_MGR_CMD_CTX_TYPE, CAM_ISP_HW_MGR_CMD_MAX, }; +enum cam_isp_ctx_type { + CAM_ISP_CTX_FS2 = 1, + CAM_ISP_CTX_RDI, + CAM_ISP_CTX_PIX, + CAM_ISP_CTX_MAX, +}; /** * struct cam_isp_hw_cmd_args - Payload for hw manager command * * @cmd_type HW command type - * @get_context Get context type information + * @sof_irq_enable To debug if SOF irq is enabled + * @ctx_type RDI_ONLY, PIX and RDI, or FS2 */ struct cam_isp_hw_cmd_args { - uint32_t cmd_type; + uint32_t cmd_type; union { - uint32_t is_rdi_only_context; uint32_t sof_irq_enable; + uint32_t ctx_type; } u; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c deleted file mode 100644 index 70223f1427f5..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c +++ /dev/null @@ -1,61 +0,0 @@ -/* 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 <linux/module.h> -#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, - .suppress_bind_attrs = true, - }, -}; - -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_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h index 85fec0f15dcd..576e8cb8d3b8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.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 @@ -222,6 +222,7 @@ static struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, }; static struct cam_ife_csid_csi2_tpg_reg_offset @@ -273,6 +274,7 @@ static struct cam_ife_csid_common_reg_offset .num_rdis = 3, .num_pix = 1, .num_ppp = 0, + .csid_reg_rst_stb = 1, .csid_rst_stb = 0x1e, .csid_rst_stb_sw_all = 0x1f, .path_rst_stb_all = 0x7f, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.h index 4fdc518c0385..42f0f290a166 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175.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 @@ -10,56 +10,93 @@ * GNU General Public License for more details. */ -#ifndef _CAM_IFE_CSID_LITE170_H_ -#define _CAM_IFE_CSID_LITE170_H_ +#ifndef _CAM_IFE_CSID_175_H_ +#define _CAM_IFE_CSID_175_H_ + #include "cam_ife_csid_core.h" -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_0_reg_offset = { +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, +}; + +static struct cam_ife_csid_pxl_reg_offset cam_ife_csid_175_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, - .csid_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, + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, }; -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_1_reg_offset = { +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_0_reg_offset = { .csid_rdi_irq_status_addr = 0x40, .csid_rdi_irq_mask_addr = 0x44, .csid_rdi_irq_clear_addr = 0x48, @@ -100,9 +137,7 @@ static struct cam_ife_csid_rdi_reg_offset .csid_rdi_byte_cntr_pong_addr = 0x3e4, }; -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_2_reg_offset = { - +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_1_reg_offset = { .csid_rdi_irq_status_addr = 0x50, .csid_rdi_irq_mask_addr = 0x54, .csid_rdi_irq_clear_addr = 0x58, @@ -120,7 +155,6 @@ static struct cam_ife_csid_rdi_reg_offset .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, @@ -144,9 +178,7 @@ static struct cam_ife_csid_rdi_reg_offset .csid_rdi_byte_cntr_pong_addr = 0x4e4, }; -static struct cam_ife_csid_rdi_reg_offset - cam_ife_csid_lite_170_rdi_3_reg_offset = { - +static struct cam_ife_csid_rdi_reg_offset cam_ife_csid_175_rdi_2_reg_offset = { .csid_rdi_irq_status_addr = 0x60, .csid_rdi_irq_mask_addr = 0x64, .csid_rdi_irq_clear_addr = 0x68, @@ -189,8 +221,7 @@ static struct cam_ife_csid_rdi_reg_offset }; static struct cam_ife_csid_csi2_rx_reg_offset - cam_ife_csid_lite_170_csi2_reg_offset = { - + cam_ife_csid_175_csi2_reg_offset = { .csid_csi2_rx_irq_status_addr = 0x20, .csid_csi2_rx_irq_mask_addr = 0x24, .csid_csi2_rx_irq_clear_addr = 0x28, @@ -232,12 +263,11 @@ static struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, }; - static struct cam_ife_csid_csi2_tpg_reg_offset - cam_ife_csid_lite_170_tpg_reg_offset = { - + cam_ife_csid_175_tpg_reg_offset = { /*CSID TPG control */ .csid_tpg_ctrl_addr = 0x600, .csid_tpg_vc_cfg0_addr = 0x604, @@ -257,16 +287,14 @@ static struct cam_ife_csid_csi2_tpg_reg_offset .csid_tpg_cgen_n_y1_addr = 0x664, .csid_tpg_cgen_n_y2_addr = 0x668, - /*configurations */ + /* 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 = { - + cam_ife_csid_175_cmn_reg_offset = { .csid_hw_version_addr = 0x0, .csid_cfg0_addr = 0x4, .csid_ctrl_addr = 0x8, @@ -284,8 +312,10 @@ static struct cam_ife_csid_common_reg_offset .major_version = 1, .minor_version = 7, .version_incr = 0, - .no_rdis = 4, - .no_pix = 0, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, .csid_rst_stb = 0x1e, .csid_rst_stb_sw_all = 0x1f, .path_rst_stb_all = 0x7f, @@ -301,19 +331,23 @@ static struct cam_ife_csid_common_reg_offset .crop_shift = 16, .ipp_irq_mask_all = 0x7FFF, .rdi_irq_mask_all = 0x7FFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, }; -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, +static struct cam_ife_csid_reg_offset cam_ife_csid_175_reg_offset = { + .cmn_reg = &cam_ife_csid_175_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_ppp_reg_offset, .rdi_reg = { - &cam_ife_csid_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, + &cam_ife_csid_175_rdi_0_reg_offset, + &cam_ife_csid_175_rdi_1_reg_offset, + &cam_ife_csid_175_rdi_2_reg_offset, + NULL, }, - .tpg_reg = &cam_ife_csid_lite_170_tpg_reg_offset, + .tpg_reg = &cam_ife_csid_175_tpg_reg_offset, }; -#endif /*_CAM_IFE_CSID_LITE170_H_ */ +#endif /*_CAM_IFE_CSID_175_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h new file mode 100644 index 000000000000..8a78fe0b9b0d --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid175_200.h @@ -0,0 +1,369 @@ +/* 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. + */ + +#ifndef _CAM_IFE_CSID_175_200_H_ +#define _CAM_IFE_CSID_175_200_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ipp_reg_offset = { + .csid_pxl_irq_status_addr = 0x30, + .csid_pxl_irq_mask_addr = 0x34, + .csid_pxl_irq_clear_addr = 0x38, + .csid_pxl_irq_set_addr = 0x3c, + + .csid_pxl_cfg0_addr = 0x200, + .csid_pxl_cfg1_addr = 0x204, + .csid_pxl_ctrl_addr = 0x208, + .csid_pxl_frm_drop_pattern_addr = 0x20c, + .csid_pxl_frm_drop_period_addr = 0x210, + .csid_pxl_irq_subsample_pattern_addr = 0x214, + .csid_pxl_irq_subsample_period_addr = 0x218, + .csid_pxl_hcrop_addr = 0x21c, + .csid_pxl_vcrop_addr = 0x220, + .csid_pxl_pix_drop_pattern_addr = 0x224, + .csid_pxl_pix_drop_period_addr = 0x228, + .csid_pxl_line_drop_pattern_addr = 0x22c, + .csid_pxl_line_drop_period_addr = 0x230, + .csid_pxl_rst_strobes_addr = 0x240, + .csid_pxl_status_addr = 0x254, + .csid_pxl_misr_val_addr = 0x258, + .csid_pxl_format_measure_cfg0_addr = 0x270, + .csid_pxl_format_measure_cfg1_addr = 0x274, + .csid_pxl_format_measure0_addr = 0x278, + .csid_pxl_format_measure1_addr = 0x27c, + .csid_pxl_format_measure2_addr = 0x280, + .csid_pxl_timestamp_curr0_sof_addr = 0x290, + .csid_pxl_timestamp_curr1_sof_addr = 0x294, + .csid_pxl_timestamp_perv0_sof_addr = 0x298, + .csid_pxl_timestamp_perv1_sof_addr = 0x29c, + .csid_pxl_timestamp_curr0_eof_addr = 0x2a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x2a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x2a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_pxl_reg_offset + cam_ife_csid_175_200_ppp_reg_offset = { + .csid_pxl_irq_status_addr = 0xa0, + .csid_pxl_irq_mask_addr = 0xa4, + .csid_pxl_irq_clear_addr = 0xa8, + .csid_pxl_irq_set_addr = 0xac, + + .csid_pxl_cfg0_addr = 0x700, + .csid_pxl_cfg1_addr = 0x704, + .csid_pxl_ctrl_addr = 0x708, + .csid_pxl_frm_drop_pattern_addr = 0x70c, + .csid_pxl_frm_drop_period_addr = 0x710, + .csid_pxl_irq_subsample_pattern_addr = 0x714, + .csid_pxl_irq_subsample_period_addr = 0x718, + .csid_pxl_hcrop_addr = 0x71c, + .csid_pxl_vcrop_addr = 0x720, + .csid_pxl_pix_drop_pattern_addr = 0x724, + .csid_pxl_pix_drop_period_addr = 0x728, + .csid_pxl_line_drop_pattern_addr = 0x72c, + .csid_pxl_line_drop_period_addr = 0x730, + .csid_pxl_rst_strobes_addr = 0x740, + .csid_pxl_status_addr = 0x754, + .csid_pxl_misr_val_addr = 0x758, + .csid_pxl_format_measure_cfg0_addr = 0x770, + .csid_pxl_format_measure_cfg1_addr = 0x774, + .csid_pxl_format_measure0_addr = 0x778, + .csid_pxl_format_measure1_addr = 0x77c, + .csid_pxl_format_measure2_addr = 0x780, + .csid_pxl_timestamp_curr0_sof_addr = 0x790, + .csid_pxl_timestamp_curr1_sof_addr = 0x794, + .csid_pxl_timestamp_perv0_sof_addr = 0x798, + .csid_pxl_timestamp_perv1_sof_addr = 0x79c, + .csid_pxl_timestamp_curr0_eof_addr = 0x7a0, + .csid_pxl_timestamp_curr1_eof_addr = 0x7a4, + .csid_pxl_timestamp_perv0_eof_addr = 0x7a8, + .csid_pxl_timestamp_perv1_eof_addr = 0x7ac, + /* configurations */ + .pix_store_en_shift_val = 7, + .early_eof_en_shift_val = 29, + .ccif_violation_en = 1, +}; + + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_0_reg_offset = { + .csid_rdi_irq_status_addr = 0x40, + .csid_rdi_irq_mask_addr = 0x44, + .csid_rdi_irq_clear_addr = 0x48, + .csid_rdi_irq_set_addr = 0x4c, + .csid_rdi_cfg0_addr = 0x300, + .csid_rdi_cfg1_addr = 0x304, + .csid_rdi_ctrl_addr = 0x308, + .csid_rdi_frm_drop_pattern_addr = 0x30c, + .csid_rdi_frm_drop_period_addr = 0x310, + .csid_rdi_irq_subsample_pattern_addr = 0x314, + .csid_rdi_irq_subsample_period_addr = 0x318, + .csid_rdi_rpp_hcrop_addr = 0x31c, + .csid_rdi_rpp_vcrop_addr = 0x320, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x324, + .csid_rdi_rpp_pix_drop_period_addr = 0x328, + .csid_rdi_rpp_line_drop_pattern_addr = 0x32c, + .csid_rdi_rpp_line_drop_period_addr = 0x330, + .csid_rdi_rst_strobes_addr = 0x340, + .csid_rdi_status_addr = 0x350, + .csid_rdi_misr_val0_addr = 0x354, + .csid_rdi_misr_val1_addr = 0x358, + .csid_rdi_misr_val2_addr = 0x35c, + .csid_rdi_misr_val3_addr = 0x360, + .csid_rdi_format_measure_cfg0_addr = 0x370, + .csid_rdi_format_measure_cfg1_addr = 0x374, + .csid_rdi_format_measure0_addr = 0x378, + .csid_rdi_format_measure1_addr = 0x37c, + .csid_rdi_format_measure2_addr = 0x380, + .csid_rdi_timestamp_curr0_sof_addr = 0x390, + .csid_rdi_timestamp_curr1_sof_addr = 0x394, + .csid_rdi_timestamp_prev0_sof_addr = 0x398, + .csid_rdi_timestamp_prev1_sof_addr = 0x39c, + .csid_rdi_timestamp_curr0_eof_addr = 0x3a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x3a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x3a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x3ac, + .csid_rdi_byte_cntr_ping_addr = 0x3e0, + .csid_rdi_byte_cntr_pong_addr = 0x3e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_1_reg_offset = { + .csid_rdi_irq_status_addr = 0x50, + .csid_rdi_irq_mask_addr = 0x54, + .csid_rdi_irq_clear_addr = 0x58, + .csid_rdi_irq_set_addr = 0x5c, + .csid_rdi_cfg0_addr = 0x400, + .csid_rdi_cfg1_addr = 0x404, + .csid_rdi_ctrl_addr = 0x408, + .csid_rdi_frm_drop_pattern_addr = 0x40c, + .csid_rdi_frm_drop_period_addr = 0x410, + .csid_rdi_irq_subsample_pattern_addr = 0x414, + .csid_rdi_irq_subsample_period_addr = 0x418, + .csid_rdi_rpp_hcrop_addr = 0x41c, + .csid_rdi_rpp_vcrop_addr = 0x420, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x424, + .csid_rdi_rpp_pix_drop_period_addr = 0x428, + .csid_rdi_rpp_line_drop_pattern_addr = 0x42c, + .csid_rdi_rpp_line_drop_period_addr = 0x430, + .csid_rdi_rst_strobes_addr = 0x440, + .csid_rdi_status_addr = 0x450, + .csid_rdi_misr_val0_addr = 0x454, + .csid_rdi_misr_val1_addr = 0x458, + .csid_rdi_misr_val2_addr = 0x45c, + .csid_rdi_misr_val3_addr = 0x460, + .csid_rdi_format_measure_cfg0_addr = 0x470, + .csid_rdi_format_measure_cfg1_addr = 0x474, + .csid_rdi_format_measure0_addr = 0x478, + .csid_rdi_format_measure1_addr = 0x47c, + .csid_rdi_format_measure2_addr = 0x480, + .csid_rdi_timestamp_curr0_sof_addr = 0x490, + .csid_rdi_timestamp_curr1_sof_addr = 0x494, + .csid_rdi_timestamp_prev0_sof_addr = 0x498, + .csid_rdi_timestamp_prev1_sof_addr = 0x49c, + .csid_rdi_timestamp_curr0_eof_addr = 0x4a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x4a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x4a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x4ac, + .csid_rdi_byte_cntr_ping_addr = 0x4e0, + .csid_rdi_byte_cntr_pong_addr = 0x4e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_175_200_rdi_2_reg_offset = { + .csid_rdi_irq_status_addr = 0x60, + .csid_rdi_irq_mask_addr = 0x64, + .csid_rdi_irq_clear_addr = 0x68, + .csid_rdi_irq_set_addr = 0x6c, + .csid_rdi_cfg0_addr = 0x500, + .csid_rdi_cfg1_addr = 0x504, + .csid_rdi_ctrl_addr = 0x508, + .csid_rdi_frm_drop_pattern_addr = 0x50c, + .csid_rdi_frm_drop_period_addr = 0x510, + .csid_rdi_irq_subsample_pattern_addr = 0x514, + .csid_rdi_irq_subsample_period_addr = 0x518, + .csid_rdi_rpp_hcrop_addr = 0x51c, + .csid_rdi_rpp_vcrop_addr = 0x520, + .csid_rdi_rpp_pix_drop_pattern_addr = 0x524, + .csid_rdi_rpp_pix_drop_period_addr = 0x528, + .csid_rdi_rpp_line_drop_pattern_addr = 0x52c, + .csid_rdi_rpp_line_drop_period_addr = 0x530, + .csid_rdi_yuv_chroma_conversion_addr = 0x534, + .csid_rdi_rst_strobes_addr = 0x540, + .csid_rdi_status_addr = 0x550, + .csid_rdi_misr_val0_addr = 0x554, + .csid_rdi_misr_val1_addr = 0x558, + .csid_rdi_misr_val2_addr = 0x55c, + .csid_rdi_misr_val3_addr = 0x560, + .csid_rdi_format_measure_cfg0_addr = 0x570, + .csid_rdi_format_measure_cfg1_addr = 0x574, + .csid_rdi_format_measure0_addr = 0x578, + .csid_rdi_format_measure1_addr = 0x57c, + .csid_rdi_format_measure2_addr = 0x580, + .csid_rdi_timestamp_curr0_sof_addr = 0x590, + .csid_rdi_timestamp_curr1_sof_addr = 0x594, + .csid_rdi_timestamp_prev0_sof_addr = 0x598, + .csid_rdi_timestamp_prev1_sof_addr = 0x59c, + .csid_rdi_timestamp_curr0_eof_addr = 0x5a0, + .csid_rdi_timestamp_curr1_eof_addr = 0x5a4, + .csid_rdi_timestamp_prev0_eof_addr = 0x5a8, + .csid_rdi_timestamp_prev1_eof_addr = 0x5ac, + .csid_rdi_byte_cntr_ping_addr = 0x5e0, + .csid_rdi_byte_cntr_pong_addr = 0x5e4, + .ccif_violation_en = 1, +}; + +static struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_175_200_csi2_reg_offset = { + .csid_csi2_rx_irq_status_addr = 0x20, + .csid_csi2_rx_irq_mask_addr = 0x24, + .csid_csi2_rx_irq_clear_addr = 0x28, + .csid_csi2_rx_irq_set_addr = 0x2c, + + /*CSI2 rx control */ + .csid_csi2_rx_cfg0_addr = 0x100, + .csid_csi2_rx_cfg1_addr = 0x104, + .csid_csi2_rx_capture_ctrl_addr = 0x108, + .csid_csi2_rx_rst_strobes_addr = 0x110, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_0_addr = 0x120, + .csid_csi2_rx_cap_unmap_long_pkt_hdr_1_addr = 0x124, + .csid_csi2_rx_captured_short_pkt_0_addr = 0x128, + .csid_csi2_rx_captured_short_pkt_1_addr = 0x12c, + .csid_csi2_rx_captured_long_pkt_0_addr = 0x130, + .csid_csi2_rx_captured_long_pkt_1_addr = 0x134, + .csid_csi2_rx_captured_long_pkt_ftr_addr = 0x138, + .csid_csi2_rx_captured_cphy_pkt_hdr_addr = 0x13c, + .csid_csi2_rx_lane0_misr_addr = 0x150, + .csid_csi2_rx_lane1_misr_addr = 0x154, + .csid_csi2_rx_lane2_misr_addr = 0x158, + .csid_csi2_rx_lane3_misr_addr = 0x15c, + .csid_csi2_rx_total_pkts_rcvd_addr = 0x160, + .csid_csi2_rx_stats_ecc_addr = 0x164, + .csid_csi2_rx_total_crc_err_addr = 0x168, + .csid_csi2_rx_de_scramble_type3_cfg0_addr = 0x170, + .csid_csi2_rx_de_scramble_type3_cfg1_addr = 0x174, + .csid_csi2_rx_de_scramble_type2_cfg0_addr = 0x178, + .csid_csi2_rx_de_scramble_type2_cfg1_addr = 0x17c, + .csid_csi2_rx_de_scramble_type1_cfg0_addr = 0x180, + .csid_csi2_rx_de_scramble_type1_cfg1_addr = 0x184, + .csid_csi2_rx_de_scramble_type0_cfg0_addr = 0x188, + .csid_csi2_rx_de_scramble_type0_cfg1_addr = 0x18c, + + .csi2_rst_srb_all = 0x3FFF, + .csi2_rst_done_shift_val = 27, + .csi2_irq_mask_all = 0xFFFFFFF, + .csi2_misr_enable_shift_val = 6, + .csi2_vc_mode_shift_val = 2, + .csi2_capture_long_pkt_en_shift = 0, + .csi2_capture_short_pkt_en_shift = 1, + .csi2_capture_cphy_pkt_en_shift = 2, + .csi2_capture_long_pkt_dt_shift = 4, + .csi2_capture_long_pkt_vc_shift = 10, + .csi2_capture_short_pkt_vc_shift = 15, + .csi2_capture_cphy_pkt_dt_shift = 20, + .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x7, +}; + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_175_200_tpg_reg_offset = { + /*CSID TPG control */ + .csid_tpg_ctrl_addr = 0x600, + .csid_tpg_vc_cfg0_addr = 0x604, + .csid_tpg_vc_cfg1_addr = 0x608, + .csid_tpg_lfsr_seed_addr = 0x60c, + .csid_tpg_dt_n_cfg_0_addr = 0x610, + .csid_tpg_dt_n_cfg_1_addr = 0x614, + .csid_tpg_dt_n_cfg_2_addr = 0x618, + .csid_tpg_color_bars_cfg_addr = 0x640, + .csid_tpg_color_box_cfg_addr = 0x644, + .csid_tpg_common_gen_cfg_addr = 0x648, + .csid_tpg_cgen_n_cfg_addr = 0x650, + .csid_tpg_cgen_n_x0_addr = 0x654, + .csid_tpg_cgen_n_x1_addr = 0x658, + .csid_tpg_cgen_n_x2_addr = 0x65c, + .csid_tpg_cgen_n_xy_addr = 0x660, + .csid_tpg_cgen_n_y1_addr = 0x664, + .csid_tpg_cgen_n_y2_addr = 0x668, + + /* configurations */ + .tpg_dtn_cfg_offset = 0xc, + .tpg_cgen_cfg_offset = 0x20, + .tpg_cpas_ife_reg_offset = 0x28, +}; + +static struct cam_ife_csid_common_reg_offset + cam_ife_csid_175_200_cmn_reg_offset = { + .csid_hw_version_addr = 0x0, + .csid_cfg0_addr = 0x4, + .csid_ctrl_addr = 0x8, + .csid_reset_addr = 0xc, + .csid_rst_strobes_addr = 0x10, + + .csid_test_bus_ctrl_addr = 0x14, + .csid_top_irq_status_addr = 0x70, + .csid_top_irq_mask_addr = 0x74, + .csid_top_irq_clear_addr = 0x78, + .csid_top_irq_set_addr = 0x7c, + .csid_irq_cmd_addr = 0x80, + + /*configurations */ + .major_version = 1, + .minor_version = 7, + .version_incr = 5, + .num_rdis = 3, + .num_pix = 1, + .num_ppp = 1, + .csid_reg_rst_stb = 1, + .csid_rst_stb = 0x1e, + .csid_rst_stb_sw_all = 0x1f, + .path_rst_stb_all = 0x7f, + .path_rst_done_shift_val = 1, + .path_en_shift_val = 31, + .dt_id_shift_val = 27, + .vc_shift_val = 22, + .dt_shift_val = 16, + .fmt_shift_val = 12, + .plain_fmt_shit_val = 10, + .crop_v_en_shift_val = 6, + .crop_h_en_shift_val = 5, + .crop_shift = 16, + .ipp_irq_mask_all = 0xFFFF, + .rdi_irq_mask_all = 0xFFFF, + .ppp_irq_mask_all = 0xFFFF, + .measure_en_hbi_vbi_cnt_mask = 0xC, + .format_measure_en_val = 1, +}; + +static struct cam_ife_csid_reg_offset cam_ife_csid_175_200_reg_offset = { + .cmn_reg = &cam_ife_csid_175_200_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_175_200_csi2_reg_offset, + .ipp_reg = &cam_ife_csid_175_200_ipp_reg_offset, + .ppp_reg = &cam_ife_csid_175_200_ppp_reg_offset, + .rdi_reg = { + &cam_ife_csid_175_200_rdi_0_reg_offset, + &cam_ife_csid_175_200_rdi_1_reg_offset, + &cam_ife_csid_175_200_rdi_2_reg_offset, + NULL, + }, + .tpg_reg = &cam_ife_csid_175_200_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_175_200_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c index f894daa846b9..80701bf6f8d0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid17x.c @@ -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 @@ -14,21 +14,42 @@ #include <linux/module.h> #include "cam_ife_csid_core.h" #include "cam_ife_csid170.h" +#include "cam_ife_csid175.h" +#include "cam_ife_csid175_200.h" #include "cam_ife_csid_dev.h" #define CAM_CSID_DRV_NAME "csid_17x" #define CAM_CSID_VERSION_V170 0x10070000 +#define CAM_CSID_VERSION_V175 0x10070050 static struct cam_ife_csid_hw_info cam_ife_csid170_hw_info = { .csid_reg = &cam_ife_csid_170_reg_offset, .hw_dts_version = CAM_CSID_VERSION_V170, }; +static struct cam_ife_csid_hw_info cam_ife_csid175_hw_info = { + .csid_reg = &cam_ife_csid_175_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + +static struct cam_ife_csid_hw_info cam_ife_csid175_200_hw_info = { + .csid_reg = &cam_ife_csid_175_200_reg_offset, + .hw_dts_version = CAM_CSID_VERSION_V175, +}; + static const struct of_device_id cam_ife_csid17x_dt_match[] = { { .compatible = "qcom,csid170", .data = &cam_ife_csid170_hw_info, }, + { + .compatible = "qcom,csid175", + .data = &cam_ife_csid175_hw_info, + }, + { + .compatible = "qcom,csid175_200", + .data = &cam_ife_csid175_200_hw_info, + }, {} }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index f3a15558bb1b..2d6e23cb7961 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* 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 @@ -67,6 +67,7 @@ static int cam_ife_csid_is_ipp_ppp_format_supported( case CAM_FORMAT_DPCM_12_8_12: case CAM_FORMAT_DPCM_14_8_14: case CAM_FORMAT_DPCM_14_10_14: + case CAM_FORMAT_DPCM_12_10_12: rc = 0; break; default: @@ -206,6 +207,10 @@ static int cam_ife_csid_get_format_rdi( *decode_fmt = 0xC; *plain_fmt = 0x1; break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; default: rc = -EINVAL; break; @@ -280,6 +285,10 @@ static int cam_ife_csid_get_format_ipp_ppp( *decode_fmt = 0xC; *plain_fmt = 0x1; break; + case CAM_FORMAT_DPCM_12_10_12: + *decode_fmt = 0xD; + *plain_fmt = 0x1; + break; default: CAM_ERR(CAM_ISP, "Unsupported format %d", in_format); @@ -309,6 +318,9 @@ static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, if (cid_data->vc == vc && cid_data->dt == dt) { cid_data->cnt++; *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); return 0; } } @@ -418,8 +430,23 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) 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 and SW registers reset */ - cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb_sw_all, + /* perform the top CSID HW registers 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); + + 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, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + } + + /* perform the SW registers reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_reg_rst_stb, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); @@ -433,6 +460,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) rc = -ETIMEDOUT; } + usleep_range(3000, 3010); 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) @@ -647,12 +675,12 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); goto end; } - CAM_DBG(CAM_ISP, "HW version: %d", camera_hw_version); + CAM_DBG(CAM_ISP, "HW version: %x", camera_hw_version); switch (camera_hw_version) { case CAM_CPAS_TITAN_NONE: case CAM_CPAS_TITAN_MAX: - CAM_ERR(CAM_ISP, "Invalid HW version: %d", camera_hw_version); + CAM_ERR(CAM_ISP, "Invalid HW version: %x", camera_hw_version); break; case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: @@ -1031,7 +1059,7 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d init CSID HW", csid_hw->hw_intf->hw_idx); - clk_lvl = cam_ife_csid_get_vote_level(soc_info, csid_hw->clk_rate); + clk_lvl = cam_soc_util_get_vote_level(soc_info, csid_hw->clk_rate); CAM_DBG(CAM_ISP, "CSID clock lvl %u", clk_lvl); rc = cam_ife_csid_enable_soc_resources(soc_info, clk_lvl); @@ -1093,6 +1121,7 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) int rc = -EINVAL; struct cam_hw_soc_info *soc_info; const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; /* Check for refcount */ if (!csid_hw->hw_info->open_count) { @@ -1127,6 +1156,9 @@ static int cam_ife_csid_disable_hw(struct cam_ife_csid_hw *csid_hw) CAM_ERR(CAM_ISP, "CSID:%d Disable CSID SOC failed", csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 0; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; csid_hw->error_irq_count = 0; @@ -1327,10 +1359,12 @@ static int cam_ife_csid_enable_csi2( return rc; /* rx cfg0 */ + val = 0; val = (csid_hw->csi2_rx_cfg.lane_num - 1) | (csid_hw->csi2_rx_cfg.lane_cfg << 4) | (csid_hw->csi2_rx_cfg.lane_type << 24); - val |= (csid_hw->csi2_rx_cfg.phy_sel & 0x3) << 20; + val |= (csid_hw->csi2_rx_cfg.phy_sel & + csid_reg->csi2_reg->csi2_rx_phy_num_mask) << 20; cam_io_w_mb(val, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_cfg0_addr); @@ -1753,6 +1787,9 @@ static int cam_ife_csid_enable_pxl_path( /* Enable the required pxl path interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + if (pxl_reg->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + if (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) @@ -1775,6 +1812,7 @@ static int cam_ife_csid_disable_pxl_path( enum cam_ife_csid_halt_cmd stop_cmd) { int rc = 0; + uint32_t val = 0; const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; struct cam_ife_csid_path_cfg *path_data; @@ -1835,6 +1873,17 @@ static int cam_ife_csid_disable_pxl_path( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + pxl_reg->csid_pxl_irq_mask_addr); + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER || + path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { + /* configure Halt */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + pxl_reg->csid_pxl_ctrl_addr); + } + return rc; } @@ -2063,6 +2112,9 @@ static int cam_ife_csid_enable_rdi_path( /* Enable the required RDI interrupts */ val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + if (csid_reg->rdi_reg[id]->ccif_violation_en) + val |= CSID_PATH_ERROR_CCIF_VIOLATION; + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_SOF_IRQ) val |= CSID_PATH_INFO_INPUT_SOF; if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ) @@ -2083,7 +2135,7 @@ static int cam_ife_csid_disable_rdi_path( enum cam_ife_csid_halt_cmd stop_cmd) { int rc = 0; - uint32_t id; + uint32_t id, val = 0; const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; @@ -2128,6 +2180,62 @@ static int cam_ife_csid_disable_rdi_path( cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[id]->csid_rdi_irq_mask_addr); + /* Halt the RDI path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + val &= ~0x3; + val |= stop_cmd; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_ctrl_addr); + + return rc; +} + +static int cam_ife_csid_poll_stop_status( + struct cam_ife_csid_hw *csid_hw, + uint32_t res_mask) +{ + int rc = 0; + uint32_t csid_status_addr = 0, val = 0, res_id = 0; + const struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + for (; res_id < CAM_IFE_PIX_PATH_RES_MAX; res_id++, res_mask >>= 1) { + if ((res_mask & 0x1) == 0) + continue; + val = 0; + + if (res_id == CAM_IFE_PIX_PATH_RES_IPP) { + csid_status_addr = + csid_reg->ipp_reg->csid_pxl_status_addr; + } else if (res_id == CAM_IFE_PIX_PATH_RES_PPP) { + csid_status_addr = + csid_reg->ppp_reg->csid_pxl_status_addr; + } else { + csid_status_addr = + csid_reg->rdi_reg[res_id]->csid_rdi_status_addr; + } + + CAM_DBG(CAM_ISP, "start polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_status_addr, val, (val & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, + CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d res:%d halt failed rc %d", + csid_hw->hw_intf->hw_idx, res_id, rc); + rc = -ETIMEDOUT; + break; + } + CAM_DBG(CAM_ISP, "End polling CSID:%d res_id:%d", + csid_hw->hw_intf->hw_idx, res_id); + } + return rc; } @@ -2176,10 +2284,10 @@ static int cam_ife_csid_get_hbi_vbi( rdi_reg->csid_rdi_format_measure2_addr); } - CAM_INFO_RATE_LIMIT(CAM_ISP, "Resource %u HBI: 0x%x", res->res_id, - hbi); - CAM_INFO_RATE_LIMIT(CAM_ISP, "Resource %u VBI: 0x%x", res->res_id, - vbi); + CAM_INFO_RATE_LIMIT(CAM_ISP, + "Device %s index %u Resource %u HBI: 0x%x VBI: 0x%x", + soc_info->dev_name, soc_info->index, + res->res_id, hbi, vbi); return 0; } @@ -2506,6 +2614,7 @@ static int cam_ife_csid_init_hw(void *hw_priv, struct cam_hw_info *csid_hw_info; struct cam_isp_resource_node *res; const struct cam_ife_csid_reg_offset *csid_reg; + unsigned long flags; if (!hw_priv || !init_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -2573,6 +2682,10 @@ static int cam_ife_csid_init_hw(void *hw_priv, if (rc) cam_ife_csid_disable_hw(csid_hw); + + spin_lock_irqsave(&csid_hw->lock_state, flags); + csid_hw->device_enabled = 1; + spin_unlock_irqrestore(&csid_hw->lock_state, flags); end: mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; @@ -2705,6 +2818,7 @@ static int cam_ife_csid_stop(void *hw_priv, struct cam_isp_resource_node *res; struct cam_csid_hw_stop_args *csid_stop; uint32_t i; + uint32_t res_mask = 0; if (!hw_priv || !stop_args || (arg_size != sizeof(struct cam_csid_hw_stop_args))) { @@ -2736,6 +2850,7 @@ static int cam_ife_csid_stop(void *hw_priv, rc = cam_ife_csid_tpg_stop(csid_hw, res); break; case CAM_ISP_RESOURCE_PIX_PATH: + res_mask |= (1 << res->res_id); if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP || res->res_id == CAM_IFE_PIX_PATH_RES_PPP) rc = cam_ife_csid_disable_pxl_path(csid_hw, @@ -2753,6 +2868,9 @@ static int cam_ife_csid_stop(void *hw_priv, } } + if (res_mask) + rc = cam_ife_csid_poll_stop_status(csid_hw, res_mask); + for (i = 0; i < csid_stop->num_res; i++) { res = csid_stop->node_res[i]; res->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; @@ -2920,6 +3038,7 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) uint32_t val, irq_status_ppp = 0; bool fatal_err_detected = false; uint32_t sof_irq_debug_en = 0; + unsigned long flags; csid_hw = (struct cam_ife_csid_hw *)data; @@ -2985,65 +3104,74 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) 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); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", - csid_hw->hw_intf->hw_idx); - fatal_err_detected = true; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_EOT_RECEPTION", - csid_hw->hw_intf->hw_idx); - csid_hw->error_irq_count++; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_SOT_RECEPTION", - csid_hw->hw_intf->hw_idx); - csid_hw->error_irq_count++; - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", - csid_hw->hw_intf->hw_idx); - } - if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_STREAM_UNDERFLOW", - csid_hw->hw_intf->hw_idx); - } - 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); + spin_lock_irqsave(&csid_hw->lock_state, flags); + if (csid_hw->device_enabled == 1) { + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE0_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 0 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE1_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 1 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE2_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 2 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_LANE3_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d lane 3 over flow", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_TG_FIFO_OVERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d TG OVER FLOW", + csid_hw->hw_intf->hw_idx); + fatal_err_detected = true; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_EOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_EOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d CPHY_SOT_RECEPTION", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_PH_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d CPHY_PH_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_CRC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_CRC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_ECC) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d ERROR_ECC", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_MMAPPED_VC_DT) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d MMAPPED_VC_DT", + csid_hw->hw_intf->hw_idx); + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_STREAM_UNDERFLOW) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d ERROR_STREAM_UNDERFLOW", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } + if (irq_status_rx & CSID_CSI2_RX_ERROR_UNBOUNDED_FRAME) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d UNBOUNDED_FRAME", + csid_hw->hw_intf->hw_idx); + csid_hw->error_irq_count++; + } } + spin_unlock_irqrestore(&csid_hw->lock_state, flags); if (csid_hw->error_irq_count > CAM_IFE_CSID_MAX_IRQ_ERROR_COUNT) { @@ -3170,6 +3298,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d IPP EOF received", csid_hw->hw_intf->hw_idx); + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d IPP CCIF violation", + csid_hw->hw_intf->hw_idx); + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d IPP fifo over flow", @@ -3203,6 +3336,11 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID:%d PPP EOF received", csid_hw->hw_intf->hw_idx); + if ((irq_status_ipp & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSID:%d PPP CCIF violation", + csid_hw->hw_intf->hw_idx); + if (irq_status_ppp & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d PPP fifo over flow", @@ -3234,6 +3372,10 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_INFO_RATE_LIMIT(CAM_ISP, "CSID RDI:%d EOF received", i); + if ((irq_status_rdi[i] & CSID_PATH_ERROR_CCIF_VIOLATION)) + CAM_INFO_RATE_LIMIT(CAM_ISP, + "CSIDi RDI :%d CCIF violation", i); + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d RDI fifo over flow", @@ -3280,9 +3422,11 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->hw_intf->hw_type, csid_idx); + ife_csid_hw->device_enabled = 0; ife_csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; mutex_init(&ife_csid_hw->hw_info->hw_mutex); spin_lock_init(&ife_csid_hw->hw_info->hw_lock); + spin_lock_init(&ife_csid_hw->lock_state); init_completion(&ife_csid_hw->hw_info->hw_complete); init_completion(&ife_csid_hw->csid_top_complete); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h index 43fd9b03132e..3a093d205f59 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.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 @@ -64,6 +64,7 @@ #define CSID_PATH_INFO_INPUT_SOF BIT(12) #define CSID_PATH_ERROR_PIX_COUNT BIT(13) #define CSID_PATH_ERROR_LINE_COUNT BIT(14) +#define CSID_PATH_ERROR_CCIF_VIOLATION BIT(15) /* * Debug values enable the corresponding interrupts and debug logs provide @@ -138,6 +139,8 @@ struct cam_ife_csid_pxl_reg_offset { /* configuration */ uint32_t pix_store_en_shift_val; uint32_t early_eof_en_shift_val; + uint32_t quad_cfa_bin_en_shift_val; + uint32_t ccif_violation_en; }; struct cam_ife_csid_rdi_reg_offset { @@ -182,6 +185,10 @@ struct cam_ife_csid_rdi_reg_offset { uint32_t csid_rdi_timestamp_prev1_eof_addr; uint32_t csid_rdi_byte_cntr_ping_addr; uint32_t csid_rdi_byte_cntr_pong_addr; + + /* configuration */ + uint32_t packing_format; + uint32_t ccif_violation_en; }; struct cam_ife_csid_csi2_rx_reg_offset { @@ -194,7 +201,7 @@ struct cam_ife_csid_csi2_rx_reg_offset { 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_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; @@ -210,6 +217,14 @@ struct cam_ife_csid_csi2_rx_reg_offset { uint32_t csid_csi2_rx_total_pkts_rcvd_addr; uint32_t csid_csi2_rx_stats_ecc_addr; uint32_t csid_csi2_rx_total_crc_err_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type3_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type2_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type1_cfg1_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg0_addr; + uint32_t csid_csi2_rx_de_scramble_type0_cfg1_addr; /*configurations */ uint32_t csi2_rst_srb_all; @@ -225,6 +240,7 @@ struct cam_ife_csid_csi2_rx_reg_offset { uint32_t csi2_capture_short_pkt_vc_shift; uint32_t csi2_capture_cphy_pkt_dt_shift; uint32_t csi2_capture_cphy_pkt_vc_shift; + uint32_t csi2_rx_phy_num_mask; }; struct cam_ife_csid_csi2_tpg_reg_offset { @@ -274,6 +290,7 @@ struct cam_ife_csid_common_reg_offset { uint32_t num_rdis; uint32_t num_pix; uint32_t num_ppp; + uint32_t csid_reg_rst_stb; uint32_t csid_rst_stb; uint32_t csid_rst_stb_sw_all; uint32_t path_rst_stb_all; @@ -477,6 +494,8 @@ struct cam_ife_csid_hw { bool sof_irq_triggered; uint32_t irq_debug_cnt; uint32_t error_irq_count; + uint32_t device_enabled; + spinlock_t lock_state; }; int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c deleted file mode 100644 index 6c39bd84e47f..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c +++ /dev/null @@ -1,59 +0,0 @@ -/* 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 <linux/module.h> -#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, - .suppress_bind_attrs = true, - }, -}; - -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_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c index b05a4b533c23..11c71145ef94 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.c @@ -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 @@ -26,6 +26,10 @@ static const struct of_device_id cam_ife_csid_lite_dt_match[] = { .compatible = "qcom,csid-lite170", .data = &cam_ife_csid_lite_hw_info, }, + { + .compatible = "qcom,csid-lite175", + .data = &cam_ife_csid_lite_hw_info, + }, {} }; MODULE_DEVICE_TABLE(of, cam_ife_csid_lite_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h index d4e05115455a..e39666fe12b7 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite17x.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 @@ -232,6 +232,7 @@ static const struct cam_ife_csid_csi2_rx_reg_offset .csi2_capture_short_pkt_vc_shift = 15, .csi2_capture_cphy_pkt_dt_shift = 20, .csi2_capture_cphy_pkt_vc_shift = 26, + .csi2_rx_phy_num_mask = 0x3, }; @@ -286,6 +287,7 @@ static const struct cam_ife_csid_common_reg_offset .version_incr = 0, .num_rdis = 4, .num_pix = 0, + .csid_reg_rst_stb = 1, .csid_rst_stb = 0x1e, .csid_rst_stb_sw_all = 0x1f, .path_rst_stb_all = 0x7f, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index 890dad3b66b2..5e02609088c4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -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 @@ -117,7 +117,7 @@ int cam_ife_csid_deinit_soc_resources( } int cam_ife_csid_enable_soc_resources( - struct cam_hw_soc_info *soc_info, uint32_t clk_lvl) + struct cam_hw_soc_info *soc_info, enum cam_vote_level clk_level) { int rc = 0; struct cam_csid_soc_private *soc_private; @@ -142,7 +142,7 @@ int cam_ife_csid_enable_soc_resources( } rc = cam_soc_util_enable_platform_resource(soc_info, true, - clk_lvl, true); + clk_level, true); if (rc) { CAM_ERR(CAM_ISP, "enable platform failed"); goto stop_cpas; @@ -235,24 +235,3 @@ int cam_ife_csid_disable_ife_force_clock_on(struct cam_hw_soc_info *soc_info, return rc; } - -uint32_t cam_ife_csid_get_vote_level(struct cam_hw_soc_info *soc_info, - uint64_t clock_rate) -{ - int i = 0; - - if (!clock_rate) - return CAM_SVS_VOTE; - - for (i = 0; i < CAM_MAX_VOTE; i++) { - if (soc_info->clk_rate[i][soc_info->num_clk - 1] >= - clock_rate) { - CAM_DBG(CAM_ISP, - "Clock rate %lld, selected clock level %d", - clock_rate, i); - return i; - } - } - - return CAM_TURBO_VOTE; -} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index 940d338a9572..61542566a924 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.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 @@ -80,14 +80,17 @@ enum cam_isp_resource_type { CAM_ISP_RESOURCE_PIX_PATH, CAM_ISP_RESOURCE_VFE_IN, CAM_ISP_RESOURCE_VFE_OUT, + CAM_ISP_RESOURCE_VFE_BUS_RD, CAM_ISP_RESOURCE_MAX, }; enum cam_isp_hw_cmd_type { CAM_ISP_HW_CMD_GET_CHANGE_BASE, CAM_ISP_HW_CMD_GET_BUF_UPDATE, + CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM, CAM_ISP_HW_CMD_GET_REG_UPDATE, CAM_ISP_HW_CMD_GET_HFR_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM, CAM_ISP_HW_CMD_GET_SECURE_MODE, CAM_ISP_HW_CMD_STRIPE_UPDATE, CAM_ISP_HW_CMD_CLOCK_UPDATE, @@ -95,10 +98,12 @@ enum cam_isp_hw_cmd_type { 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_UBWC_UPDATE, CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_SET_CAMIF_DEBUG, - CAM_ISP_HW_CMD_UBWC_UPDATE, CAM_ISP_HW_CMD_CSID_CLOCK_UPDATE, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, + CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD, CAM_ISP_HW_CMD_MAX, }; @@ -186,6 +191,20 @@ struct cam_isp_hw_get_wm_update { }; /* + * struct cam_isp_hw_rup_data: + * + * @Brief: RUP for required resources. + * + * @is_fe_enable if fetch engine enabled + * @res_bitmap resource bitmap for set resources + * + */ +struct cam_isp_hw_rup_data { + bool is_fe_enable; + unsigned long res_bitmap; +}; + +/* * struct cam_isp_hw_get_cmd_update: * * @Brief: Get cmd buffer update for different CMD types @@ -202,10 +221,13 @@ struct cam_isp_hw_get_cmd_update { union { void *data; struct cam_isp_hw_get_wm_update *wm_update; + struct cam_isp_hw_get_wm_update *rm_update; struct cam_isp_port_hfr_config *hfr_update; struct cam_isp_clock_config *clock_update; struct cam_isp_bw_config *bw_update; struct cam_ubwc_plane_cfg_v1 *ubwc_update; + struct cam_fe_config *fe_update; + struct cam_isp_hw_rup_data *rup_data; }; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h index b957d6913f77..f60bf6e4b3d4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_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 @@ -28,7 +28,7 @@ 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_RD = 2, CAM_ISP_HW_VFE_IN_RDI0 = 3, CAM_ISP_HW_VFE_IN_RDI1 = 4, CAM_ISP_HW_VFE_IN_RDI2 = 5, @@ -153,6 +153,7 @@ struct cam_vfe_hw_vfe_in_acquire_args { * used to schedule bottom of IRQ events associated * with this resource. * @vfe_out: Acquire args for VFE_OUT + * @vfe_bus_rd Acquire args for VFE_BUS_READ * @vfe_in: Acquire args for VFE_IN */ struct cam_vfe_acquire_args { @@ -160,6 +161,7 @@ struct cam_vfe_acquire_args { void *tasklet; union { struct cam_vfe_hw_vfe_out_acquire_args vfe_out; + struct cam_vfe_hw_vfe_out_acquire_args vfe_bus_rd; struct cam_vfe_hw_vfe_in_acquire_args vfe_in; }; }; @@ -178,7 +180,7 @@ struct cam_vfe_clock_update_args { /* * struct cam_vfe_bw_update_args: * - * @node_res: Resource to get the time stamp + * @node_res: Resource to get the BW * @camnoc_bw_bytes: Bandwidth vote request for CAMNOC * @external_bw_bytes: Bandwidth vote request from CAMNOC * out to the rest of the path-to-DDR @@ -189,6 +191,18 @@ struct cam_vfe_bw_update_args { uint64_t external_bw_bytes; }; +/* + * struct cam_vfe_fe_update_args: + * + * @node_res: Resource to get fetch configuration + * @fe_config: fetch engine configuration + * + */ +struct cam_vfe_fe_update_args { + struct cam_isp_resource_node *node_res; + struct cam_fe_config fe_config; +}; + enum cam_vfe_bw_control_action { CAM_VFE_BW_CONTROL_EXCLUDE = 0, CAM_VFE_BW_CONTROL_INCLUDE = 1 @@ -218,6 +232,7 @@ struct cam_vfe_bw_control_args { * @irq_reg_val: IRQ and Error register values, read when IRQ was * handled * @error_type: Identify different errors + * @enable_reg_dump: enable register dump on error * @ts: Timestamp */ struct cam_vfe_top_irq_evt_payload { @@ -227,6 +242,7 @@ struct cam_vfe_top_irq_evt_payload { uint32_t evt_id; uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; uint32_t error_type; + bool enable_reg_dump; struct cam_isp_timestamp ts; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 5e6bb2012fff..2bd6db9954f1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -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 @@ -36,6 +36,11 @@ static uint32_t camif_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x00000000, }; +static uint32_t camif_fe_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x10000056, + 0x00000000, +}; + static uint32_t camif_irq_err_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { 0x0003FC00, 0xEFFF7EBC, @@ -286,6 +291,16 @@ int cam_vfe_init_hw(void *hw_priv, void *init_hw_args, uint32_t arg_size) goto deinint_vfe_res; } + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.init( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) { + CAM_ERR(CAM_ISP, "Bus RD HW init Failed rc=%d", rc); + goto deinint_vfe_res; + } + } + vfe_hw->hw_state = CAM_HW_STATE_POWER_UP; return rc; @@ -339,6 +354,14 @@ int cam_vfe_deinit_hw(void *hw_priv, void *deinit_hw_args, uint32_t arg_size) if (rc) CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.deinit( + core_info->vfe_rd_bus->bus_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_ISP, "Bus HW deinit Failed rc=%d", rc); + } + isp_res = (struct cam_isp_resource_node *)deinit_hw_args; if (isp_res && isp_res->deinit) { rc = isp_res->deinit(isp_res, NULL, 0); @@ -485,18 +508,25 @@ int cam_vfe_reserve(void *hw_priv, void *reserve_args, uint32_t arg_size) core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; acquire = (struct cam_vfe_acquire_args *)reserve_args; + CAM_DBG(CAM_ISP, "acq res type: %d", acquire->rsrc_type); mutex_lock(&vfe_hw->hw_mutex); - if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_IN) + 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) + } 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 + } else if (acquire->rsrc_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.reserve( + core_info->vfe_rd_bus->bus_priv, acquire, + sizeof(*acquire)); + } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", acquire->rsrc_type); + } mutex_unlock(&vfe_hw->hw_mutex); @@ -529,8 +559,14 @@ int cam_vfe_release(void *hw_priv, void *release_args, uint32_t arg_size) rc = core_info->vfe_bus->hw_ops.release( core_info->vfe_bus->bus_priv, isp_res, sizeof(*isp_res)); - else + else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.release( + core_info->vfe_rd_bus->bus_priv, isp_res, + sizeof(*isp_res)); + } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } mutex_unlock(&vfe_hw->hw_mutex); @@ -570,6 +606,19 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) &tasklet_bh_api); if (isp_res->irq_handle < 1) rc = -ENOMEM; + } else if (isp_res->res_id == CAM_ISP_HW_VFE_IN_RD) { + isp_res->irq_handle = + cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + camif_fe_irq_reg_mask, + &core_info->irq_payload, + cam_vfe_irq_top_half, + cam_ife_mgr_do_tasklet, + isp_res->tasklet_info, + &tasklet_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( @@ -598,6 +647,10 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) } } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.start(isp_res, NULL, 0); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.start(isp_res, + NULL, 0); } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); rc = -EFAULT; @@ -653,6 +706,10 @@ int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) sizeof(struct cam_isp_resource_node)); } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_BUS_RD) { + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.stop(isp_res, + NULL, 0); } else { CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); } @@ -716,7 +773,26 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type, core_info->vfe_bus->bus_priv, cmd_type, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + if (core_info->vfe_rd_bus) + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = core_info->vfe_top->hw_ops.process_cmd( + core_info->vfe_top->top_priv, cmd_type, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + if (core_info->vfe_rd_bus) { + rc = core_info->vfe_rd_bus->hw_ops.process_cmd( + core_info->vfe_rd_bus->bus_priv, cmd_type, + cmd_args, arg_size); + } + break; default: CAM_ERR(CAM_ISP, "Invalid cmd type:%d", cmd_type); rc = -EINVAL; @@ -766,7 +842,8 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, goto deinit_controller; } - rc = cam_vfe_bus_init(vfe_hw_info->bus_version, soc_info, hw_intf, + rc = cam_vfe_bus_init(vfe_hw_info->bus_version, BUS_TYPE_WR, + soc_info, hw_intf, vfe_hw_info->bus_hw_info, core_info->vfe_irq_controller, &core_info->vfe_bus); if (rc) { @@ -774,6 +851,19 @@ int cam_vfe_core_init(struct cam_vfe_hw_core_info *core_info, goto deinit_top; } + /* Read Bus is not valid for vfe-lite */ + if ((hw_intf->hw_idx == 0) || (hw_intf->hw_idx == 1)) { + rc = cam_vfe_bus_init(vfe_hw_info->bus_rd_version, BUS_TYPE_RD, + soc_info, hw_intf, vfe_hw_info->bus_rd_hw_info, + core_info->vfe_irq_controller, &core_info->vfe_rd_bus); + if (rc) { + CAM_ERR(CAM_ISP, "Error! RD cam_vfe_bus_init failed"); + rc = 0; + } + CAM_DBG(CAM_ISP, "vfe_bus_rd %pK hw_idx %d", + core_info->vfe_rd_bus, hw_intf->hw_idx); + } + 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); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h index 9cec56a15fec..dd078f2d6ce3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.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 @@ -25,6 +25,9 @@ struct cam_vfe_hw_info { uint32_t bus_version; void *bus_hw_info; + uint32_t bus_rd_version; + void *bus_rd_hw_info; + uint32_t top_version; void *top_hw_info; uint32_t camif_version; @@ -53,6 +56,7 @@ struct cam_vfe_hw_core_info { void *vfe_irq_controller; struct cam_vfe_top *vfe_top; struct cam_vfe_bus *vfe_bus; + struct cam_vfe_bus *vfe_rd_bus; void *tasklet_info; struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_EVT_MAX]; struct list_head free_payload_list; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c index 12b7a03c6276..b57762644082 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -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 @@ -26,6 +26,8 @@ static bool cam_vfe_cpas_cb(uint32_t client_handle, void *userdata, switch (irq_data->irq_type) { case CAM_CAMNOC_IRQ_IFE02_UBWC_ENCODE_ERROR: case CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE0_UBWC_ENCODE_ERROR: + case CAM_CAMNOC_IRQ_IFE1_WRITE_UBWC_ENCODE_ERROR: CAM_ERR_RATE_LIMIT(CAM_ISP, "IFE UBWC Encode error type=%d status=%x", irq_data->irq_type, @@ -104,7 +106,7 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *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"); + CAM_WARN(CAM_ISP, "Option clk get failed with rc %d", rc); rc = cam_vfe_request_platform_resource(soc_info, vfe_irq_handler, irq_data); @@ -115,20 +117,56 @@ int cam_vfe_init_soc_resources(struct cam_hw_soc_info *soc_info, } 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); + + rc = cam_cpas_get_cpas_hw_version(&soc_private->cpas_version); 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; + CAM_ERR(CAM_ISP, "Error! Invalid cpas version rc=%d", rc); + goto free_soc_private; } + switch (soc_private->cpas_version) { + case CAM_CPAS_TITAN_175_V120: + strlcpy(cpas_register_param.identifier, "iferdi", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "rdi CPAS registration failed rc=%d", + rc); + goto release_soc; + } else { + soc_private->cpas_handle[0] = + cpas_register_param.client_handle; + } + + strlcpy(cpas_register_param.identifier, "ifenrdi", + CAM_HW_IDENTIFIER_LENGTH); + rc = cam_cpas_register_client(&cpas_register_param); + if (rc) { + CAM_ERR(CAM_ISP, "nrdi CPAS registration failed rc=%d", + rc); + goto release_soc; + } else { + soc_private->cpas_handle[1] = + cpas_register_param.client_handle; + } + break; + default: + strlcpy(cpas_register_param.identifier, "ife", + CAM_HW_IDENTIFIER_LENGTH); + 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[0] = + cpas_register_param.client_handle; + } + } return rc; release_soc: @@ -154,10 +192,15 @@ int cam_vfe_deinit_soc_resources(struct cam_hw_soc_info *soc_info) CAM_ERR(CAM_ISP, "Error! soc_private NULL"); return -ENODEV; } - - rc = cam_cpas_unregister_client(soc_private->cpas_handle); + rc = cam_cpas_unregister_client(soc_private->cpas_handle[0]); if (rc) - CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); + CAM_ERR(CAM_ISP, "CPAS0 unregistration failed rc=%d", rc); + + if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + rc = cam_cpas_unregister_client(soc_private->cpas_handle[1]); + if (rc) + CAM_ERR(CAM_ISP, "CPAS1 unregistration failed rc=%d", + rc); rc = cam_vfe_release_platform_resource(soc_info); if (rc < 0) @@ -194,13 +237,22 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) axi_vote.compressed_bw = 10640000000L; axi_vote.uncompressed_bw = 10640000000L; - rc = cam_cpas_start(soc_private->cpas_handle, &ahb_vote, &axi_vote); + rc = cam_cpas_start(soc_private->cpas_handle[0], &ahb_vote, &axi_vote); if (rc) { - CAM_ERR(CAM_ISP, "Error! CPAS start failed rc=%d", rc); + CAM_ERR(CAM_ISP, "Error! CPAS0 start failed rc=%d", rc); rc = -EFAULT; goto end; } + if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + rc = cam_cpas_start(soc_private->cpas_handle[1], &ahb_vote, + &axi_vote); + if (rc) { + CAM_ERR(CAM_ISP, "Error! CPAS1 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) { @@ -211,7 +263,9 @@ int cam_vfe_enable_soc_resources(struct cam_hw_soc_info *soc_info) return rc; stop_cpas: - cam_cpas_stop(soc_private->cpas_handle); + cam_cpas_stop(soc_private->cpas_handle[0]); + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + cam_cpas_stop(soc_private->cpas_handle[1]); end: return rc; } @@ -283,11 +337,18 @@ int cam_vfe_disable_soc_resources(struct cam_hw_soc_info *soc_info) return rc; } - rc = cam_cpas_stop(soc_private->cpas_handle); + rc = cam_cpas_stop(soc_private->cpas_handle[0]); if (rc) { CAM_ERR(CAM_ISP, "Error! CPAS stop failed rc=%d", rc); return rc; } + if (!rc && soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) + rc = cam_cpas_stop(soc_private->cpas_handle[1]); + 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_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h index 3f862e9249f8..780bd34ab968 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.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 @@ -18,6 +18,12 @@ #define CAM_VFE_DSP_CLK_NAME "ife_dsp_clk" +enum cam_cpas_handle_id { + CAM_CPAS_HANDLE_CAMIF, + CAM_CPAS_HANDLE_RAW, + CAM_CPAS_HANDLE_MAX, +}; + /* * struct cam_vfe_soc_private: * @@ -26,9 +32,11 @@ * @cpas_handle: Handle returned on registering with CPAS driver. * This handle is used for all further interface * with CPAS. + * @cpas_version: Has cpas version read from Hardware */ struct cam_vfe_soc_private { - uint32_t cpas_handle; + uint32_t cpas_handle[CAM_CPAS_HANDLE_MAX]; + uint32_t cpas_version; struct clk *dsp_clk; int32_t dsp_clk_index; int32_t dsp_clk_rate; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile deleted file mode 100644 index deeae35cef79..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_utils -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_core -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/hw_utils/irq_controller -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top -ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus -ccflags-y += -Idrivers/media/platform/msm/camera_v3/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_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c deleted file mode 100644 index d002f84015de..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c +++ /dev/null @@ -1,52 +0,0 @@ -/* 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 <linux/module.h> -#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, - .suppress_bind_attrs = true, - }, -}; - -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_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c deleted file mode 100644 index ab692cf095e4..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c +++ /dev/null @@ -1,52 +0,0 @@ -/* 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 <linux/module.h> -#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, - .suppress_bind_attrs = true, - }, -}; - -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_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h deleted file mode 100644 index 4b2e0963a599..000000000000 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h +++ /dev/null @@ -1,336 +0,0 @@ -/* 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_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_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h index 88d5b132ad3d..61c1e9e01ba2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe170.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 @@ -828,6 +828,12 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .max_height = -1, }, }, + .reg_data = { + .ubwc_10bit_threshold_lossy_0 = 0, + .ubwc_10bit_threshold_lossy_1 = 0, + .ubwc_8bit_threshold_lossy_0 = 0, + .ubwc_8bit_threshold_lossy_1 = 0, + }, }; struct cam_vfe_hw_info cam_vfe170_hw_info = { diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.h index d1284d9f23d2..13147f4acf96 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175.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 @@ -10,16 +10,17 @@ * GNU General Public License for more details. */ -#ifndef _CAM_VFE170_H_ -#define _CAM_VFE170_H_ +#ifndef _CAM_VFE175_H_ +#define _CAM_VFE175_H_ #include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" #include "cam_vfe_bus_ver2.h" #include "cam_irq_controller.h" #include "cam_vfe_top_ver2.h" #include "cam_vfe_core.h" -static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { +static struct cam_irq_register_set vfe175_top_irq_reg_set[2] = { { .mask_reg_offset = 0x0000005C, .clear_reg_offset = 0x00000064, @@ -32,14 +33,14 @@ static struct cam_irq_register_set vfe170_top_irq_reg_set[2] = { }, }; -static struct cam_irq_controller_reg_info vfe170_top_irq_reg_info = { +static struct cam_irq_controller_reg_info vfe175_top_irq_reg_info = { .num_registers = 2, - .irq_reg_set = vfe170_top_irq_reg_set, + .irq_reg_set = vfe175_top_irq_reg_set, .global_clear_offset = 0x00000058, .global_clear_bitmask = 0x00000001, }; -static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = { +static struct cam_vfe_camif_ver2_reg vfe175_camif_reg = { .camif_cmd = 0x00000478, .camif_config = 0x0000047C, .line_skip_pattern = 0x00000488, @@ -54,7 +55,7 @@ static struct cam_vfe_camif_ver2_reg vfe170_camif_reg = { .vfe_diag_sensor_status = 0x00000C4C, }; -static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = { +static struct cam_vfe_camif_reg_data vfe_175_camif_reg_data = { .raw_crop_first_pixel_shift = 16, .raw_crop_first_pixel_mask = 0xFFFF, .raw_crop_last_pixel_shift = 0x0, @@ -80,35 +81,57 @@ static struct cam_vfe_camif_reg_data vfe_170_camif_reg_data = { .reg_update_irq_mask = 0x00000010, .eof_irq_mask = 0x00000002, .error_irq_mask0 = 0x0003FC00, - .error_irq_mask1 = 0x0FFF7E80, + .error_irq_mask1 = 0xEFFF7E80, .enable_diagnostic_hw = 0x1, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_170_reg = { +static struct cam_vfe_camif_lite_ver2_reg vfe175_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data vfe175_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_error_irq_mask0 = 0x00400000, + .lite_error_irq_mask1 = 0x00004100, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_reg = { .reset = 0x0000001C, .cgc_ovd = 0x0000002C, .enable = 0x00000040, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_170_reg = { +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_reg = { .reset = 0x00000020, .cgc_ovd = 0x00000030, .enable = 0x00000044, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl color_170_reg = { +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_reg = { .reset = 0x00000024, .cgc_ovd = 0x00000034, .enable = 0x00000048, }; -struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_170_reg = { +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_reg = { .reset = 0x00000028, .cgc_ovd = 0x00000038, .enable = 0x0000004C, }; -static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { +static struct cam_vfe_top_ver2_reg_offset_common vfe175_top_common_reg = { .hw_version = 0x00000000, .hw_capability = 0x00000004, .lens_feature = 0x00000008, @@ -117,10 +140,10 @@ static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { .zoom_feature = 0x00000014, .global_reset_cmd = 0x00000018, .module_ctrl = { - &lens_170_reg, - &stats_170_reg, - &color_170_reg, - &zoom_170_reg, + &lens_175_reg, + &stats_175_reg, + &color_175_reg, + &zoom_175_reg, }, .bus_cgc_ovd = 0x0000003C, .core_cfg = 0x00000050, @@ -129,42 +152,47 @@ static struct cam_vfe_top_ver2_reg_offset_common vfe170_top_common_reg = { .reg_update_cmd = 0x000004AC, }; -static struct cam_vfe_rdi_ver2_reg vfe170_rdi_reg = { +static struct cam_vfe_rdi_ver2_reg vfe175_rdi_reg = { .reg_update_cmd = 0x000004AC, }; -static struct cam_vfe_rdi_reg_data vfe_170_rdi_0_data = { +static struct cam_vfe_rdi_reg_data vfe_175_rdi_0_data = { .reg_update_cmd_data = 0x2, .sof_irq_mask = 0x8000000, .reg_update_irq_mask = 0x20, }; -static struct cam_vfe_rdi_reg_data vfe_170_rdi_1_data = { +static struct cam_vfe_rdi_reg_data vfe_175_rdi_1_data = { .reg_update_cmd_data = 0x4, .sof_irq_mask = 0x10000000, .reg_update_irq_mask = 0x40, }; -static struct cam_vfe_rdi_reg_data vfe_170_rdi_2_data = { +static struct cam_vfe_rdi_reg_data vfe_175_rdi_2_data = { .reg_update_cmd_data = 0x8, .sof_irq_mask = 0x20000000, .reg_update_irq_mask = 0x80, }; -static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { - .common_reg = &vfe170_top_common_reg, +static struct cam_vfe_top_ver2_hw_info vfe175_top_hw_info = { + .common_reg = &vfe175_top_common_reg, .camif_hw_info = { - .common_reg = &vfe170_top_common_reg, - .camif_reg = &vfe170_camif_reg, - .reg_data = &vfe_170_camif_reg_data, + .common_reg = &vfe175_top_common_reg, + .camif_reg = &vfe175_camif_reg, + .reg_data = &vfe_175_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_top_common_reg, + .camif_lite_reg = &vfe175_camif_lite_reg, + .reg_data = &vfe175_camif_lite_reg_data, }, .rdi_hw_info = { - .common_reg = &vfe170_top_common_reg, - .rdi_reg = &vfe170_rdi_reg, + .common_reg = &vfe175_top_common_reg, + .rdi_reg = &vfe175_rdi_reg, .reg_data = { - &vfe_170_rdi_0_data, - &vfe_170_rdi_1_data, - &vfe_170_rdi_2_data, + &vfe_175_rdi_0_data, + &vfe_175_rdi_1_data, + &vfe_175_rdi_2_data, NULL, }, }, @@ -173,10 +201,11 @@ static struct cam_vfe_top_ver2_hw_info vfe170_top_hw_info = { CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, }, }; -static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { +static struct cam_irq_register_set vfe175_bus_irq_reg[3] = { { .mask_reg_offset = 0x00002044, .clear_reg_offset = 0x00002050, @@ -194,29 +223,68 @@ static struct cam_irq_register_set vfe170_bus_irq_reg[3] = { }, }; -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_3_client + vfe175_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, + .threshlod_lossy_0 = 0x000025A8, + .threshlod_lossy_1 = 0x000025AC, + +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, + .threshlod_lossy_0 = 0x000026A8, + .threshlod_lossy_1 = 0x000026AC, }; -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_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, + .threshlod_lossy_0 = 0x000036A8, + .threshlod_lossy_1 = 0x000036AC, }; -static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, + .threshlod_lossy_0 = 0x000037A8, + .threshlod_lossy_1 = 0x000037AC, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_bus_hw_info = { .common_reg = { .hw_version = 0x00002000, .hw_capability = 0x00002004, @@ -226,7 +294,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .dual_master_comp_cfg = 0x00002028, .irq_reg_info = { .num_registers = 3, - .irq_reg_set = vfe170_bus_irq_reg, + .irq_reg_set = vfe175_bus_irq_reg, .global_clear_offset = 0x00002068, .global_clear_bitmask = 0x00000001, }, @@ -240,7 +308,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .debug_status_cfg = 0x0000226C, .debug_status_0 = 0x00002270, }, - .num_client = 20, + .num_client = 24, .bus_client_reg = { /* BUS Client 0 */ { @@ -324,7 +392,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .framedrop_pattern = 0x00002554, .frame_inc = 0x00002558, .burst_limit = 0x0000255C, - .ubwc_regs = &ubwc_regs_client_3, + .ubwc_regs = &vfe175_ubwc_regs_client_3, }, /* BUS Client 4 */ { @@ -345,7 +413,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .framedrop_pattern = 0x00002654, .frame_inc = 0x00002658, .burst_limit = 0x0000265C, - .ubwc_regs = &ubwc_regs_client_4, + .ubwc_regs = &vfe175_ubwc_regs_client_4, }, /* BUS Client 5 */ { @@ -662,6 +730,90 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .burst_limit = 0x0000355C, .ubwc_regs = NULL, }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = &vfe175_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = &vfe175_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, }, .comp_grp_reg = { /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ @@ -721,7 +873,7 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .addr_sync_mask = 0x0000209C, }, }, - .num_out = 18, + .num_out = 22, .vfe_out_hw_info = { { .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, @@ -822,21 +974,50 @@ static struct cam_vfe_bus_ver2_hw_info vfe170_bus_hw_info = { .max_width = -1, .max_height = -1, }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, + .reg_data = { + .ubwc_10bit_threshold_lossy_0 = 0x8330002, + .ubwc_10bit_threshold_lossy_1 = 0x20204, + .ubwc_8bit_threshold_lossy_0 = 0x6210022, + .ubwc_8bit_threshold_lossy_1 = 0xE0E, }, }; -struct cam_vfe_hw_info cam_vfe170_hw_info = { - .irq_reg_info = &vfe170_top_irq_reg_info, +struct cam_vfe_hw_info cam_vfe175_hw_info = { + .irq_reg_info = &vfe175_top_irq_reg_info, .bus_version = CAM_VFE_BUS_VER_2_0, - .bus_hw_info = &vfe170_bus_hw_info, + .bus_hw_info = &vfe175_bus_hw_info, .top_version = CAM_VFE_TOP_VER_2_0, - .top_hw_info = &vfe170_top_hw_info, + .top_hw_info = &vfe175_top_hw_info, .camif_version = CAM_VFE_CAMIF_VER_2_0, - .camif_reg = &vfe170_camif_reg, + .camif_reg = &vfe175_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_camif_lite_reg, }; -#endif /* _CAM_VFE170_H_ */ +#endif /* _CAM_VFE175_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h new file mode 100644 index 000000000000..5a09c76f95b0 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe175_130.h @@ -0,0 +1,1131 @@ +/* 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. + */ + +#ifndef _CAM_VFE175_130_H_ +#define _CAM_VFE175_130_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_camif_lite_ver2.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_irq_controller.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_core.h" + +static struct cam_irq_register_set vfe175_130_top_irq_reg_set[2] = { + { + .mask_reg_offset = 0x0000005C, + .clear_reg_offset = 0x00000064, + .status_reg_offset = 0x0000006C, + }, + { + .mask_reg_offset = 0x00000060, + .clear_reg_offset = 0x00000068, + .status_reg_offset = 0x00000070, + }, +}; + +static struct cam_irq_controller_reg_info vfe175_130_top_irq_reg_info = { + .num_registers = 2, + .irq_reg_set = vfe175_130_top_irq_reg_set, + .global_clear_offset = 0x00000058, + .global_clear_bitmask = 0x00000001, +}; + +static struct cam_vfe_camif_ver2_reg vfe175_130_camif_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, +}; + +static struct cam_vfe_camif_reg_data vfe_175_130_camif_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .enable_diagnostic_hw = 0x1, +}; + +static struct cam_vfe_fe_ver1_reg vfe175_130_fe_reg = { + .camif_cmd = 0x00000478, + .camif_config = 0x0000047C, + .line_skip_pattern = 0x00000488, + .pixel_skip_pattern = 0x0000048C, + .skip_period = 0x00000490, + .irq_subsample_pattern = 0x0000049C, + .epoch_irq = 0x000004A0, + .raw_crop_width_cfg = 0x00000CE4, + .raw_crop_height_cfg = 0x00000CE8, + .reg_update_cmd = 0x000004AC, + .vfe_diag_config = 0x00000C48, + .vfe_diag_sensor_status = 0x00000C4C, + .fe_cfg = 0x00000084, +}; + +static struct cam_vfe_fe_reg_data vfe_175_130_fe_reg_data = { + .raw_crop_first_pixel_shift = 16, + .raw_crop_first_pixel_mask = 0xFFFF, + .raw_crop_last_pixel_shift = 0x0, + .raw_crop_last_pixel_mask = 0x3FFF, + .raw_crop_first_line_shift = 16, + .raw_crop_first_line_mask = 0xFFFF, + .raw_crop_last_line_shift = 0, + .raw_crop_last_line_mask = 0x3FFF, + .input_mux_sel_shift = 5, + .input_mux_sel_mask = 0x3, + .extern_reg_update_shift = 4, + .extern_reg_update_mask = 1, + .pixel_pattern_shift = 0, + .pixel_pattern_mask = 0x7, + .dsp_mode_shift = 23, + .dsp_mode_mask = 0x1, + .dsp_en_shift = 3, + .dsp_en_mask = 0x1, + .reg_update_cmd_data = 0x1, + .epoch_line_cfg = 0x00140014, + .sof_irq_mask = 0x00000001, + .epoch0_irq_mask = 0x00000004, + .reg_update_irq_mask = 0x00000010, + .eof_irq_mask = 0x00000002, + .error_irq_mask0 = 0x0003FC00, + .error_irq_mask1 = 0xEFFF7E80, + .enable_diagnostic_hw = 0x1, + .fe_mux_data = 0x2, + .hbi_cnt_shift = 0x8, +}; + +static struct cam_vfe_camif_lite_ver2_reg vfe175_130_camif_lite_reg = { + .camif_lite_cmd = 0x00000FC0, + .camif_lite_config = 0x00000FC4, + .lite_skip_period = 0x00000FC8, + .lite_irq_subsample_pattern = 0x00000FCC, + .lite_epoch_irq = 0x00000FD0, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_camif_lite_ver2_reg_data + vfe175_130_camif_lite_reg_data = { + .dual_pd_reg_update_cmd_data = 0x20, + .lite_epoch_line_cfg = 0x00140014, + .lite_sof_irq_mask = 0x00040000, + .lite_epoch0_irq_mask = 0x00100000, + .dual_pd_reg_upd_irq_mask = 0x04000000, + .lite_eof_irq_mask = 0x00080000, + .lite_error_irq_mask0 = 0x00400000, + .lite_error_irq_mask1 = 0x00004100, + .extern_reg_update_shift = 4, + .dual_pd_path_sel_shift = 24, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl lens_175_130_reg = { + .reset = 0x0000001C, + .cgc_ovd = 0x0000002C, + .enable = 0x00000040, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl stats_175_130_reg = { + .reset = 0x00000020, + .cgc_ovd = 0x00000030, + .enable = 0x00000044, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl color_175_130_reg = { + .reset = 0x00000024, + .cgc_ovd = 0x00000034, + .enable = 0x00000048, +}; + +struct cam_vfe_top_ver2_reg_offset_module_ctrl zoom_175_130_reg = { + .reset = 0x00000028, + .cgc_ovd = 0x00000038, + .enable = 0x0000004C, +}; + +static struct cam_vfe_top_ver2_reg_offset_common vfe175_130_top_common_reg = { + .hw_version = 0x00000000, + .hw_capability = 0x00000004, + .lens_feature = 0x00000008, + .stats_feature = 0x0000000C, + .color_feature = 0x00000010, + .zoom_feature = 0x00000014, + .global_reset_cmd = 0x00000018, + .module_ctrl = { + &lens_175_130_reg, + &stats_175_130_reg, + &color_175_130_reg, + &zoom_175_130_reg, + }, + .bus_cgc_ovd = 0x0000003C, + .core_cfg = 0x00000050, + .three_D_cfg = 0x00000054, + .violation_status = 0x0000007C, + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_ver2_reg vfe175_130_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe_175_130_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_top_ver2_hw_info vfe175_130_top_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_reg = &vfe175_130_camif_reg, + .reg_data = &vfe_175_130_camif_reg_data, + }, + .camif_lite_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + .reg_data = &vfe175_130_camif_lite_reg_data, + }, + .rdi_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .rdi_reg = &vfe175_130_rdi_reg, + .reg_data = { + &vfe_175_130_rdi_0_data, + &vfe_175_130_rdi_1_data, + &vfe_175_130_rdi_2_data, + NULL, + }, + }, + .fe_hw_info = { + .common_reg = &vfe175_130_top_common_reg, + .fe_reg = &vfe175_130_fe_reg, + .reg_data = &vfe_175_130_fe_reg_data, + }, + .mux_type = { + CAM_VFE_CAMIF_VER_2_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_RDI_VER_1_0, + CAM_VFE_CAMIF_LITE_VER_2_0, + CAM_VFE_IN_RD_VER_1_0, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_rd_irq_reg[1] = { + { + .mask_reg_offset = 0x00005010, + .clear_reg_offset = 0x00005014, + .status_reg_offset = 0x0000501C, + }, +}; + +static struct cam_irq_register_set vfe175_130_bus_irq_reg[3] = { + { + .mask_reg_offset = 0x00002044, + .clear_reg_offset = 0x00002050, + .status_reg_offset = 0x0000205C, + }, + { + .mask_reg_offset = 0x00002048, + .clear_reg_offset = 0x00002054, + .status_reg_offset = 0x00002060, + }, + { + .mask_reg_offset = 0x0000204C, + .clear_reg_offset = 0x00002058, + .status_reg_offset = 0x00002064, + }, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_3 = { + .tile_cfg = 0x0000252C, + .h_init = 0x00002530, + .v_init = 0x00002534, + .meta_addr = 0x00002538, + .meta_offset = 0x0000253C, + .meta_stride = 0x00002540, + .mode_cfg_0 = 0x00002544, + .mode_cfg_1 = 0x000025A4, + .bw_limit = 0x000025A0, + .threshlod_lossy_0 = 0x000025A8, + .threshlod_lossy_1 = 0x000025AC, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_4 = { + .tile_cfg = 0x0000262C, + .h_init = 0x00002630, + .v_init = 0x00002634, + .meta_addr = 0x00002638, + .meta_offset = 0x0000263C, + .meta_stride = 0x00002640, + .mode_cfg_0 = 0x00002644, + .mode_cfg_1 = 0x000026A4, + .bw_limit = 0x000026A0, + .threshlod_lossy_0 = 0x000026A8, + .threshlod_lossy_1 = 0x000026AC, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_20 = { + .tile_cfg = 0x0000362C, + .h_init = 0x00003630, + .v_init = 0x00003634, + .meta_addr = 0x00003638, + .meta_offset = 0x0000363C, + .meta_stride = 0x00003640, + .mode_cfg_0 = 0x00003644, + .mode_cfg_1 = 0x000036A4, + .bw_limit = 0x000036A0, + .threshlod_lossy_0 = 0x000036A8, + .threshlod_lossy_1 = 0x000036AC, +}; + +static struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client + vfe175_130_ubwc_regs_client_21 = { + .tile_cfg = 0x0000372C, + .h_init = 0x00003730, + .v_init = 0x00003734, + .meta_addr = 0x00003738, + .meta_offset = 0x0000373C, + .meta_stride = 0x00003740, + .mode_cfg_0 = 0x00003744, + .mode_cfg_1 = 0x000037A4, + .bw_limit = 0x000037A0, + .threshlod_lossy_0 = 0x000037A8, + .threshlod_lossy_1 = 0x000037AC, +}; + +static struct cam_vfe_bus_rd_ver1_hw_info vfe175_130_bus_rd_hw_info = { + .common_reg = { + .hw_version = 0x00005000, + .hw_capability = 0x00005004, + .sw_reset = 0x00005008, + .cgc_ovd = 0x0000500C, + .pwr_iso_cfg = 0x000050CC, + .input_if_cmd = 0x00005020, + .test_bus_ctrl = 0x00005048, + .irq_reg_info = { + .num_registers = 1, + .irq_reg_set = vfe175_130_bus_rd_irq_reg, + .global_clear_offset = 0x00005018, + .global_clear_bitmask = 0x00000001, + }, + }, + .num_client = 1, + .bus_client_reg = { + /* BUS Client 0 */ + { + .cfg = 0x00005050, + .image_addr = 0x00005058, + .buffer_width_cfg = 0x0000505C, + .unpacker_cfg = 0x00005064, + .stride = 0x00005060, + .burst_limit = 0x00005080, + .latency_buf_allocation = 0x00005078, + .ubwc_regs = NULL, + }, + }, + .num_bus_rd_resc = 1, + .vfe_bus_rd_hw_info = { + { + .vfe_bus_rd_type = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + .max_width = -1, + .max_height = -1, + }, + }, +}; + +static struct cam_vfe_bus_ver2_hw_info vfe175_130_bus_hw_info = { + .common_reg = { + .hw_version = 0x00002000, + .hw_capability = 0x00002004, + .sw_reset = 0x00002008, + .cgc_ovd = 0x0000200C, + .pwr_iso_cfg = 0x000020CC, + .dual_master_comp_cfg = 0x00002028, + .irq_reg_info = { + .num_registers = 3, + .irq_reg_set = vfe175_130_bus_irq_reg, + .global_clear_offset = 0x00002068, + .global_clear_bitmask = 0x00000001, + }, + .comp_error_status = 0x0000206C, + .comp_ovrwr_status = 0x00002070, + .dual_comp_error_status = 0x00002074, + .dual_comp_ovrwr_status = 0x00002078, + .addr_sync_cfg = 0x0000207C, + .addr_sync_frame_hdr = 0x00002080, + .addr_sync_no_sync = 0x00002084, + }, + .num_client = 24, + .bus_client_reg = { + /* BUS Client 0 */ + { + .status0 = 0x00002200, + .status1 = 0x00002204, + .cfg = 0x00002208, + .header_addr = 0x0000220C, + .header_cfg = 0x00002210, + .image_addr = 0x00002214, + .image_addr_offset = 0x00002218, + .buffer_width_cfg = 0x0000221C, + .buffer_height_cfg = 0x00002220, + .packer_cfg = 0x00002224, + .stride = 0x00002228, + .irq_subsample_period = 0x00002248, + .irq_subsample_pattern = 0x0000224C, + .framedrop_period = 0x00002250, + .framedrop_pattern = 0x00002254, + .frame_inc = 0x00002258, + .burst_limit = 0x0000225C, + .ubwc_regs = NULL, + }, + /* BUS Client 1 */ + { + .status0 = 0x00002300, + .status1 = 0x00002304, + .cfg = 0x00002308, + .header_addr = 0x0000230C, + .header_cfg = 0x00002310, + .image_addr = 0x00002314, + .image_addr_offset = 0x00002318, + .buffer_width_cfg = 0x0000231C, + .buffer_height_cfg = 0x00002320, + .packer_cfg = 0x00002324, + .stride = 0x00002328, + .irq_subsample_period = 0x00002348, + .irq_subsample_pattern = 0x0000234C, + .framedrop_period = 0x00002350, + .framedrop_pattern = 0x00002354, + .frame_inc = 0x00002358, + .burst_limit = 0x0000235C, + .ubwc_regs = NULL, + }, + /* BUS Client 2 */ + { + .status0 = 0x00002400, + .status1 = 0x00002404, + .cfg = 0x00002408, + .header_addr = 0x0000240C, + .header_cfg = 0x00002410, + .image_addr = 0x00002414, + .image_addr_offset = 0x00002418, + .buffer_width_cfg = 0x0000241C, + .buffer_height_cfg = 0x00002420, + .packer_cfg = 0x00002424, + .stride = 0x00002428, + .irq_subsample_period = 0x00002448, + .irq_subsample_pattern = 0x0000244C, + .framedrop_period = 0x00002450, + .framedrop_pattern = 0x00002454, + .frame_inc = 0x00002458, + .burst_limit = 0x0000245C, + .ubwc_regs = NULL, + }, + /* BUS Client 3 */ + { + .status0 = 0x00002500, + .status1 = 0x00002504, + .cfg = 0x00002508, + .header_addr = 0x0000250C, + .header_cfg = 0x00002510, + .image_addr = 0x00002514, + .image_addr_offset = 0x00002518, + .buffer_width_cfg = 0x0000251C, + .buffer_height_cfg = 0x00002520, + .packer_cfg = 0x00002524, + .stride = 0x00002528, + .irq_subsample_period = 0x00002548, + .irq_subsample_pattern = 0x0000254C, + .framedrop_period = 0x00002550, + .framedrop_pattern = 0x00002554, + .frame_inc = 0x00002558, + .burst_limit = 0x0000255C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_3, + }, + /* BUS Client 4 */ + { + .status0 = 0x00002600, + .status1 = 0x00002604, + .cfg = 0x00002608, + .header_addr = 0x0000260C, + .header_cfg = 0x00002610, + .image_addr = 0x00002614, + .image_addr_offset = 0x00002618, + .buffer_width_cfg = 0x0000261C, + .buffer_height_cfg = 0x00002620, + .packer_cfg = 0x00002624, + .stride = 0x00002628, + .irq_subsample_period = 0x00002648, + .irq_subsample_pattern = 0x0000264C, + .framedrop_period = 0x00002650, + .framedrop_pattern = 0x00002654, + .frame_inc = 0x00002658, + .burst_limit = 0x0000265C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_4, + }, + /* BUS Client 5 */ + { + .status0 = 0x00002700, + .status1 = 0x00002704, + .cfg = 0x00002708, + .header_addr = 0x0000270C, + .header_cfg = 0x00002710, + .image_addr = 0x00002714, + .image_addr_offset = 0x00002718, + .buffer_width_cfg = 0x0000271C, + .buffer_height_cfg = 0x00002720, + .packer_cfg = 0x00002724, + .stride = 0x00002728, + .irq_subsample_period = 0x00002748, + .irq_subsample_pattern = 0x0000274C, + .framedrop_period = 0x00002750, + .framedrop_pattern = 0x00002754, + .frame_inc = 0x00002758, + .burst_limit = 0x0000275C, + .ubwc_regs = NULL, + }, + /* BUS Client 6 */ + { + .status0 = 0x00002800, + .status1 = 0x00002804, + .cfg = 0x00002808, + .header_addr = 0x0000280C, + .header_cfg = 0x00002810, + .image_addr = 0x00002814, + .image_addr_offset = 0x00002818, + .buffer_width_cfg = 0x0000281C, + .buffer_height_cfg = 0x00002820, + .packer_cfg = 0x00002824, + .stride = 0x00002828, + .irq_subsample_period = 0x00002848, + .irq_subsample_pattern = 0x0000284C, + .framedrop_period = 0x00002850, + .framedrop_pattern = 0x00002854, + .frame_inc = 0x00002858, + .burst_limit = 0x0000285C, + .ubwc_regs = NULL, + }, + /* BUS Client 7 */ + { + .status0 = 0x00002900, + .status1 = 0x00002904, + .cfg = 0x00002908, + .header_addr = 0x0000290C, + .header_cfg = 0x00002910, + .image_addr = 0x00002914, + .image_addr_offset = 0x00002918, + .buffer_width_cfg = 0x0000291C, + .buffer_height_cfg = 0x00002920, + .packer_cfg = 0x00002924, + .stride = 0x00002928, + .irq_subsample_period = 0x00002948, + .irq_subsample_pattern = 0x0000294C, + .framedrop_period = 0x00002950, + .framedrop_pattern = 0x00002954, + .frame_inc = 0x00002958, + .burst_limit = 0x0000295C, + .ubwc_regs = NULL, + }, + /* BUS Client 8 */ + { + .status0 = 0x00002A00, + .status1 = 0x00002A04, + .cfg = 0x00002A08, + .header_addr = 0x00002A0C, + .header_cfg = 0x00002A10, + .image_addr = 0x00002A14, + .image_addr_offset = 0x00002A18, + .buffer_width_cfg = 0x00002A1C, + .buffer_height_cfg = 0x00002A20, + .packer_cfg = 0x00002A24, + .stride = 0x00002A28, + .irq_subsample_period = 0x00002A48, + .irq_subsample_pattern = 0x00002A4C, + .framedrop_period = 0x00002A50, + .framedrop_pattern = 0x00002A54, + .frame_inc = 0x00002A58, + .burst_limit = 0x00002A5C, + .ubwc_regs = NULL, + }, + /* BUS Client 9 */ + { + .status0 = 0x00002B00, + .status1 = 0x00002B04, + .cfg = 0x00002B08, + .header_addr = 0x00002B0C, + .header_cfg = 0x00002B10, + .image_addr = 0x00002B14, + .image_addr_offset = 0x00002B18, + .buffer_width_cfg = 0x00002B1C, + .buffer_height_cfg = 0x00002B20, + .packer_cfg = 0x00002B24, + .stride = 0x00002B28, + .irq_subsample_period = 0x00002B48, + .irq_subsample_pattern = 0x00002B4C, + .framedrop_period = 0x00002B50, + .framedrop_pattern = 0x00002B54, + .frame_inc = 0x00002B58, + .burst_limit = 0x00002B5C, + .ubwc_regs = NULL, + }, + /* BUS Client 10 */ + { + .status0 = 0x00002C00, + .status1 = 0x00002C04, + .cfg = 0x00002C08, + .header_addr = 0x00002C0C, + .header_cfg = 0x00002C10, + .image_addr = 0x00002C14, + .image_addr_offset = 0x00002C18, + .buffer_width_cfg = 0x00002C1C, + .buffer_height_cfg = 0x00002C20, + .packer_cfg = 0x00002C24, + .stride = 0x00002C28, + .irq_subsample_period = 0x00002C48, + .irq_subsample_pattern = 0x00002C4C, + .framedrop_period = 0x00002C50, + .framedrop_pattern = 0x00002C54, + .frame_inc = 0x00002C58, + .burst_limit = 0x00002C5C, + .ubwc_regs = NULL, + }, + /* BUS Client 11 */ + { + .status0 = 0x00002D00, + .status1 = 0x00002D04, + .cfg = 0x00002D08, + .header_addr = 0x00002D0C, + .header_cfg = 0x00002D10, + .image_addr = 0x00002D14, + .image_addr_offset = 0x00002D18, + .buffer_width_cfg = 0x00002D1C, + .buffer_height_cfg = 0x00002D20, + .packer_cfg = 0x00002D24, + .stride = 0x00002D28, + .irq_subsample_period = 0x00002D48, + .irq_subsample_pattern = 0x00002D4C, + .framedrop_period = 0x00002D50, + .framedrop_pattern = 0x00002D54, + .frame_inc = 0x00002D58, + .burst_limit = 0x00002D5C, + .ubwc_regs = NULL, + }, + /* BUS Client 12 */ + { + .status0 = 0x00002E00, + .status1 = 0x00002E04, + .cfg = 0x00002E08, + .header_addr = 0x00002E0C, + .header_cfg = 0x00002E10, + .image_addr = 0x00002E14, + .image_addr_offset = 0x00002E18, + .buffer_width_cfg = 0x00002E1C, + .buffer_height_cfg = 0x00002E20, + .packer_cfg = 0x00002E24, + .stride = 0x00002E28, + .irq_subsample_period = 0x00002E48, + .irq_subsample_pattern = 0x00002E4C, + .framedrop_period = 0x00002E50, + .framedrop_pattern = 0x00002E54, + .frame_inc = 0x00002E58, + .burst_limit = 0x00002E5C, + .ubwc_regs = NULL, + }, + /* BUS Client 13 */ + { + .status0 = 0x00002F00, + .status1 = 0x00002F04, + .cfg = 0x00002F08, + .header_addr = 0x00002F0C, + .header_cfg = 0x00002F10, + .image_addr = 0x00002F14, + .image_addr_offset = 0x00002F18, + .buffer_width_cfg = 0x00002F1C, + .buffer_height_cfg = 0x00002F20, + .packer_cfg = 0x00002F24, + .stride = 0x00002F28, + .irq_subsample_period = 0x00002F48, + .irq_subsample_pattern = 0x00002F4C, + .framedrop_period = 0x00002F50, + .framedrop_pattern = 0x00002F54, + .frame_inc = 0x00002F58, + .burst_limit = 0x00002F5C, + .ubwc_regs = NULL, + }, + /* BUS Client 14 */ + { + .status0 = 0x00003000, + .status1 = 0x00003004, + .cfg = 0x00003008, + .header_addr = 0x0000300C, + .header_cfg = 0x00003010, + .image_addr = 0x00003014, + .image_addr_offset = 0x00003018, + .buffer_width_cfg = 0x0000301C, + .buffer_height_cfg = 0x00003020, + .packer_cfg = 0x00003024, + .stride = 0x00003028, + .irq_subsample_period = 0x00003048, + .irq_subsample_pattern = 0x0000304C, + .framedrop_period = 0x00003050, + .framedrop_pattern = 0x00003054, + .frame_inc = 0x00003058, + .burst_limit = 0x0000305C, + .ubwc_regs = NULL, + }, + /* BUS Client 15 */ + { + .status0 = 0x00003100, + .status1 = 0x00003104, + .cfg = 0x00003108, + .header_addr = 0x0000310C, + .header_cfg = 0x00003110, + .image_addr = 0x00003114, + .image_addr_offset = 0x00003118, + .buffer_width_cfg = 0x0000311C, + .buffer_height_cfg = 0x00003120, + .packer_cfg = 0x00003124, + .stride = 0x00003128, + .irq_subsample_period = 0x00003148, + .irq_subsample_pattern = 0x0000314C, + .framedrop_period = 0x00003150, + .framedrop_pattern = 0x00003154, + .frame_inc = 0x00003158, + .burst_limit = 0x0000315C, + .ubwc_regs = NULL, + }, + /* BUS Client 16 */ + { + .status0 = 0x00003200, + .status1 = 0x00003204, + .cfg = 0x00003208, + .header_addr = 0x0000320C, + .header_cfg = 0x00003210, + .image_addr = 0x00003214, + .image_addr_offset = 0x00003218, + .buffer_width_cfg = 0x0000321C, + .buffer_height_cfg = 0x00003220, + .packer_cfg = 0x00003224, + .stride = 0x00003228, + .irq_subsample_period = 0x00003248, + .irq_subsample_pattern = 0x0000324C, + .framedrop_period = 0x00003250, + .framedrop_pattern = 0x00003254, + .frame_inc = 0x00003258, + .burst_limit = 0x0000325C, + .ubwc_regs = NULL, + }, + /* BUS Client 17 */ + { + .status0 = 0x00003300, + .status1 = 0x00003304, + .cfg = 0x00003308, + .header_addr = 0x0000330C, + .header_cfg = 0x00003310, + .image_addr = 0x00003314, + .image_addr_offset = 0x00003318, + .buffer_width_cfg = 0x0000331C, + .buffer_height_cfg = 0x00003320, + .packer_cfg = 0x00003324, + .stride = 0x00003328, + .irq_subsample_period = 0x00003348, + .irq_subsample_pattern = 0x0000334C, + .framedrop_period = 0x00003350, + .framedrop_pattern = 0x00003354, + .frame_inc = 0x00003358, + .burst_limit = 0x0000335C, + .ubwc_regs = NULL, + }, + /* BUS Client 18 */ + { + .status0 = 0x00003400, + .status1 = 0x00003404, + .cfg = 0x00003408, + .header_addr = 0x0000340C, + .header_cfg = 0x00003410, + .image_addr = 0x00003414, + .image_addr_offset = 0x00003418, + .buffer_width_cfg = 0x0000341C, + .buffer_height_cfg = 0x00003420, + .packer_cfg = 0x00003424, + .stride = 0x00003428, + .irq_subsample_period = 0x00003448, + .irq_subsample_pattern = 0x0000344C, + .framedrop_period = 0x00003450, + .framedrop_pattern = 0x00003454, + .frame_inc = 0x00003458, + .burst_limit = 0x0000345C, + .ubwc_regs = NULL, + }, + /* BUS Client 19 */ + { + .status0 = 0x00003500, + .status1 = 0x00003504, + .cfg = 0x00003508, + .header_addr = 0x0000350C, + .header_cfg = 0x00003510, + .image_addr = 0x00003514, + .image_addr_offset = 0x00003518, + .buffer_width_cfg = 0x0000351C, + .buffer_height_cfg = 0x00003520, + .packer_cfg = 0x00003524, + .stride = 0x00003528, + .irq_subsample_period = 0x00003548, + .irq_subsample_pattern = 0x0000354C, + .framedrop_period = 0x00003550, + .framedrop_pattern = 0x00003554, + .frame_inc = 0x00003558, + .burst_limit = 0x0000355C, + .ubwc_regs = NULL, + }, + /* BUS Client 20 */ + { + .status0 = 0x00003600, + .status1 = 0x00003604, + .cfg = 0x00003608, + .header_addr = 0x0000360C, + .header_cfg = 0x00003610, + .image_addr = 0x00003614, + .image_addr_offset = 0x00003618, + .buffer_width_cfg = 0x0000361C, + .buffer_height_cfg = 0x00003620, + .packer_cfg = 0x00003624, + .stride = 0x00003628, + .irq_subsample_period = 0x00003648, + .irq_subsample_pattern = 0x0000364C, + .framedrop_period = 0x00003650, + .framedrop_pattern = 0x00003654, + .frame_inc = 0x00003658, + .burst_limit = 0x0000365C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_20, + }, + /* BUS Client 21 */ + { + .status0 = 0x00003700, + .status1 = 0x00003704, + .cfg = 0x00003708, + .header_addr = 0x0000370C, + .header_cfg = 0x00003710, + .image_addr = 0x00003714, + .image_addr_offset = 0x00003718, + .buffer_width_cfg = 0x0000371C, + .buffer_height_cfg = 0x00003720, + .packer_cfg = 0x00003724, + .stride = 0x00003728, + .irq_subsample_period = 0x00003748, + .irq_subsample_pattern = 0x0000374C, + .framedrop_period = 0x00003750, + .framedrop_pattern = 0x00003754, + .frame_inc = 0x00003758, + .burst_limit = 0x0000375C, + .ubwc_regs = + &vfe175_130_ubwc_regs_client_21, + }, + /* BUS Client 22 */ + { + .status0 = 0x00003800, + .status1 = 0x00003804, + .cfg = 0x00003808, + .header_addr = 0x0000380C, + .header_cfg = 0x00003810, + .image_addr = 0x00003814, + .image_addr_offset = 0x00003818, + .buffer_width_cfg = 0x0000381C, + .buffer_height_cfg = 0x00003820, + .packer_cfg = 0x00003824, + .stride = 0x00003828, + .irq_subsample_period = 0x00003848, + .irq_subsample_pattern = 0x0000384C, + .framedrop_period = 0x00003850, + .framedrop_pattern = 0x00003854, + .frame_inc = 0x00003858, + .burst_limit = 0x0000385C, + .ubwc_regs = NULL, + }, + /* BUS Client 23 */ + { + .status0 = 0x00003900, + .status1 = 0x00003904, + .cfg = 0x00003908, + .header_addr = 0x0000390C, + .header_cfg = 0x00003910, + .image_addr = 0x00003914, + .image_addr_offset = 0x00003918, + .buffer_width_cfg = 0x0000391C, + .buffer_height_cfg = 0x00003920, + .packer_cfg = 0x00003924, + .stride = 0x00003928, + .irq_subsample_period = 0x00003948, + .irq_subsample_pattern = 0x0000394C, + .framedrop_period = 0x00003950, + .framedrop_pattern = 0x00003954, + .frame_inc = 0x00003958, + .burst_limit = 0x0000395C, + .ubwc_regs = NULL, + }, + }, + .comp_grp_reg = { + /* CAM_VFE_BUS_VER2_COMP_GRP_0 */ + { + .comp_mask = 0x00002010, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_1 */ + { + .comp_mask = 0x00002014, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_2 */ + { + .comp_mask = 0x00002018, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_3 */ + { + .comp_mask = 0x0000201C, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_4 */ + { + .comp_mask = 0x00002020, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_5 */ + { + .comp_mask = 0x00002024, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_0 */ + { + .comp_mask = 0x0000202C, + .addr_sync_mask = 0x00002088, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_1 */ + { + .comp_mask = 0x00002030, + .addr_sync_mask = 0x0000208C, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_2 */ + { + .comp_mask = 0x00002034, + .addr_sync_mask = 0x00002090, + + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_3 */ + { + .comp_mask = 0x00002038, + .addr_sync_mask = 0x00002094, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_4 */ + { + .comp_mask = 0x0000203C, + .addr_sync_mask = 0x00002098, + }, + /* CAM_VFE_BUS_VER2_COMP_GRP_DUAL_5 */ + { + .comp_mask = 0x00002040, + .addr_sync_mask = 0x0000209C, + }, + }, + .num_out = 22, + .vfe_out_hw_info = { + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI0, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI1, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RDI2, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_RAW_DUMP, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FD, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_PDAF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BE, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_HDR_BHIST, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_TL_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BF, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_AWB_BG, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_BHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_RS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_CS, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = + CAM_VFE_BUS_VER2_VFE_OUT_STATS_IHIST, + .max_width = -1, + .max_height = -1, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_FULL_DISP, + .max_width = 4096, + .max_height = 4096, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS4_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_DS16_DISP, + .max_width = 1920, + .max_height = 1080, + }, + { + .vfe_out_type = CAM_VFE_BUS_VER2_VFE_OUT_2PD, + .max_width = 1920, + .max_height = 1080, + }, + }, + .reg_data = { + .ubwc_10bit_threshold_lossy_0 = 0x8330002, + .ubwc_10bit_threshold_lossy_1 = 0x20204, + .ubwc_8bit_threshold_lossy_0 = 0x6210022, + .ubwc_8bit_threshold_lossy_1 = 0xE0E, + }, +}; + +struct cam_vfe_hw_info cam_vfe175_130_hw_info = { + .irq_reg_info = &vfe175_130_top_irq_reg_info, + + .bus_version = CAM_VFE_BUS_VER_2_0, + .bus_hw_info = &vfe175_130_bus_hw_info, + + .bus_rd_version = CAM_VFE_BUS_VER_2_0, + .bus_rd_hw_info = &vfe175_130_bus_rd_hw_info, + + .top_version = CAM_VFE_TOP_VER_2_0, + .top_hw_info = &vfe175_130_top_hw_info, + + .camif_version = CAM_VFE_CAMIF_VER_2_0, + .camif_reg = &vfe175_130_camif_reg, + + .camif_lite_version = CAM_VFE_CAMIF_LITE_VER_2_0, + .camif_lite_reg = &vfe175_130_camif_lite_reg, + +}; + +#endif /* _CAM_VFE175_130_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c index 6ec5ffbde4e0..2e11dc40d5a3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe17x/cam_vfe17x.c @@ -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 @@ -12,6 +12,8 @@ #include <linux/module.h> #include "cam_vfe170.h" +#include "cam_vfe175.h" +#include "cam_vfe175_130.h" #include "cam_vfe_lite17x.h" #include "cam_vfe_hw_intf.h" #include "cam_vfe_core.h" @@ -23,9 +25,21 @@ static const struct of_device_id cam_vfe_dt_match[] = { .data = &cam_vfe170_hw_info, }, { + .compatible = "qcom,vfe175", + .data = &cam_vfe175_hw_info, + }, + { + .compatible = "qcom,vfe175_130", + .data = &cam_vfe175_130_hw_info, + }, + { .compatible = "qcom,vfe-lite170", .data = &cam_vfe_lite17x_hw_info, }, + { + .compatible = "qcom,vfe-lite175", + .data = &cam_vfe_lite17x_hw_info, + }, {} }; MODULE_DEVICE_TABLE(of, cam_vfe_dt_match); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile index 1823497221ba..d8db0b56a0ee 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -11,4 +11,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vf ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include -obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o cam_vfe_bus_rd_ver1.o diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c index 4c0c147f4122..b0495922a90d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c @@ -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 @@ -13,9 +13,11 @@ #include "cam_vfe_bus.h" #include "cam_vfe_bus_ver1.h" #include "cam_vfe_bus_ver2.h" +#include "cam_vfe_bus_rd_ver1.h" #include "cam_debug_util.h" int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, struct cam_hw_soc_info *soc_info, struct cam_hw_intf *hw_intf, void *bus_hw_info, @@ -24,10 +26,16 @@ int cam_vfe_bus_init(uint32_t bus_version, { 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); + switch (bus_type) { + case BUS_TYPE_WR: + if (CAM_VFE_BUS_VER_2_0) + rc = cam_vfe_bus_ver2_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); + break; + case BUS_TYPE_RD: + /* Call vfe bus rd init function */ + rc = cam_vfe_bus_rd_ver1_init(soc_info, hw_intf, + bus_hw_info, vfe_irq_controller, vfe_bus); break; default: CAM_ERR(CAM_ISP, "Unsupported Bus Version %x", bus_version); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c new file mode 100644 index 000000000000..00cc40158fd4 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.c @@ -0,0 +1,1232 @@ +/* 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 <linux/ratelimit.h> +#include <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_hw_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_vfe_hw_intf.h" +#include "cam_irq_controller.h" +#include "cam_tasklet_util.h" +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_rd_ver1.h" +#include "cam_vfe_core.h" +#include "cam_debug_util.h" +#include "cam_cpas_api.h" + +static const char drv_name[] = "vfe_bus_rd"; + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +#define MAX_BUF_UPDATE_REG_NUM \ + (sizeof(struct cam_vfe_bus_rd_ver1_reg_offset_bus_client)/4) + +#define MAX_REG_VAL_PAIR_SIZE \ + (MAX_BUF_UPDATE_REG_NUM * 2 * CAM_PACKET_MAX_PLANES) + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[(index)++] = offset; \ + buf_array[(index)++] = val; \ + } while (0) + +enum cam_vfe_bus_rd_ver1_unpacker_format { + BUS_RD_VER1_PACKER_FMT_PLAIN_128 = 0x0, + BUS_RD_VER1_PACKER_FMT_PLAIN_8 = 0x1, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_10BPP = 0x2, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_12BPP = 0x3, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_14BPP = 0x4, + BUS_RD_VER1_PACKER_FMT_PLAIN_16_16BPP = 0x5, + BUS_RD_VER1_PACKER_FMT_ARGB_10 = 0x6, + BUS_RD_VER1_PACKER_FMT_ARGB_12 = 0x7, + BUS_RD_VER1_PACKER_FMT_ARGB_14 = 0x8, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_20BPP = 0x9, + BUS_RD_VER1_PACKER_FMT_PLAIN_64 = 0xA, + BUS_RD_VER1_PACKER_FMT_TP_10 = 0xB, + BUS_RD_VER1_PACKER_FMT_PLAIN_32_32BPP = 0xC, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN = 0xD, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10 = 0xE, + BUS_RD_VER1_PACKER_FMT_PLAIN_8_LSB_MSB_10_ODD_EVEN = 0xF, + BUS_RD_VER1_PACKER_FMT_MAX = 0xF, +}; + +struct cam_vfe_bus_rd_ver1_common_data { + uint32_t core_index; + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + void *bus_irq_controller; + void *vfe_irq_controller; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + uint32_t io_buf_update[ + MAX_REG_VAL_PAIR_SIZE]; + + struct list_head free_payload_list; + spinlock_t spin_lock; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t fs_sync_enable; + uint32_t go_cmd_sel; +}; + +struct cam_vfe_bus_rd_ver1_rm_resource_data { + uint32_t index; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client *hw_regs; + void *ctx; + + uint32_t irq_enabled; + uint32_t offset; + + uint32_t min_vbi; + uint32_t fs_mode; + uint32_t hbi_count; + uint32_t width; + uint32_t height; + uint32_t stride; + uint32_t format; + uint32_t latency_buf_allocation; + uint32_t unpacker_cfg; + uint32_t burst_len; + + uint32_t go_cmd_sel; + uint32_t fs_sync_enable; + uint32_t fs_line_sync_en; + + uint32_t en_cfg; + uint32_t is_dual; + uint32_t img_addr; + uint32_t input_if_cmd; +}; + +struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data { + uint32_t bus_rd_type; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + + uint32_t num_rm; + struct cam_isp_resource_node *rm_res[PLANE_MAX]; + + struct cam_isp_resource_node *comp_grp; + enum cam_isp_hw_sync_mode dual_comp_sync_mode; + uint32_t dual_hw_alternate_vfe_id; + struct list_head vfe_bus_rd_list; + + uint32_t format; + uint32_t max_width; + uint32_t max_height; + struct cam_cdm_utils_ops *cdm_util_ops; + uint32_t secure_mode; +}; + +struct cam_vfe_bus_rd_ver1_priv { + struct cam_vfe_bus_rd_ver1_common_data common_data; + uint32_t num_client; + uint32_t num_bus_rd_resc; + + struct cam_isp_resource_node bus_client[ + CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + struct cam_isp_resource_node vfe_bus_rd[ + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; + + 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 enum cam_vfe_bus_rd_ver1_unpacker_format + cam_vfe_bus_get_unpacker_fmt(uint32_t unpack_fmt) +{ + switch (unpack_fmt) { + case CAM_FORMAT_MIPI_RAW_10: + return BUS_RD_VER1_PACKER_FMT_PLAIN_8_ODD_EVEN; + default: + return BUS_RD_VER1_PACKER_FMT_MAX; + } +} + +static bool cam_vfe_bus_can_be_secure(uint32_t out_type) +{ + switch (out_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return false; + + default: + return false; + } +} + +static enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type + cam_vfe_bus_get_bus_rd_res_id(uint32_t res_type) +{ + switch (res_type) { + case CAM_ISP_RESOURCE_VFE_BUS_RD: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0; + default: + return CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + } +} + +static int cam_vfe_bus_get_num_rm( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type res_type) +{ + switch (res_type) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + return 1; + default: + break; + } + + CAM_ERR(CAM_ISP, "Unsupported resource_type %u", + res_type); + return -EINVAL; +} + +static int cam_vfe_bus_get_rm_idx( + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane) +{ + int rm_idx = -1; + + switch (vfe_bus_rd_res_id) { + case CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0: + switch (plane) { + case PLANE_Y: + rm_idx = 0; + break; + default: + break; + } + break; + default: + break; + } + + return rm_idx; +} + +static int cam_vfe_bus_acquire_rm( + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_isp_out_port_info *out_port_info, + void *tasklet, + void *ctx, + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_res_id, + enum cam_vfe_bus_plane_type plane, + uint32_t subscribe_irq, + struct cam_isp_resource_node **rm_res, + uint32_t *client_done_mask, + uint32_t is_dual) +{ + uint32_t rm_idx = 0; + struct cam_isp_resource_node *rm_res_local = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = NULL; + + *rm_res = NULL; + *client_done_mask = 0; + + /* No need to allocate for BUS VER2. VFE OUT to RM is fixed. */ + rm_idx = cam_vfe_bus_get_rm_idx(vfe_bus_rd_res_id, plane); + if (rm_idx < 0 || rm_idx >= ver1_bus_rd_priv->num_client) { + CAM_ERR(CAM_ISP, "Unsupported VFE out %d plane %d", + vfe_bus_rd_res_id, plane); + return -EINVAL; + } + + rm_res_local = &ver1_bus_rd_priv->bus_client[rm_idx]; + if (rm_res_local->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "RM res not available state:%d", + rm_res_local->res_state); + return -EALREADY; + } + rm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + rm_res_local->tasklet_info = tasklet; + + rsrc_data = rm_res_local->res_priv; + rsrc_data->irq_enabled = subscribe_irq; + rsrc_data->ctx = ctx; + rsrc_data->is_dual = is_dual; + /* Set RM offset value to default */ + rsrc_data->offset = 0; + + *client_done_mask = (1 << rm_idx); + *rm_res = rm_res_local; + + CAM_DBG(CAM_ISP, "RM %d: Acquired"); + return 0; +} + +static int cam_vfe_bus_release_rm(void *bus_priv, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + + rsrc_data->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->unpacker_cfg = 0; + rsrc_data->burst_len = 0; + rsrc_data->en_cfg = 0; + rsrc_data->is_dual = 0; + + rm_res->tasklet_info = NULL; + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rm_data->common_data; + uint32_t buf_size; + uint32_t val; + uint32_t offset; + + CAM_DBG(CAM_ISP, "w: 0x%x", rm_data->width); + CAM_DBG(CAM_ISP, "h: 0x%x", rm_data->height); + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", rm_data->fs_sync_enable); + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", rm_data->fs_line_sync_en); + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + + /* Write All the values*/ + offset = rm_data->hw_regs->buffer_width_cfg; + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + cam_io_w_mb(buf_size, common_data->mem_base + offset); + CAM_DBG(CAM_ISP, "buf_size: 0x%x", buf_size); + + val = rm_data->width; + offset = rm_data->hw_regs->stride; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + CAM_DBG(CAM_ISP, "rm_data->unpacker_cfg:0x%x", rm_data->unpacker_cfg); + val = cam_vfe_bus_get_unpacker_fmt(rm_data->unpacker_cfg); + CAM_DBG(CAM_ISP, " value:0x%x", val); + offset = rm_data->hw_regs->unpacker_cfg; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + val = rm_data->latency_buf_allocation; + offset = rm_data->hw_regs->latency_buf_allocation; + CAM_DBG(CAM_ISP, "offset:0x%x, value:0x%x", offset, val); + cam_io_w_mb(val, common_data->mem_base + offset); + + cam_io_w_mb(0x1, common_data->mem_base + + rm_data->hw_regs->cfg); + return rc; +} + +static int cam_vfe_bus_stop_rm(struct cam_isp_resource_node *rm_res) +{ + int rc = 0; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data = + rm_res->res_priv; + struct cam_vfe_bus_rd_ver1_common_data *common_data = + rsrc_data->common_data; + + /* Disable RM */ + cam_io_w_mb(0x0, + common_data->mem_base + rsrc_data->hw_regs->cfg); + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_bus_init_rm_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info, + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_rm_resource_data), + GFP_KERNEL); + if (!rsrc_data) { + CAM_DBG(CAM_ISP, "Failed to alloc for RM res priv"); + return -ENOMEM; + } + rm_res->res_priv = rsrc_data; + + rsrc_data->index = index; + rsrc_data->hw_regs = &bus_rd_hw_info->bus_client_reg[index]; + rsrc_data->common_data = &ver1_bus_rd_priv->common_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = cam_vfe_bus_start_rm; + rm_res->stop = cam_vfe_bus_stop_rm; + rm_res->hw_intf = ver1_bus_rd_priv->common_data.hw_intf; + + + return 0; +} + +static int cam_vfe_bus_deinit_rm_resource( + struct cam_isp_resource_node *rm_res) +{ + struct cam_vfe_bus_rd_ver1_rm_resource_data *rsrc_data; + + rm_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&rm_res->list); + + rm_res->start = NULL; + rm_res->stop = NULL; + rm_res->top_half_handler = NULL; + rm_res->bottom_half_handler = NULL; + rm_res->hw_intf = NULL; + + rsrc_data = rm_res->res_priv; + rm_res->res_priv = NULL; + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_get_secure_mode(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_acquire_vfe_bus_rd(void *bus_priv, void *acquire_args, + uint32_t args_size) +{ + int rc = -ENODEV; + int i; + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type bus_rd_res_id; + int num_rm; + uint32_t subscribe_irq; + uint32_t client_done_mask; + struct cam_vfe_bus_rd_ver1_priv *ver1_bus_rd_priv = + bus_priv; + struct cam_vfe_acquire_args *acq_args = acquire_args; + struct cam_vfe_hw_vfe_out_acquire_args *bus_rd_acquire_args; + struct cam_isp_resource_node *rsrc_node = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0, mode; + + if (!bus_priv || !acquire_args) { + CAM_ERR(CAM_ISP, "Invalid Param"); + return -EINVAL; + } + + bus_rd_acquire_args = &acq_args->vfe_bus_rd; + + CAM_DBG(CAM_ISP, "Acquiring resource type 0x%x", + acq_args->rsrc_type); + + bus_rd_res_id = cam_vfe_bus_get_bus_rd_res_id( + acq_args->rsrc_type); + if (bus_rd_res_id == CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX) + return -ENODEV; + + num_rm = cam_vfe_bus_get_num_rm(bus_rd_res_id); + if (num_rm < 1) + return -EINVAL; + + rsrc_node = &ver1_bus_rd_priv->vfe_bus_rd[bus_rd_res_id]; + if (rsrc_node->res_state != CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, "Resource not available: Res_id %d state:%d", + bus_rd_res_id, rsrc_node->res_state); + return -EBUSY; + } + + rsrc_data = rsrc_node->res_priv; + secure_caps = cam_vfe_bus_can_be_secure( + rsrc_data->bus_rd_type); + + mode = bus_rd_acquire_args->out_port_info->secure_mode; + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (!rsrc_data->common_data->num_sec_out) { + rsrc_data->secure_mode = mode; + rsrc_data->common_data->secure_mode = mode; + } else { + if (mode == rsrc_data->common_data->secure_mode) { + rsrc_data->secure_mode = + rsrc_data->common_data->secure_mode; + } else { + rc = -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Mismatch: Acquire mode[%d], drvr mode[%d]", + rsrc_data->common_data->secure_mode, + mode); + mutex_unlock( + &rsrc_data->common_data->bus_mutex); + return -EINVAL; + } + } + rsrc_data->common_data->num_sec_out++; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + rsrc_data->num_rm = num_rm; + rsrc_node->tasklet_info = acq_args->tasklet; + rsrc_node->cdm_ops = bus_rd_acquire_args->cdm_ops; + rsrc_data->cdm_util_ops = bus_rd_acquire_args->cdm_ops; + + subscribe_irq = 1; + + for (i = 0; i < num_rm; i++) { + rc = cam_vfe_bus_acquire_rm(ver1_bus_rd_priv, + bus_rd_acquire_args->out_port_info, + acq_args->tasklet, + bus_rd_acquire_args->ctx, + bus_rd_res_id, + i, + subscribe_irq, + &rsrc_data->rm_res[i], + &client_done_mask, + bus_rd_acquire_args->is_dual); + if (rc) { + CAM_ERR(CAM_ISP, + "VFE%d RM acquire failed for Out %d rc=%d", + rsrc_data->common_data->core_index, + bus_rd_res_id, rc); + goto release_rm; + } + } + + rsrc_node->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + bus_rd_acquire_args->rsrc_node = rsrc_node; + + CAM_DBG(CAM_ISP, "Acquire successful"); + return rc; + +release_rm: + for (i--; i >= 0; i--) + cam_vfe_bus_release_rm(ver1_bus_rd_priv, rsrc_data->rm_res[i]); + return rc; +} + +static int cam_vfe_bus_release_vfe_bus_rd(void *bus_priv, void *release_args, + uint32_t args_size) +{ + uint32_t i; + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + uint32_t secure_caps = 0; + + if (!bus_priv || !release_args) { + CAM_ERR(CAM_ISP, "Invalid input bus_priv %pK release_args %pK", + bus_priv, release_args); + return -EINVAL; + } + + vfe_bus_rd = release_args; + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_bus_rd->res_state); + } + + for (i = 0; i < rsrc_data->num_rm; i++) + cam_vfe_bus_release_rm(bus_priv, rsrc_data->rm_res[i]); + rsrc_data->num_rm = 0; + + vfe_bus_rd->tasklet_info = NULL; + vfe_bus_rd->cdm_ops = NULL; + rsrc_data->cdm_util_ops = NULL; + + secure_caps = cam_vfe_bus_can_be_secure(rsrc_data->bus_rd_type); + mutex_lock(&rsrc_data->common_data->bus_mutex); + if (secure_caps) { + if (rsrc_data->secure_mode == + rsrc_data->common_data->secure_mode) { + rsrc_data->common_data->num_sec_out--; + rsrc_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } else { + /* + * The validity of the mode is properly + * checked while acquiring the output port. + * not expected to reach here, unless there is + * some corruption. + */ + CAM_ERR(CAM_ISP, "driver[%d],resource[%d] mismatch", + rsrc_data->common_data->secure_mode, + rsrc_data->secure_mode); + } + + if (!rsrc_data->common_data->num_sec_out) + rsrc_data->common_data->secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + mutex_unlock(&rsrc_data->common_data->bus_mutex); + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + + return 0; +} + +static int cam_vfe_bus_start_vfe_bus_rd( + struct cam_isp_resource_node *vfe_out) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + struct cam_vfe_bus_rd_ver1_common_data *common_data = NULL; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + common_data = rsrc_data->common_data; + + CAM_DBG(CAM_ISP, "Start resource type: %x", rsrc_data->bus_rd_type); + + if (vfe_out->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Invalid resource state:%d", + vfe_out->res_state); + return -EACCES; + } + + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_start_rm(rsrc_data->rm_res[i]); + vfe_out->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + return rc; +} + +static int cam_vfe_bus_stop_vfe_bus_rd( + struct cam_isp_resource_node *vfe_bus_rd) +{ + int rc = 0, i; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + + CAM_DBG(CAM_ISP, "E:Stop rd Res"); + if (!vfe_bus_rd) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_bus_rd->res_priv; + + if (vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE || + vfe_bus_rd->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, "vfe_out res_state is %d", + vfe_bus_rd->res_state); + return rc; + } + for (i = 0; i < rsrc_data->num_rm; i++) + rc = cam_vfe_bus_stop_rm(rsrc_data->rm_res[i]); + + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_vfe_bus_init_vfe_bus_read_resource(uint32_t index, + struct cam_vfe_bus_rd_ver1_priv *bus_rd_priv, + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info) +{ + struct cam_isp_resource_node *vfe_bus_rd = NULL; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *rsrc_data = NULL; + int rc = 0; + int32_t vfe_bus_rd_resc_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + + if (vfe_bus_rd_resc_type < 0 || + vfe_bus_rd_resc_type > CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed, Invalid type=%d", + vfe_bus_rd_resc_type); + return -EINVAL; + } + + vfe_bus_rd = &bus_rd_priv->vfe_bus_rd[vfe_bus_rd_resc_type]; + if (vfe_bus_rd->res_state != CAM_ISP_RESOURCE_STATE_UNAVAILABLE || + vfe_bus_rd->res_priv) { + CAM_ERR(CAM_ISP, + "Error. Looks like same resource is init again"); + return -EFAULT; + } + + rsrc_data = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data), + GFP_KERNEL); + if (!rsrc_data) { + rc = -ENOMEM; + return rc; + } + + vfe_bus_rd->res_priv = rsrc_data; + + vfe_bus_rd->res_type = CAM_ISP_RESOURCE_VFE_BUS_RD; + vfe_bus_rd->res_state = CAM_ISP_RESOURCE_STATE_AVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd->list); + + rsrc_data->bus_rd_type = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].vfe_bus_rd_type; + rsrc_data->common_data = &bus_rd_priv->common_data; + rsrc_data->max_width = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_width; + rsrc_data->max_height = + bus_rd_hw_info->vfe_bus_rd_hw_info[index].max_height; + rsrc_data->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + vfe_bus_rd->start = cam_vfe_bus_start_vfe_bus_rd; + vfe_bus_rd->stop = cam_vfe_bus_stop_vfe_bus_rd; + vfe_bus_rd->process_cmd = cam_vfe_bus_process_cmd; + vfe_bus_rd->hw_intf = bus_rd_priv->common_data.hw_intf; + + return 0; +} + +static int cam_vfe_bus_deinit_vfe_bus_rd_resource( + struct cam_isp_resource_node *vfe_bus_rd_res) +{ + struct cam_vfe_bus_ver2_vfe_out_data *rsrc_data = + vfe_bus_rd_res->res_priv; + + if (vfe_bus_rd_res->res_state == CAM_ISP_RESOURCE_STATE_UNAVAILABLE) { + /* + * This is not error. It can happen if the resource is + * never supported in the HW. + */ + CAM_DBG(CAM_ISP, "HW%d Res %d already deinitialized"); + return 0; + } + + vfe_bus_rd_res->start = NULL; + vfe_bus_rd_res->stop = NULL; + vfe_bus_rd_res->top_half_handler = NULL; + vfe_bus_rd_res->bottom_half_handler = NULL; + vfe_bus_rd_res->hw_intf = NULL; + + vfe_bus_rd_res->res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + INIT_LIST_HEAD(&vfe_bus_rd_res->list); + vfe_bus_rd_res->res_priv = NULL; + + if (!rsrc_data) + return -ENOMEM; + kfree(rsrc_data); + + return 0; +} + +static int cam_vfe_bus_rd_ver1_handle_irq(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + + bus_priv = th_payload->handler_priv; + CAM_DBG(CAM_ISP, "BUS READ IRQ Received"); + return 0; +} + +static int cam_vfe_bus_rd_update_rm(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_isp_hw_get_cmd_update *update_buf; + struct cam_buf_io_cfg *io_cfg; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + uint32_t val; + uint32_t buf_size = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + update_buf = (struct cam_isp_hw_get_cmd_update *) cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + update_buf->res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "#of RM: %d", vfe_bus_rd_data->num_rm); + if (update_buf->rm_update->num_buf != vfe_bus_rd_data->num_rm) { + CAM_ERR(CAM_ISP, + "Failed! Invalid number buffers:%d required:%d", + update_buf->rm_update->num_buf, + vfe_bus_rd_data->num_rm); + return -EINVAL; + } + + reg_val_pair = &vfe_bus_rd_data->common_data->io_buf_update[0]; + io_cfg = update_buf->rm_update->io_cfg; + + for (i = 0, j = 0; i < vfe_bus_rd_data->num_rm; i++) { + if (j >= (MAX_REG_VAL_PAIR_SIZE - MAX_BUF_UPDATE_REG_NUM * 2)) { + CAM_ERR(CAM_ISP, + "reg_val_pair %d exceeds the array limit %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + + /* update size register */ + rm_data->width = io_cfg->planes[i].width; + rm_data->height = io_cfg->planes[i].height; + CAM_DBG(CAM_ISP, "RM %d image w 0x%x h 0x%x image size 0x%x", + rm_data->index, rm_data->width, rm_data->height, + buf_size); + + buf_size = ((rm_data->width)&(0x0000FFFF)) | + ((rm_data->height<<16)&(0xFFFF0000)); + + CAM_DBG(CAM_ISP, "size offset 0x%x buf_size 0x%x", + rm_data->hw_regs->buf_size, buf_size); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->buffer_width_cfg, + buf_size); + CAM_DBG(CAM_ISP, "RM %d image size 0x%x", + rm_data->index, reg_val_pair[j-1]); + + val = rm_data->width; + CAM_DBG(CAM_ISP, "io_cfg stride 0x%x", val); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->stride, + val); + rm_data->stride = val; + CAM_DBG(CAM_ISP, "RM %d image stride 0x%x", + rm_data->index, reg_val_pair[j-1]); + + /* RM Image address */ + CAM_DBG(CAM_ISP, "image_addr offset %x", + rm_data->hw_regs->image_addr); + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + rm_data->hw_regs->image_addr, + update_buf->rm_update->image_buf[i] + + rm_data->offset); + CAM_DBG(CAM_ISP, "RM %d image address 0x%x", + rm_data->index, reg_val_pair[j-1]); + rm_data->img_addr = reg_val_pair[j-1]; + + } + + size = vfe_bus_rd_data->cdm_util_ops->cdm_required_size_reg_random(j/2); + + /* cdm util returns dwords, need to convert to bytes */ + if ((size * 4) > update_buf->cmd.size) { + CAM_ERR(CAM_ISP, + "Failed! Buf size:%d insufficient, expected size:%d", + update_buf->cmd.size, size); + return -ENOMEM; + } + + vfe_bus_rd_data->cdm_util_ops->cdm_write_regrandom( + update_buf->cmd.cmd_buf_addr, j/2, reg_val_pair); + + /* cdm util returns dwords, need to convert to bytes */ + update_buf->cmd.used_bytes = size * 4; + + return 0; +} + +static int cam_vfe_bus_rd_update_hfr(void *priv, void *cmd_args, + uint32_t arg_size) +{ + return 0; +} + +static int cam_vfe_bus_rd_update_fs_cfg(void *priv, void *cmd_args, + uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv; + struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *vfe_bus_rd_data = NULL; + struct cam_vfe_bus_rd_ver1_rm_resource_data *rm_data = NULL; + struct cam_vfe_fe_update_args *fe_upd_args; + struct cam_fe_config *fe_cfg; + struct cam_vfe_bus_rd_ver1_common_data *common_data; + int i = 0; + + bus_priv = (struct cam_vfe_bus_rd_ver1_priv *) priv; + fe_upd_args = (struct cam_vfe_fe_update_args *)cmd_args; + + vfe_bus_rd_data = (struct cam_vfe_bus_rd_ver1_vfe_bus_rd_data *) + fe_upd_args->node_res->res_priv; + + if (!vfe_bus_rd_data || !vfe_bus_rd_data->cdm_util_ops) { + CAM_ERR(CAM_ISP, "Failed! Invalid data"); + return -EINVAL; + } + + fe_cfg = &fe_upd_args->fe_config; + + for (i = 0; i < vfe_bus_rd_data->num_rm; i++) { + + rm_data = vfe_bus_rd_data->rm_res[i]->res_priv; + common_data = rm_data->common_data; + + rm_data->format = fe_cfg->format; + CAM_DBG(CAM_ISP, "format: 0x%x", rm_data->format); + + rm_data->unpacker_cfg = fe_cfg->unpacker_cfg; + CAM_DBG(CAM_ISP, "unpacker_cfg: 0x%x", rm_data->unpacker_cfg); + + rm_data->latency_buf_allocation = fe_cfg->latency_buf_size; + CAM_DBG(CAM_ISP, "latency_buf_allocation: 0x%x", + rm_data->latency_buf_allocation); + + rm_data->stride = fe_cfg->stride; + CAM_DBG(CAM_ISP, "stride: 0x%x", rm_data->stride); + + rm_data->go_cmd_sel = fe_cfg->go_cmd_sel; + CAM_DBG(CAM_ISP, "go_cmd_sel: 0x%x", rm_data->go_cmd_sel); + + rm_data->fs_sync_enable = fe_cfg->fs_sync_enable; + CAM_DBG(CAM_ISP, "fs_sync_enable: 0x%x", + rm_data->fs_sync_enable); + + rm_data->hbi_count = fe_cfg->hbi_count; + CAM_DBG(CAM_ISP, "hbi_count: 0x%x", rm_data->hbi_count); + + rm_data->fs_line_sync_en = fe_cfg->fs_line_sync_en; + CAM_DBG(CAM_ISP, "fs_line_sync_en: 0x%x", + rm_data->fs_line_sync_en); + + rm_data->fs_mode = fe_cfg->fs_mode; + CAM_DBG(CAM_ISP, "fs_mode: 0x%x", rm_data->fs_mode); + + rm_data->min_vbi = fe_cfg->min_vbi; + CAM_DBG(CAM_ISP, "min_vbi: 0x%x", rm_data->min_vbi); + } + bus_priv->common_data.fs_sync_enable = fe_cfg->fs_sync_enable; + bus_priv->common_data.go_cmd_sel = fe_cfg->go_cmd_sel; + return 0; +} + +static int cam_vfe_bus_start_hw(void *hw_priv, + void *start_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_start_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_stop_hw(void *hw_priv, + void *stop_hw_args, uint32_t arg_size) +{ + return cam_vfe_bus_stop_vfe_bus_rd(hw_priv); +} + +static int cam_vfe_bus_init_hw(void *hw_priv, + void *init_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + uint32_t top_irq_reg_mask[2] = {0}; + uint32_t offset = 0, val = 0; + struct cam_vfe_bus_rd_ver1_reg_offset_common *common_reg; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + common_reg = bus_priv->common_data.common_reg; + top_irq_reg_mask[0] = (1 << 23); + + bus_priv->irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.vfe_irq_controller, + CAM_IRQ_PRIORITY_2, + top_irq_reg_mask, + bus_priv, + cam_vfe_bus_rd_ver1_handle_irq, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle <= 0) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + return -EFAULT; + } + /* no clock gating at bus input */ + offset = common_reg->cgc_ovd; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* BUS_RD_TEST_BUS_CTRL */ + offset = common_reg->test_bus_ctrl; + cam_io_w_mb(0x0, bus_priv->common_data.mem_base + offset); + + /* Read irq mask */ + offset = common_reg->irq_reg_info.irq_reg_set->mask_reg_offset; + cam_io_w_mb(0x5, bus_priv->common_data.mem_base + offset); + + /* INPUT_IF_CMD */ + val = (bus_priv->common_data.fs_sync_enable << 5) | + (bus_priv->common_data.go_cmd_sel << 4); + offset = common_reg->input_if_cmd; + cam_io_w_mb(val, bus_priv->common_data.mem_base + offset); + return 0; +} + +static int cam_vfe_bus_deinit_hw(void *hw_priv, + void *deinit_hw_args, uint32_t arg_size) +{ + struct cam_vfe_bus_rd_ver1_priv *bus_priv = hw_priv; + int rc = 0; + + if (!bus_priv) { + CAM_ERR(CAM_ISP, "Error: Invalid args"); + return -EINVAL; + } + + if (bus_priv->error_irq_handle) { + rc = cam_irq_controller_unsubscribe_irq( + bus_priv->common_data.bus_irq_controller, + bus_priv->error_irq_handle); + 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; + + if (!priv || !cmd_args) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_BUF_UPDATE_RM: + rc = cam_vfe_bus_rd_update_rm(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_HFR_UPDATE_RM: + rc = cam_vfe_bus_rd_update_hfr(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_GET_SECURE_MODE: + rc = cam_vfe_bus_rd_get_secure_mode(priv, cmd_args, arg_size); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_BUS_RD: + rc = cam_vfe_bus_rd_update_fs_cfg(priv, cmd_args, arg_size); + break; + default: + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid camif process command:%d", + cmd_type); + break; + } + + return rc; +} + +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + struct cam_vfe_bus_rd_ver1_hw_info *bus_rd_hw_info = bus_hw_info; + + if (!soc_info || !hw_intf || !bus_hw_info || !vfe_irq_controller) { + CAM_ERR(CAM_ISP, + "Inval_prms soc_info:%pK hw_intf:%pK hw_info%pK", + soc_info, hw_intf, bus_rd_hw_info); + CAM_ERR(CAM_ISP, "controller: %pK", vfe_irq_controller); + rc = -EINVAL; + goto end; + } + + vfe_bus_local = kzalloc(sizeof(struct cam_vfe_bus), GFP_KERNEL); + if (!vfe_bus_local) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus"); + rc = -ENOMEM; + goto end; + } + + bus_priv = kzalloc(sizeof(struct cam_vfe_bus_rd_ver1_priv), + GFP_KERNEL); + if (!bus_priv) { + CAM_DBG(CAM_ISP, "Failed to alloc for vfe_bus_priv"); + rc = -ENOMEM; + goto free_bus_local; + } + + vfe_bus_local->bus_priv = bus_priv; + + bus_priv->num_client = bus_rd_hw_info->num_client; + bus_priv->num_bus_rd_resc = + bus_rd_hw_info->num_bus_rd_resc; + bus_priv->common_data.num_sec_out = 0; + bus_priv->common_data.secure_mode = CAM_SECURE_MODE_NON_SECURE; + bus_priv->common_data.core_index = soc_info->index; + bus_priv->common_data.mem_base = + CAM_SOC_GET_REG_MAP_START(soc_info, VFE_CORE_BASE_IDX); + bus_priv->common_data.hw_intf = hw_intf; + bus_priv->common_data.vfe_irq_controller = vfe_irq_controller; + bus_priv->common_data.common_reg = &bus_rd_hw_info->common_reg; + + mutex_init(&bus_priv->common_data.bus_mutex); + + rc = cam_irq_controller_init(drv_name, bus_priv->common_data.mem_base, + &bus_rd_hw_info->common_reg.irq_reg_info, + &bus_priv->common_data.bus_irq_controller); + if (rc) { + CAM_ERR(CAM_ISP, "cam_irq_controller_init failed"); + goto free_bus_priv; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_init_rm_resource(i, bus_priv, bus_hw_info, + &bus_priv->bus_client[i]); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init RM failed rc=%d", rc); + goto deinit_rm; + } + } + + for (i = 0; i < bus_priv->num_bus_rd_resc; i++) { + rc = cam_vfe_bus_init_vfe_bus_read_resource(i, bus_priv, + bus_rd_hw_info); + if (rc < 0) { + CAM_ERR(CAM_ISP, "Init VFE Out failed rc=%d", rc); + goto deinit_vfe_bus_rd; + } + } + + spin_lock_init(&bus_priv->common_data.spin_lock); + + vfe_bus_local->hw_ops.reserve = cam_vfe_bus_acquire_vfe_bus_rd; + vfe_bus_local->hw_ops.release = cam_vfe_bus_release_vfe_bus_rd; + vfe_bus_local->hw_ops.start = cam_vfe_bus_start_hw; + vfe_bus_local->hw_ops.stop = cam_vfe_bus_stop_hw; + vfe_bus_local->hw_ops.init = cam_vfe_bus_init_hw; + vfe_bus_local->hw_ops.deinit = cam_vfe_bus_deinit_hw; + vfe_bus_local->top_half_handler = cam_vfe_bus_rd_ver1_handle_irq; + vfe_bus_local->bottom_half_handler = NULL; + vfe_bus_local->hw_ops.process_cmd = __cam_vfe_bus_process_cmd; + + *vfe_bus = vfe_bus_local; + + return rc; + +deinit_vfe_bus_rd: + if (i < 0) + i = CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); +deinit_rm: + if (i < 0) + i = bus_priv->num_client; + for (--i; i >= 0; i--) + cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + +free_bus_priv: + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + +end: + return rc; +} + +int cam_vfe_bus_rd_bus_ver1_deinit( + struct cam_vfe_bus **vfe_bus) +{ + int i, rc = 0; + struct cam_vfe_bus_rd_ver1_priv *bus_priv = NULL; + struct cam_vfe_bus *vfe_bus_local; + + if (!vfe_bus || !*vfe_bus) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + vfe_bus_local = *vfe_bus; + + bus_priv = vfe_bus_local->bus_priv; + if (!bus_priv) { + CAM_ERR(CAM_ISP, "bus_priv is NULL"); + rc = -ENODEV; + goto free_bus_local; + } + + for (i = 0; i < bus_priv->num_client; i++) { + rc = cam_vfe_bus_deinit_rm_resource(&bus_priv->bus_client[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit RM failed rc=%d", rc); + } + for (i = 0; i < CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX; i++) { + rc = cam_vfe_bus_deinit_vfe_bus_rd_resource( + &bus_priv->vfe_bus_rd[i]); + if (rc < 0) + CAM_ERR(CAM_ISP, + "Deinit VFE Out failed rc=%d", rc); + } + + rc = cam_irq_controller_deinit( + &bus_priv->common_data.bus_irq_controller); + if (rc) + CAM_ERR(CAM_ISP, + "Deinit IRQ Controller failed rc=%d", rc); + + mutex_destroy(&bus_priv->common_data.bus_mutex); + kfree(vfe_bus_local->bus_priv); + +free_bus_local: + kfree(vfe_bus_local); + + *vfe_bus = NULL; + + return rc; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h new file mode 100644 index 000000000000..9ab2911d6472 --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_rd_ver1.h @@ -0,0 +1,143 @@ +/* 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. + */ + +#ifndef _CAM_VFE_BUS_R_VER1_H_ +#define _CAM_VFE_BUS_R_VER1_H_ + +#include "cam_irq_controller.h" +#include "cam_vfe_bus.h" + +#define CAM_VFE_BUS_RD_VER1_MAX_CLIENTS 1 + +enum cam_vfe_bus_rd_ver1_vfe_core_id { + CAM_VFE_BUS_RD_VER1_VFE_CORE_0, + CAM_VFE_BUS_RD_VER1_VFE_CORE_1, + CAM_VFE_BUS_RD_VER1_VFE_CORE_MAX, +}; + +enum cam_vfe_bus_rd_ver1_comp_grp_type { + CAM_VFE_BUS_RD_VER1_COMP_GRP_0, + CAM_VFE_BUS_RD_VER1_COMP_GRP_MAX, +}; + + +enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type { + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_RDI0, + CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX, +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_common: + * + * @Brief: Common registers across all BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_common { + uint32_t hw_version; + uint32_t hw_capability; + uint32_t sw_reset; + uint32_t cgc_ovd; + uint32_t pwr_iso_cfg; + uint32_t input_if_cmd; + uint32_t test_bus_ctrl; + struct cam_irq_controller_reg_info irq_reg_info; +}; + +/* + * struct cam_vfe_bus_rd_ver1_reg_offset_bus_client: + * + * @Brief: Register offsets for BUS Clients + */ +struct cam_vfe_bus_rd_ver1_reg_offset_bus_client { + uint32_t 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 unpacker_cfg; + uint32_t stride; + void *ubwc_regs; + uint32_t burst_limit; + uint32_t latency_buf_allocation; + uint32_t buf_size; +}; + +/* + * struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info: + * + * @Brief: HW capability of VFE Bus Client + */ +struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info { + enum cam_vfe_bus_rd_ver1_vfe_bus_rd_type vfe_bus_rd_type; + uint32_t max_width; + uint32_t max_height; +}; + +/* + * struct cam_vfe_bus_rd_ver1_hw_info: + * + * @Brief: HW register info for entire Bus + * + * @common_reg: Common register details + * @bus_client_reg: Bus client register info + * @comp_reg_grp: Composite group register info + * @vfe_out_hw_info: VFE output capability + */ +struct cam_vfe_bus_rd_ver1_hw_info { + struct cam_vfe_bus_rd_ver1_reg_offset_common common_reg; + uint32_t num_client; + struct cam_vfe_bus_rd_ver1_reg_offset_bus_client + bus_client_reg[CAM_VFE_BUS_RD_VER1_MAX_CLIENTS]; + uint32_t num_bus_rd_resc; + struct cam_vfe_bus_rd_ver1_vfe_bus_hw_info + vfe_bus_rd_hw_info[CAM_VFE_BUS_RD_VER1_VFE_BUSRD_MAX]; +}; + +/* + * cam_vfe_bus_rd_ver1_init() + * + * @Brief: Initialize Bus layer + * + * @soc_info: Soc Information for the associated HW + * @hw_intf: HW Interface of HW to which this resource belongs + * @bus_hw_info: BUS HW info that contains details of BUS registers + * @vfe_irq_controller: VFE IRQ Controller to use for subscribing to Top + * level IRQs + * @vfe_bus: Pointer to vfe_bus structure which will be filled + * and returned on successful initialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_ver1_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *bus_hw_info, + void *vfe_irq_controller, + struct cam_vfe_bus **vfe_bus); + +/* + * cam_vfe_bus_rd_bus_ver1_deinit() + * + * @Brief: Deinitialize Bus layer + * + * @vfe_bus: Pointer to vfe_bus structure to deinitialize + * + * @Return: 0: Success + * Non-zero: Failure + */ +int cam_vfe_bus_rd_bus_ver1_deinit(struct cam_vfe_bus **vfe_bus); + +#endif /* _CAM_VFE_BUS_R_VER1_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 7ee9f000a8c0..8ad4d96dcff8 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* 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 @@ -103,6 +103,7 @@ struct cam_vfe_bus_ver2_common_data { void *bus_irq_controller; void *vfe_irq_controller; struct cam_vfe_bus_ver2_reg_offset_common *common_reg; + struct cam_vfe_bus_ver2_reg_data *reg_data; uint32_t io_buf_update[ MAX_REG_VAL_PAIR_SIZE]; @@ -114,6 +115,7 @@ struct cam_vfe_bus_ver2_common_data { uint32_t secure_mode; uint32_t num_sec_out; uint32_t addr_no_sync; + uint32_t camera_hw_version; }; struct cam_vfe_bus_ver2_wm_resource_data { @@ -123,8 +125,6 @@ struct cam_vfe_bus_ver2_wm_resource_data { void *ctx; uint32_t irq_enabled; - bool init_cfg_done; - bool hfr_cfg_done; uint32_t offset; uint32_t width; @@ -306,10 +306,10 @@ static int cam_vfe_bus_put_evt_payload(void *core_info, 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) + uint32_t *intra_client_mask, + uint32_t camera_hw_version) { int rc = 0; - uint32_t camera_hw_version = 0; uint32_t version_based_intra_client_mask = 0x1; *intra_client_mask = 0; @@ -321,10 +321,6 @@ static int cam_vfe_bus_ver2_get_intra_client_mask( 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; @@ -1130,8 +1126,6 @@ static int cam_vfe_bus_release_wm(void *bus_priv, rsrc_data->ubwc_mode_cfg_0 = 0; rsrc_data->ubwc_mode_cfg_1 = 0; rsrc_data->ubwc_meta_offset = 0; - rsrc_data->init_cfg_done = false; - rsrc_data->hfr_cfg_done = false; rsrc_data->en_cfg = 0; rsrc_data->is_dual = 0; @@ -1149,7 +1143,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}; - uint32_t camera_hw_version; + uint32_t camera_hw_version = 0; cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); @@ -1185,12 +1179,7 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) /* enable ubwc if needed*/ if (rsrc_data->en_ubwc) { - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to get HW version:%d rc:%d", - camera_hw_version, rc); - return rc; - } + camera_hw_version = rsrc_data->common_data->camera_hw_version; if ((camera_hw_version > CAM_CPAS_TITAN_NONE) && (camera_hw_version < CAM_CPAS_TITAN_175_V100)) { struct cam_vfe_bus_ver2_reg_offset_ubwc_client @@ -1268,8 +1257,6 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) 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; } @@ -1571,7 +1558,8 @@ static int cam_vfe_bus_acquire_comp_grp( rc = cam_vfe_bus_ver2_get_intra_client_mask( dual_slave_core, comp_grp_local->hw_intf->hw_idx, - &rsrc_data->intra_client_mask); + &rsrc_data->intra_client_mask, + rsrc_data->common_data->camera_hw_version); if (rc) return rc; } else { @@ -2526,9 +2514,9 @@ static void cam_vfe_bus_update_ubwc_meta_addr( uint32_t *reg_val_pair, uint32_t *j, void *regs, - uint64_t image_buf) + uint64_t image_buf, + uint32_t camera_hw_version) { - uint32_t camera_hw_version; struct cam_vfe_bus_ver2_reg_offset_ubwc_client *ubwc_regs; struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_3_regs; int rc = 0; @@ -2539,11 +2527,7 @@ static void cam_vfe_bus_update_ubwc_meta_addr( goto end; } - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - if (rc) { - CAM_ERR(CAM_ISP, "Failed to get HW version rc: %d", rc); - goto end; - } else if ((camera_hw_version < CAM_CPAS_TITAN_170_V100) || + if ((camera_hw_version < CAM_CPAS_TITAN_170_V100) || (camera_hw_version > CAM_CPAS_TITAN_175_V120)) { CAM_ERR(CAM_ISP, "Invalid HW version: %d", camera_hw_version); @@ -2582,7 +2566,9 @@ static int cam_vfe_bus_update_ubwc_3_regs( uint32_t *reg_val_pair, uint32_t i, uint32_t *j) { struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *ubwc_regs; + struct cam_vfe_bus_ver2_reg_data *reg_data; uint32_t ubwc_bw_limit = 0; + uint32_t camera_hw_version = 0; int rc = 0; if (!wm_data || !reg_val_pair || !j) { @@ -2593,6 +2579,7 @@ static int cam_vfe_bus_update_ubwc_3_regs( ubwc_regs = (struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client *) wm_data->hw_regs->ubwc_regs; + reg_data = wm_data->common_data->reg_data; CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, wm_data->hw_regs->packer_cfg, wm_data->packer_cfg); @@ -2663,6 +2650,39 @@ static int cam_vfe_bus_update_ubwc_3_regs( wm_data->index, ubwc_bw_limit); } + camera_hw_version = wm_data->common_data->camera_hw_version; + if (camera_hw_version == CAM_CPAS_TITAN_175_V120) { + switch (wm_data->format) { + case CAM_FORMAT_UBWC_TP10: + case CAM_FORMAT_UBWC_P010: + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->threshlod_lossy_0, + reg_data->ubwc_10bit_threshold_lossy_0); + CAM_DBG(CAM_ISP, "WM %d threshlod_lossy_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->threshlod_lossy_1, + reg_data->ubwc_10bit_threshold_lossy_1); + CAM_DBG(CAM_ISP, "WM %d threshlod_lossy_1 0x%x", + wm_data->index, reg_val_pair[*j-1]); + break; + default: + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->threshlod_lossy_0, + reg_data->ubwc_8bit_threshold_lossy_0); + CAM_DBG(CAM_ISP, "WM %d threshlod_lossy_0 0x%x", + wm_data->index, reg_val_pair[*j-1]); + + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, *j, + ubwc_regs->threshlod_lossy_1, + reg_data->ubwc_8bit_threshold_lossy_1); + CAM_DBG(CAM_ISP, "WM %d threshlod_lossy_1 0x%x", + wm_data->index, reg_val_pair[*j-1]); + break; + } + } + end: return rc; } @@ -2866,8 +2886,7 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, io_cfg->planes[i].plane_stride, val); - if ((wm_data->stride != val || - !wm_data->init_cfg_done) && (wm_data->index >= 3)) { + if (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); @@ -2882,17 +2901,16 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, "No UBWC register to configure."); return -EINVAL; } - if (wm_data->ubwc_updated) { - wm_data->ubwc_updated = false; - cam_vfe_bus_update_ubwc_regs( - wm_data, reg_val_pair, i, &j); - } + + cam_vfe_bus_update_ubwc_regs( + wm_data, reg_val_pair, i, &j); /* UBWC meta address */ cam_vfe_bus_update_ubwc_meta_addr( reg_val_pair, &j, wm_data->hw_regs->ubwc_regs, - update_buf->wm_update->image_buf[i]); + update_buf->wm_update->image_buf[i], + wm_data->common_data->camera_hw_version); CAM_DBG(CAM_ISP, "WM %d ubwc meta addr 0x%llx", wm_data->index, update_buf->wm_update->image_buf[i]); @@ -2946,9 +2964,6 @@ static int cam_vfe_bus_update_wm(void *priv, void *cmd_args, 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); @@ -3012,52 +3027,36 @@ static int cam_vfe_bus_update_hfr(void *priv, void *cmd_args, return -EINVAL; } - if ((wm_data->framedrop_pattern != - hfr_cfg->framedrop_pattern) || - !wm_data->hfr_cfg_done) { - CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, - wm_data->hw_regs->framedrop_pattern, - hfr_cfg->framedrop_pattern); - wm_data->framedrop_pattern = hfr_cfg->framedrop_pattern; - CAM_DBG(CAM_ISP, "WM %d framedrop pattern 0x%x", - wm_data->index, wm_data->framedrop_pattern); - } + 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); - } + 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); - } + 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); - } + 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); @@ -3126,62 +3125,14 @@ static int cam_vfe_bus_update_ubwc_config(void *cmd_args) goto end; } - if (wm_data->packer_cfg != - ubwc_plane_cfg->packer_config || - !wm_data->init_cfg_done) { - wm_data->packer_cfg = ubwc_plane_cfg->packer_config; - wm_data->ubwc_updated = true; - } - - if ((!wm_data->is_dual) && ((wm_data->tile_cfg != - ubwc_plane_cfg->tile_config) - || !wm_data->init_cfg_done)) { - wm_data->tile_cfg = ubwc_plane_cfg->tile_config; - wm_data->ubwc_updated = true; - } - - if ((!wm_data->is_dual) && ((wm_data->h_init != - ubwc_plane_cfg->h_init) || - !wm_data->init_cfg_done)) { - wm_data->h_init = ubwc_plane_cfg->h_init; - wm_data->ubwc_updated = true; - } - - if (wm_data->v_init != ubwc_plane_cfg->v_init || - !wm_data->init_cfg_done) { - wm_data->v_init = ubwc_plane_cfg->v_init; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_meta_stride != - ubwc_plane_cfg->meta_stride || - !wm_data->init_cfg_done) { - wm_data->ubwc_meta_stride = ubwc_plane_cfg->meta_stride; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_mode_cfg_0 != - ubwc_plane_cfg->mode_config_0 || - !wm_data->init_cfg_done) { - wm_data->ubwc_mode_cfg_0 = - ubwc_plane_cfg->mode_config_0; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_mode_cfg_1 != - ubwc_plane_cfg->mode_config_1 || - !wm_data->init_cfg_done) { - wm_data->ubwc_mode_cfg_1 = - ubwc_plane_cfg->mode_config_1; - wm_data->ubwc_updated = true; - } - - if (wm_data->ubwc_meta_offset != - ubwc_plane_cfg->meta_offset || - !wm_data->init_cfg_done) { - wm_data->ubwc_meta_offset = ubwc_plane_cfg->meta_offset; - wm_data->ubwc_updated = true; - } + wm_data->packer_cfg = ubwc_plane_cfg->packer_config; + wm_data->tile_cfg = ubwc_plane_cfg->tile_config; + wm_data->h_init = ubwc_plane_cfg->h_init; + wm_data->v_init = ubwc_plane_cfg->v_init; + wm_data->ubwc_meta_stride = ubwc_plane_cfg->meta_stride; + wm_data->ubwc_mode_cfg_0 = ubwc_plane_cfg->mode_config_0; + wm_data->ubwc_mode_cfg_1 = ubwc_plane_cfg->mode_config_1; + wm_data->ubwc_meta_offset = ubwc_plane_cfg->meta_offset; } end: @@ -3268,24 +3219,27 @@ static int cam_vfe_bus_init_hw(void *hw_priv, NULL, NULL); - if (bus_priv->irq_handle <= 0) { + if ((int)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, - cam_vfe_bus_err_bottom_half, - bus_priv->tasklet_info, - &tasklet_bh_api); - - if (bus_priv->irq_handle <= 0) { - CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); - return -EFAULT; + if (bus_priv->tasklet_info != NULL) { + bus_priv->error_irq_handle = cam_irq_controller_subscribe_irq( + bus_priv->common_data.bus_irq_controller, + CAM_IRQ_PRIORITY_0, + bus_error_irq_mask, + bus_priv, + cam_vfe_bus_error_irq_top_half, + cam_vfe_bus_err_bottom_half, + bus_priv->tasklet_info, + &tasklet_bh_api); + + if ((int)bus_priv->error_irq_handle <= 0) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS error IRQ %d", + bus_priv->error_irq_handle); + return -EFAULT; + } } /*Set Debug Registers*/ @@ -3422,6 +3376,7 @@ int cam_vfe_bus_ver2_init( 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; + uint32_t camera_hw_version = 0; CAM_DBG(CAM_ISP, "Enter"); @@ -3434,6 +3389,14 @@ int cam_vfe_bus_ver2_init( goto end; } + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version:%d rc:%d", + camera_hw_version, rc); + 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"); @@ -3460,8 +3423,10 @@ int cam_vfe_bus_ver2_init( 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.reg_data = &ver2_hw_info->reg_data; bus_priv->common_data.addr_no_sync = CAM_VFE_BUS_ADDR_NO_SYNC_DEFAULT_VAL; + bus_priv->common_data.camera_hw_version = camera_hw_version; mutex_init(&bus_priv->common_data.bus_mutex); diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h index 73b7eb2dc59d..39d8fa561590 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.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 @@ -122,6 +122,8 @@ struct cam_vfe_bus_ver2_reg_offset_ubwc_3_client { uint32_t mode_cfg_0; uint32_t mode_cfg_1; uint32_t bw_limit; + uint32_t threshlod_lossy_0; + uint32_t threshlod_lossy_1; }; @@ -175,6 +177,19 @@ struct cam_vfe_bus_ver2_vfe_out_hw_info { }; /* + * struct cam_vfe_bus_ver2_reg_data: + * + * @Brief: Holds the bus register data + */ + +struct cam_vfe_bus_ver2_reg_data { + uint32_t ubwc_10bit_threshold_lossy_0; + uint32_t ubwc_10bit_threshold_lossy_1; + uint32_t ubwc_8bit_threshold_lossy_0; + uint32_t ubwc_8bit_threshold_lossy_1; +}; + +/* * struct cam_vfe_bus_ver2_hw_info: * * @Brief: HW register info for entire Bus @@ -183,6 +198,7 @@ struct cam_vfe_bus_ver2_vfe_out_hw_info { * @bus_client_reg: Bus client register info * @comp_reg_grp: Composite group register info * @vfe_out_hw_info: VFE output capability + * @reg_data: bus register data; */ struct cam_vfe_bus_ver2_hw_info { struct cam_vfe_bus_ver2_reg_offset_common common_reg; @@ -194,6 +210,7 @@ struct cam_vfe_bus_ver2_hw_info { uint32_t num_out; struct cam_vfe_bus_ver2_vfe_out_hw_info vfe_out_hw_info[CAM_VFE_BUS_VER2_VFE_OUT_MAX]; + struct cam_vfe_bus_ver2_reg_data reg_data; }; /* diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h index 6f88bc7f5a99..4cdb28a0cb67 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.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 @@ -19,6 +19,7 @@ #define CAM_VFE_BUS_VER_1_0 0x1000 #define CAM_VFE_BUS_VER_2_0 0x2000 +#define CAM_VFE_BUS_RD_VER_4_0 0x4000 enum cam_vfe_bus_plane_type { PLANE_Y, @@ -26,6 +27,12 @@ enum cam_vfe_bus_plane_type { PLANE_MAX, }; +enum cam_vfe_bus_type { + BUS_TYPE_WR, + BUS_TYPE_RD, + BUS_TYPE_MAX, +}; + /* * struct cam_vfe_bus: * @@ -50,6 +57,7 @@ struct cam_vfe_bus { * @Brief: Initialize Bus layer * * @bus_version: Version of BUS to initialize + * @bus_type: Bus Type RD/WR * @soc_info: Soc Information for the associated HW * @hw_intf: HW Interface of HW to which this resource belongs * @bus_hw_info: BUS HW info that contains details of BUS registers @@ -62,6 +70,7 @@ struct cam_vfe_bus { * Non-zero: Failure */ int cam_vfe_bus_init(uint32_t bus_version, + int bus_type, struct cam_hw_soc_info *soc_info, struct cam_hw_intf *hw_intf, void *bus_hw_info, diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile index cdb6b2867433..eb867630d88e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -11,3 +11,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vf obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_camif_lite_ver2.o obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o cam_vfe_rdi.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_fe_ver1.o diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c index 64b77eb7ccb8..b3c795417171 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_lite_ver2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* 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 @@ -166,10 +166,7 @@ static int cam_vfe_camif_lite_resource_start( static int cam_vfe_camif_lite_resource_stop( struct cam_isp_resource_node *camif_lite_res) { - struct cam_vfe_mux_camif_lite_data *camif_lite_priv; - struct cam_vfe_camif_lite_ver2_reg *camif_lite_reg; int rc = 0; - uint32_t val = 0; if (!camif_lite_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -180,16 +177,6 @@ static int cam_vfe_camif_lite_resource_stop( (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) return 0; - camif_lite_priv = (struct cam_vfe_mux_camif_lite_data *) - camif_lite_res->res_priv; - camif_lite_reg = camif_lite_priv->camif_lite_reg; - - val = cam_io_r_mb(camif_lite_priv->mem_base + - camif_lite_priv->common_reg->core_cfg); - val &= (~(1 << camif_lite_priv->reg_data->dual_pd_path_sel_shift)); - cam_io_w_mb(val, camif_lite_priv->mem_base + - camif_lite_priv->common_reg->core_cfg); - if (camif_lite_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) camif_lite_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 95bed8d9d23c..c40936525c73 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -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 @@ -212,8 +212,7 @@ static int cam_vfe_camif_resource_start( uint32_t epoch0_irq_mask; uint32_t epoch1_irq_mask; uint32_t computed_epoch_line_cfg; - uint32_t camera_hw_version = 0; - int rc = 0; + struct cam_vfe_soc_private *soc_private; if (!camif_res) { CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); @@ -228,6 +227,13 @@ static int cam_vfe_camif_resource_start( rsrc_data = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; + soc_private = rsrc_data->soc_info->soc_private; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + return -ENODEV; + } + /*config vfe core*/ val = (rsrc_data->pix_pattern << rsrc_data->reg_data->pixel_pattern_shift); @@ -253,26 +259,14 @@ static int cam_vfe_camif_resource_start( rsrc_data->common_reg->module_ctrl[ CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); - /* get the HW version */ - rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); - - if (rc) { - CAM_ERR(CAM_ISP, "Couldn't find HW version. rc: %d", rc); - return rc; - } - /* epoch config */ - switch (camera_hw_version) { + switch (soc_private->cpas_version) { case CAM_CPAS_TITAN_170_V100: case CAM_CPAS_TITAN_170_V110: case CAM_CPAS_TITAN_170_V120: - cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, - rsrc_data->mem_base + - rsrc_data->camif_reg->epoch_irq); - break; default: - epoch0_irq_mask = ((rsrc_data->last_line - - rsrc_data->first_line) / 2) + + epoch0_irq_mask = (((rsrc_data->last_line - + rsrc_data->first_line) * 2) / 3) + rsrc_data->first_line; epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; @@ -316,27 +310,16 @@ static int cam_vfe_camif_resource_start( } 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_mux_camif_data *camif_priv; - struct cam_vfe_soc_private *soc_private; - int rc = 0, i; - uint32_t val = 0; + uint32_t val = 0, wm_idx, offset; + int i = 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 = 0xA3C; i <= 0xA90; i += 8) { + CAM_INFO(CAM_ISP, + "SCALING offset 0x%x val 0x%x offset 0x%x val 0x%x", + i, cam_io_r_mb(camif_priv->mem_base + i), i + 4, + cam_io_r_mb(camif_priv->mem_base + i + 4)); } for (i = 0xE0C; i <= 0xE3C; i += 4) { @@ -344,64 +327,96 @@ static int cam_vfe_camif_reg_dump( 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); + for (wm_idx = 0; wm_idx <= 23; wm_idx++) { + offset = 0x2214 + 0x100 * wm_idx; + CAM_INFO(CAM_ISP, + "BUS_WM%u offset 0x%x val 0x%x offset 0x%x val 0x%x", + wm_idx, offset, + cam_io_r_mb(camif_priv->mem_base + offset), + offset + 4, cam_io_r_mb(camif_priv->mem_base + + offset + 4)); + CAM_INFO(CAM_ISP, + "offset+8 0x%x val+8 0x%x offset+12 0x%x val+12 0x%x", + offset + 8, + cam_io_r_mb(camif_priv->mem_base + offset + 8), + offset + 12, cam_io_r_mb(camif_priv->mem_base + + offset + 12)); } - 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); + offset = 0x420; + val = cam_soc_util_r(camif_priv->soc_info, 1, offset); + CAM_INFO(CAM_ISP, "CAMNOC IFE02 MaxWR_LOW offset 0x%x value 0x%x", + offset, 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); + offset = 0x820; + val = cam_soc_util_r(camif_priv->soc_info, 1, offset); + CAM_INFO(CAM_ISP, "CAMNOC IFE13 MaxWR_LOW offset 0x%x value 0x%x", + offset, val); - return rc; + return 0; } -static int cam_vfe_camif_reg_dump_bh(struct cam_vfe_mux_camif_data *camif_priv) +static int cam_vfe_camif_reg_dump_bh( + struct cam_isp_resource_node *camif_res) { + struct cam_vfe_mux_camif_data *camif_priv; + struct cam_vfe_soc_private *soc_private; uint32_t offset, val, wm_idx; + if (!camif_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((camif_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (camif_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + camif_priv = (struct cam_vfe_mux_camif_data *)camif_res->res_priv; for (offset = 0x0; offset < 0x1000; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); - CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val); } for (offset = 0x2000; offset <= 0x20B8; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); - CAM_INFO(CAM_ISP, "offset 0x%x value 0x%x", offset, val); + CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val); } for (wm_idx = 0; wm_idx <= 23; wm_idx++) { for (offset = 0x2200 + 0x100 * wm_idx; offset < 0x2278 + 0x100 * wm_idx; offset += 0x4) { val = cam_soc_util_r(camif_priv->soc_info, 0, offset); - CAM_INFO(CAM_ISP, + CAM_DBG(CAM_ISP, "offset 0x%x value 0x%x", offset, val); } } - offset = 0x420; - val = cam_soc_util_r(camif_priv->soc_info, 1, offset); - CAM_INFO(CAM_ISP, "CAMNOC IFE02 MaxWR_LOW offset 0x%x value 0x%x", - offset, val); - - offset = 0x820; - val = cam_soc_util_r(camif_priv->soc_info, 1, offset); - CAM_INFO(CAM_ISP, "CAMNOC IFE13 MaxWR_LOW offset 0x%x value 0x%x", - offset, val); + soc_private = camif_priv->soc_info->soc_private; + if (soc_private->cpas_version == CAM_CPAS_TITAN_175_V120) { + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x3A20, true, &val); + CAM_DBG(CAM_ISP, "IFE0_nRDI_MAXWR_LOW offset 0x3A20 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x5420, true, &val); + CAM_DBG(CAM_ISP, "IFE1_nRDI_MAXWR_LOW offset 0x5420 val 0x%x", + val); + + cam_cpas_reg_read(soc_private->cpas_handle[1], + CAM_CPAS_REG_CAMNOC, 0x3620, true, &val); + CAM_DBG(CAM_ISP, + "IFE0123_RDI_WR_MAXWR_LOW offset 0x3620 val 0x%x", val); + } else { + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_DBG(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read(soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_DBG(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + } return 0; } @@ -483,7 +498,7 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, arg_size); break; case CAM_ISP_HW_CMD_GET_REG_DUMP: - rc = cam_vfe_camif_reg_dump(rsrc_node); + rc = cam_vfe_camif_reg_dump_bh(rsrc_node); break; case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args); @@ -573,11 +588,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, } break; case CAM_ISP_HW_EVENT_ERROR: - if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { + if (irq_status1 & camif_priv->reg_data->error_irq_mask1 && + payload->enable_reg_dump) { CAM_DBG(CAM_ISP, "Received ERROR\n"); ret = CAM_ISP_HW_ERROR_OVERFLOW; - cam_vfe_camif_reg_dump(camif_node); - cam_vfe_camif_reg_dump_bh(camif_node->res_priv); + cam_vfe_camif_reg_dump(camif_node->res_priv); } else { ret = CAM_ISP_HW_ERROR_NONE; } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c new file mode 100644 index 000000000000..2432d7a5044b --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.c @@ -0,0 +1,638 @@ +/* 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 <linux/slab.h> +#include <uapi/media/cam_isp.h> +#include "cam_io_util.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_isp_hw.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_soc.h" +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.h" +#include "cam_vfe_fe_ver1.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +#define CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX 2 + +struct cam_vfe_mux_fe_data { + void __iomem *mem_base; + struct cam_hw_intf *hw_intf; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_reg_data *reg_data; + struct cam_hw_soc_info *soc_info; + + enum cam_isp_hw_sync_mode sync_mode; + uint32_t dsp_mode; + uint32_t pix_pattern; + uint32_t first_pixel; + uint32_t first_line; + uint32_t last_pixel; + uint32_t last_line; + bool enable_sof_irq_debug; + uint32_t irq_debug_cnt; + uint32_t fe_cfg_data; + uint32_t hbi_count; +}; + +static int cam_vfe_fe_validate_pix_pattern(uint32_t pattern) +{ + int rc; + + switch (pattern) { + case CAM_ISP_PATTERN_BAYER_RGRGRG: + case CAM_ISP_PATTERN_BAYER_GRGRGR: + case CAM_ISP_PATTERN_BAYER_BGBGBG: + case CAM_ISP_PATTERN_BAYER_GBGBGB: + case CAM_ISP_PATTERN_YUV_YCBYCR: + case CAM_ISP_PATTERN_YUV_YCRYCB: + case CAM_ISP_PATTERN_YUV_CBYCRY: + case CAM_ISP_PATTERN_YUV_CRYCBY: + rc = 0; + break; + default: + CAM_ERR(CAM_ISP, "Error! Invalid pix pattern:%d", pattern); + rc = -EINVAL; + break; + } + return rc; +} + +static int cam_vfe_fe_update( + struct cam_isp_resource_node *fe_res, + void *cmd_data, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + struct cam_vfe_fe_update_args *args = cmd_data; + uint32_t fe_cfg_data; + + if (arg_size != sizeof(struct cam_vfe_fe_update_args)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!args) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "fe_update->min_vbi = 0x%x", args->fe_config.min_vbi); + CAM_DBG(CAM_ISP, "fe_update->hbi_count = 0x%x", + args->fe_config.hbi_count); + CAM_DBG(CAM_ISP, "fe_update->fs_mode = 0x%x", args->fe_config.fs_mode); + CAM_DBG(CAM_ISP, "fe_update->fs_line_sync_en = 0x%x", + args->fe_config.fs_line_sync_en); + + fe_cfg_data = args->fe_config.min_vbi | + args->fe_config.fs_mode << 8 | + args->fe_config.fs_line_sync_en; + + rsrc_data = fe_res->res_priv; + rsrc_data->fe_cfg_data = fe_cfg_data; + rsrc_data->hbi_count = args->fe_config.hbi_count; + + CAM_DBG(CAM_ISP, "fe_cfg_data = 0x%x", fe_cfg_data); + return 0; +} + +static int cam_vfe_fe_get_reg_update( + struct cam_isp_resource_node *fe_res, + void *cmd_args, uint32_t arg_size) +{ + uint32_t size = 0; + uint32_t reg_val_pair[2]; + struct cam_isp_hw_get_cmd_update *cdm_args = cmd_args; + struct cam_cdm_utils_ops *cdm_util_ops = NULL; + struct cam_vfe_mux_fe_data *rsrc_data = NULL; + + if (arg_size != sizeof(struct cam_isp_hw_get_cmd_update)) { + CAM_ERR(CAM_ISP, "Invalid cmd size"); + return -EINVAL; + } + + if (!cdm_args || !cdm_args->res) { + CAM_ERR(CAM_ISP, "Invalid args"); + return -EINVAL; + } + + cdm_util_ops = (struct cam_cdm_utils_ops *)cdm_args->res->cdm_ops; + + if (!cdm_util_ops) { + CAM_ERR(CAM_ISP, "Invalid CDM ops"); + return -EINVAL; + } + + if (cdm_args->rup_data->is_fe_enable && + (cdm_args->rup_data->res_bitmap & + (1 << CAM_IFE_REG_UPD_CMD_RDI1_BIT))) { + CAM_DBG(CAM_ISP, "Avoiding rup_upd for fe"); + cdm_args->cmd.used_bytes = 0; + return 0; + } + + size = cdm_util_ops->cdm_required_size_reg_random(1); + /* since cdm returns dwords, we need to convert it into bytes */ + if ((size * 4) > cdm_args->cmd.size) { + CAM_ERR(CAM_ISP, "buf size:%d is not sufficient, expected: %d", + cdm_args->cmd.size, size); + return -EINVAL; + } + + rsrc_data = fe_res->res_priv; + reg_val_pair[0] = rsrc_data->fe_reg->reg_update_cmd; + reg_val_pair[1] = rsrc_data->reg_data->reg_update_cmd_data; + CAM_DBG(CAM_ISP, "CAMIF res_id %d reg_update_cmd 0x%x offset 0x%x", + fe_res->res_id, reg_val_pair[1], reg_val_pair[0]); + + cdm_util_ops->cdm_write_regrandom(cdm_args->cmd.cmd_buf_addr, + 1, reg_val_pair); + + cdm_args->cmd.used_bytes = size * 4; + + return 0; +} + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *fe_res, + void *acquire_param) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_vfe_acquire_args *acquire_data; + + int rc = 0; + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + acquire_data = (struct cam_vfe_acquire_args *)acquire_param; + + rc = cam_vfe_fe_validate_pix_pattern( + acquire_data->vfe_in.in_port->test_pattern); + if (rc) { + CAM_ERR(CAM_ISP, "pix validation failed: id:%d pix_pattern %d", + fe_res->hw_intf->hw_idx, + acquire_data->vfe_in.in_port->test_pattern); + return rc; + } + + fe_data->sync_mode = acquire_data->vfe_in.sync_mode; + fe_data->pix_pattern = acquire_data->vfe_in.in_port->test_pattern; + fe_data->dsp_mode = acquire_data->vfe_in.in_port->dsp_mode; + fe_data->first_pixel = acquire_data->vfe_in.in_port->left_start; + fe_data->last_pixel = acquire_data->vfe_in.in_port->left_stop; + fe_data->first_line = acquire_data->vfe_in.in_port->line_start; + fe_data->last_line = acquire_data->vfe_in.in_port->line_stop; + + CAM_DBG(CAM_ISP, "hw id:%d pix_pattern:%d dsp_mode=%d", + fe_res->hw_intf->hw_idx, + fe_data->pix_pattern, fe_data->dsp_mode); + return rc; +} + +static int cam_vfe_fe_resource_init( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_enable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to enable dsp clk"); + } + + return rc; +} + +static int cam_vfe_fe_resource_deinit( + struct cam_isp_resource_node *fe_res, + void *init_args, uint32_t arg_size) +{ + struct cam_vfe_mux_fe_data *fe_data; + struct cam_hw_soc_info *soc_info; + int rc = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error Invalid input arguments"); + return -EINVAL; + } + + fe_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + soc_info = fe_data->soc_info; + + if ((fe_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + rc = cam_vfe_soc_disable_clk(soc_info, CAM_VFE_DSP_CLK_NAME); + if (rc) + CAM_ERR(CAM_ISP, "failed to disable dsp clk"); + } + + return rc; + +} + +static int cam_vfe_fe_resource_start( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *rsrc_data; + uint32_t val = 0; + uint32_t epoch0_irq_mask; + uint32_t epoch1_irq_mask; + uint32_t computed_epoch_line_cfg; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_ERR(CAM_ISP, "Error! Invalid fe res res_state:%d", + fe_res->res_state); + return -EINVAL; + } + + rsrc_data = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + + /* config vfe core */ + val = (rsrc_data->pix_pattern << + rsrc_data->reg_data->pixel_pattern_shift); + if (rsrc_data->sync_mode == CAM_ISP_HW_SYNC_SLAVE) + val |= (1 << rsrc_data->reg_data->extern_reg_update_shift); + + if ((rsrc_data->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (rsrc_data->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + /* DSP mode reg val is CAM_ISP_DSP_MODE - 1 */ + val |= (((rsrc_data->dsp_mode - 1) & + rsrc_data->reg_data->dsp_mode_mask) << + rsrc_data->reg_data->dsp_mode_shift); + val |= (0x1 << rsrc_data->reg_data->dsp_en_shift); + } + + if (rsrc_data->fe_cfg_data) { + /*set Mux mode value to EXT_RD_PATH */ + val |= (rsrc_data->reg_data->fe_mux_data << + rsrc_data->reg_data->input_mux_sel_shift); + } + + if (rsrc_data->hbi_count) { + /*set hbi count*/ + val |= (rsrc_data->hbi_count << + rsrc_data->reg_data->hbi_cnt_shift); + } + cam_io_w_mb(val, rsrc_data->mem_base + rsrc_data->common_reg->core_cfg); + + CAM_DBG(CAM_ISP, "hw id:%d core_cfg (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->common_reg->core_cfg, + val); + + /* disable the CGC for stats */ + cam_io_w_mb(0xFFFFFFFF, rsrc_data->mem_base + + rsrc_data->common_reg->module_ctrl[ + CAM_VFE_TOP_VER2_MODULE_STATS]->cgc_ovd); + + /* epoch config */ + epoch0_irq_mask = ((rsrc_data->last_line - rsrc_data->first_line) / 2) + + rsrc_data->first_line; + + epoch1_irq_mask = rsrc_data->reg_data->epoch_line_cfg & 0xFFFF; + computed_epoch_line_cfg = (epoch0_irq_mask << 16) | epoch1_irq_mask; + cam_io_w_mb(computed_epoch_line_cfg, + rsrc_data->mem_base + rsrc_data->fe_reg->epoch_irq); + CAM_DBG(CAM_ISP, "first_line:0x%x last_line:0x%x epoch_line_cfg: 0x%x", + rsrc_data->first_line, rsrc_data->last_line, + computed_epoch_line_cfg); + + fe_res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + /* Read Back cfg */ + cam_io_w_mb(rsrc_data->fe_cfg_data, + rsrc_data->mem_base + rsrc_data->fe_reg->fe_cfg); + CAM_DBG(CAM_ISP, "hw id:%d fe_cfg_data(off:0x%x val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->fe_cfg, + rsrc_data->fe_cfg_data); + + /* Reg Update */ + cam_io_w_mb(rsrc_data->reg_data->reg_update_cmd_data, + rsrc_data->mem_base + rsrc_data->fe_reg->reg_update_cmd); + CAM_DBG(CAM_ISP, "hw id:%d RUP (off:0x%x, val:0x%x)", + fe_res->hw_intf->hw_idx, + rsrc_data->fe_reg->reg_update_cmd, + rsrc_data->reg_data->reg_update_cmd_data); + + /* disable sof irq debug flag */ + rsrc_data->enable_sof_irq_debug = false; + rsrc_data->irq_debug_cnt = 0; + + CAM_DBG(CAM_ISP, "Start Camif IFE %d Done", fe_res->hw_intf->hw_idx); + return 0; +} + +static int cam_vfe_fe_reg_dump( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_soc_private *soc_private; + int rc = 0, i; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if ((fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED) || + (fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE)) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + soc_private = fe_priv->soc_info->soc_private; + for (i = 0xA3C; i <= 0xA90; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0xE0C; i <= 0xE3C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2000; i <= 0x20B8; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2500; i <= 0x255C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + for (i = 0x2600; i <= 0x265C; i += 4) { + val = cam_io_r_mb(fe_priv->mem_base + i); + CAM_INFO(CAM_ISP, "offset 0x%x val 0x%x", i, val); + } + + cam_cpas_reg_read((uint32_t)soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x420, true, &val); + CAM_INFO(CAM_ISP, "IFE02_MAXWR_LOW offset 0x420 val 0x%x", val); + + cam_cpas_reg_read((uint32_t)soc_private->cpas_handle[0], + CAM_CPAS_REG_CAMNOC, 0x820, true, &val); + CAM_INFO(CAM_ISP, "IFE13_MAXWR_LOW offset 0x820 val 0x%x", val); + + return rc; +} + +static int cam_vfe_fe_resource_stop( + struct cam_isp_resource_node *fe_res) +{ + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_fe_ver1_reg *fe_reg; + int rc = 0; + uint32_t val = 0; + + if (!fe_res) { + CAM_ERR(CAM_ISP, "Error! Invalid input arguments"); + return -EINVAL; + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_RESERVED || + fe_res->res_state == CAM_ISP_RESOURCE_STATE_AVAILABLE) + return 0; + + fe_priv = (struct cam_vfe_mux_fe_data *)fe_res->res_priv; + fe_reg = fe_priv->fe_reg; + + if ((fe_priv->dsp_mode >= CAM_ISP_DSP_MODE_ONE_WAY) && + (fe_priv->dsp_mode <= CAM_ISP_DSP_MODE_ROUND)) { + val = cam_io_r_mb(fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + val &= (~(1 << fe_priv->reg_data->dsp_en_shift)); + cam_io_w_mb(val, fe_priv->mem_base + + fe_priv->common_reg->core_cfg); + } + + if (fe_res->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) + fe_res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + return rc; +} + +static int cam_vfe_fe_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_fe_data *fe_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + fe_priv = + (struct cam_vfe_mux_fe_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + fe_priv->enable_sof_irq_debug = true; + else + fe_priv->enable_sof_irq_debug = false; + + return 0; +} + +static int cam_vfe_fe_process_cmd(struct cam_isp_resource_node *rsrc_node, + uint32_t cmd_type, void *cmd_args, uint32_t arg_size) +{ + int rc = -EINVAL; + + if (!rsrc_node || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid input arguments"); + return -EINVAL; + } + + switch (cmd_type) { + case CAM_ISP_HW_CMD_GET_REG_UPDATE: + rc = cam_vfe_fe_get_reg_update(rsrc_node, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_GET_REG_DUMP: + rc = cam_vfe_fe_reg_dump(rsrc_node); + break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_fe_sof_irq_debug(rsrc_node, cmd_args); + break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_fe_update(rsrc_node, cmd_args, arg_size); + break; + default: + CAM_ERR(CAM_ISP, + "unsupported process command:%d", cmd_type); + break; + } + + return rc; +} + +static int cam_vfe_fe_handle_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + return -EPERM; +} + +static int cam_vfe_fe_handle_irq_bottom_half(void *handler_priv, + void *evt_payload_priv) +{ + int ret = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *fe_node; + struct cam_vfe_mux_fe_data *fe_priv; + struct cam_vfe_top_irq_evt_payload *payload; + uint32_t irq_status0; + uint32_t irq_status1; + + if (!handler_priv || !evt_payload_priv) { + CAM_ERR(CAM_ISP, "Invalid params"); + return ret; + } + + fe_node = handler_priv; + fe_priv = fe_node->res_priv; + payload = evt_payload_priv; + irq_status0 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS0]; + irq_status1 = payload->irq_reg_val[CAM_IFE_IRQ_CAMIF_REG_STATUS1]; + + CAM_DBG(CAM_ISP, "event ID:%d, irq_status_0 = 0x%x", + payload->evt_id, irq_status0); + + switch (payload->evt_id) { + case CAM_ISP_HW_EVENT_SOF: + if (irq_status0 & fe_priv->reg_data->sof_irq_mask) { + if ((fe_priv->enable_sof_irq_debug) && + (fe_priv->irq_debug_cnt <= + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX)) { + CAM_INFO_RATE_LIMIT(CAM_ISP, "Received SOF"); + + fe_priv->irq_debug_cnt++; + if (fe_priv->irq_debug_cnt == + CAM_VFE_CAMIF_IRQ_SOF_DEBUG_CNT_MAX) { + fe_priv->enable_sof_irq_debug = + false; + fe_priv->irq_debug_cnt = 0; + } + } else { + CAM_DBG(CAM_ISP, "Received SOF"); + } + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_EPOCH: + if (irq_status0 & fe_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 & fe_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 & fe_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 & fe_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR\n"); + ret = CAM_ISP_HW_ERROR_OVERFLOW; + cam_vfe_fe_reg_dump(fe_node); + } else { + ret = CAM_ISP_HW_ERROR_NONE; + } + break; + default: + break; + } + + CAM_DBG(CAM_ISP, "returing status = %d", ret); + return ret; +} + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *fe_hw_info, + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = NULL; + struct cam_vfe_fe_ver1_hw_info *fe_info = fe_hw_info; + + fe_priv = kzalloc(sizeof(struct cam_vfe_mux_fe_data), + GFP_KERNEL); + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! Failed to alloc for fe_priv"); + return -ENOMEM; + } + + fe_node->res_priv = fe_priv; + + fe_priv->mem_base = soc_info->reg_map[VFE_CORE_BASE_IDX].mem_base; + fe_priv->fe_reg = fe_info->fe_reg; + fe_priv->common_reg = fe_info->common_reg; + fe_priv->reg_data = fe_info->reg_data; + fe_priv->hw_intf = hw_intf; + fe_priv->soc_info = soc_info; + + fe_node->init = cam_vfe_fe_resource_init; + fe_node->deinit = cam_vfe_fe_resource_deinit; + fe_node->start = cam_vfe_fe_resource_start; + fe_node->stop = cam_vfe_fe_resource_stop; + fe_node->process_cmd = cam_vfe_fe_process_cmd; + fe_node->top_half_handler = cam_vfe_fe_handle_irq_top_half; + fe_node->bottom_half_handler = cam_vfe_fe_handle_irq_bottom_half; + + return 0; +} + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *fe_node) +{ + struct cam_vfe_mux_fe_data *fe_priv = fe_node->res_priv; + + fe_node->start = NULL; + fe_node->stop = NULL; + fe_node->process_cmd = NULL; + fe_node->top_half_handler = NULL; + fe_node->bottom_half_handler = NULL; + + fe_node->res_priv = NULL; + + if (!fe_priv) { + CAM_ERR(CAM_ISP, "Error! fe_priv is NULL"); + return -ENODEV; + } + + kfree(fe_priv); + + return 0; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h new file mode 100644 index 000000000000..0f8d2f18d1ec --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_fe_ver1.h @@ -0,0 +1,94 @@ +/* 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. + */ + +#ifndef _CAM_VFE_FE_VER1_H_ +#define _CAM_VFE_FE_VER1_H_ + +#include "cam_isp_hw.h" +#include "cam_vfe_top.h" + +struct cam_vfe_fe_ver1_reg { + uint32_t camif_cmd; + uint32_t camif_config; + uint32_t line_skip_pattern; + uint32_t pixel_skip_pattern; + uint32_t skip_period; + uint32_t irq_subsample_pattern; + uint32_t epoch_irq; + uint32_t raw_crop_width_cfg; + uint32_t raw_crop_height_cfg; + uint32_t reg_update_cmd; + uint32_t vfe_diag_config; + uint32_t vfe_diag_sensor_status; + uint32_t fe_cfg; +}; + +struct cam_vfe_fe_reg_data { + uint32_t raw_crop_first_pixel_shift; + uint32_t raw_crop_first_pixel_mask; + + uint32_t raw_crop_last_pixel_shift; + uint32_t raw_crop_last_pixel_mask; + + uint32_t raw_crop_first_line_shift; + uint32_t raw_crop_first_line_mask; + + uint32_t raw_crop_last_line_shift; + uint32_t raw_crop_last_line_mask; + + uint32_t input_mux_sel_shift; + uint32_t input_mux_sel_mask; + uint32_t extern_reg_update_shift; + uint32_t extern_reg_update_mask; + + uint32_t pixel_pattern_shift; + uint32_t pixel_pattern_mask; + + uint32_t dsp_mode_shift; + uint32_t dsp_mode_mask; + uint32_t dsp_en_shift; + uint32_t dsp_en_mask; + + uint32_t reg_update_cmd_data; + uint32_t epoch_line_cfg; + uint32_t sof_irq_mask; + uint32_t epoch0_irq_mask; + uint32_t reg_update_irq_mask; + uint32_t eof_irq_mask; + uint32_t error_irq_mask0; + uint32_t error_irq_mask1; + + uint32_t enable_diagnostic_hw; + uint32_t fe_mux_data; + uint32_t hbi_cnt_shift; +}; + +struct cam_vfe_fe_ver1_hw_info { + struct cam_vfe_top_ver2_reg_offset_common *common_reg; + struct cam_vfe_fe_ver1_reg *fe_reg; + struct cam_vfe_fe_reg_data *reg_data; +}; + +int cam_vfe_fe_ver1_acquire_resource( + struct cam_isp_resource_node *camif_res, + void *acquire_param); + +int cam_vfe_fe_ver1_init( + struct cam_hw_intf *hw_intf, + struct cam_hw_soc_info *soc_info, + void *camif_hw_info, + struct cam_isp_resource_node *camif_node); + +int cam_vfe_fe_ver1_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_FE_VER1_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c index 230698f7f890..c2c1bc20463b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -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 @@ -64,6 +64,14 @@ static int cam_vfe_rdi_get_reg_update( return -EINVAL; } + if (cdm_args->rup_data->is_fe_enable && + (cdm_args->rup_data->res_bitmap & + (1 << CAM_IFE_REG_UPD_CMD_PIX_BIT))) { + cdm_args->cmd.used_bytes = 0; + CAM_DBG(CAM_ISP, "Avoiding reg_upd for fe for rdi"); + return 0; + } + 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; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index f54f52af5334..569bbb6b2ce0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -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 @@ -37,11 +37,13 @@ struct cam_vfe_top_ver2_priv { struct cam_axi_vote applied_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]; - struct cam_axi_vote last_vote[CAM_VFE_TOP_VER2_MUX_MAX * + struct cam_axi_vote last_vote[CAM_CPAS_HANDLE_MAX] + [CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES]; - uint32_t last_counter; + uint32_t last_counter[CAM_CPAS_HANDLE_MAX]; enum cam_vfe_bw_control_action axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX]; + enum cam_cpas_handle_id cpashdl_type[CAM_VFE_TOP_VER2_MUX_MAX]; }; static int cam_vfe_top_mux_get_base(struct cam_vfe_top_ver2_priv *top_priv, @@ -133,99 +135,131 @@ static int cam_vfe_top_set_axi_bw_vote( struct cam_vfe_soc_private *soc_private = soc_info->soc_private; bool apply_bw_update = false; + enum cam_cpas_handle_id cpashdl_type; + struct cam_axi_vote *last_vote = NULL; 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 += + for (cpashdl_type = 0; cpashdl_type < CAM_CPAS_HANDLE_MAX; + cpashdl_type++) { + + if ((soc_private->cpas_version != CAM_CPAS_TITAN_175_V120) + && cpashdl_type) + continue; + + sum.uncompressed_bw = sum.compressed_bw = 0; + to_be_applied_axi_vote.uncompressed_bw = 0; + to_be_applied_axi_vote.compressed_bw = 0; + apply_bw_update = false; + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE && + top_priv->cpashdl_type[i] == + cpashdl_type) { + sum.uncompressed_bw += top_priv->req_axi_vote[i].uncompressed_bw; - sum.compressed_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); - top_priv->last_vote[top_priv->last_counter] = sum; - top_priv->last_counter = (top_priv->last_counter + 1) % - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - - 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", + 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); - return 0; - } + top_priv->applied_axi_vote.compressed_bw, + sum.uncompressed_bw, + sum.compressed_bw); - if (start_stop == true) { - /* need to vote current request immediately */ - to_be_applied_axi_vote = sum; - /* Reset everything, we can start afresh */ - memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * - (CAM_VFE_TOP_VER2_MUX_MAX * - CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); - top_priv->last_counter = 0; - top_priv->last_vote[top_priv->last_counter] = sum; - top_priv->last_counter = (top_priv->last_counter + 1) % + last_vote = top_priv->last_vote[cpashdl_type]; + + last_vote[top_priv->last_counter[cpashdl_type]] = sum; + top_priv->last_counter[cpashdl_type] = + (top_priv->last_counter[cpashdl_type] + 1) % (CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); - } else { + + 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); + return 0; + } + + if (start_stop == true) { + rc = cam_cpas_update_axi_vote( + soc_private->cpas_handle[cpashdl_type], + &to_be_applied_axi_vote); + if (!rc) { + top_priv->applied_axi_vote.uncompressed_bw = + to_be_applied_axi_vote.uncompressed_bw; + top_priv->applied_axi_vote.compressed_bw = + to_be_applied_axi_vote.compressed_bw; + } + return rc; + } + /* - * Find max bw request in last few frames. This will the bw - *that we want to vote to CPAS now. + * Find max bw request in last few frames. This is the bw + * that we want to vote to CPAS now. */ for (i = 0; i < (CAM_VFE_TOP_VER2_MUX_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES); i++) { if (to_be_applied_axi_vote.compressed_bw < - top_priv->last_vote[i].compressed_bw) + last_vote[i].compressed_bw) to_be_applied_axi_vote.compressed_bw = - top_priv->last_vote[i].compressed_bw; + last_vote[i].compressed_bw; if (to_be_applied_axi_vote.uncompressed_bw < - top_priv->last_vote[i].uncompressed_bw) + last_vote[i].uncompressed_bw) to_be_applied_axi_vote.uncompressed_bw = - top_priv->last_vote[i].uncompressed_bw; + last_vote[i].uncompressed_bw; } - } - if ((to_be_applied_axi_vote.uncompressed_bw != - top_priv->applied_axi_vote.uncompressed_bw) || - (to_be_applied_axi_vote.compressed_bw != - top_priv->applied_axi_vote.compressed_bw)) - apply_bw_update = true; + if ((to_be_applied_axi_vote.uncompressed_bw != + top_priv->applied_axi_vote.uncompressed_bw) || + (to_be_applied_axi_vote.compressed_bw != + top_priv->applied_axi_vote.compressed_bw)) + apply_bw_update = true; - CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update); + CAM_DBG(CAM_ISP, "apply_bw_update=%d", apply_bw_update); - if (apply_bw_update == true) { - rc = cam_cpas_update_axi_vote( - soc_private->cpas_handle, - &to_be_applied_axi_vote); - if (!rc) { - top_priv->applied_axi_vote.uncompressed_bw = + if (apply_bw_update == true) { + rc = cam_cpas_update_axi_vote( + soc_private->cpas_handle[cpashdl_type], + &to_be_applied_axi_vote); + if (!rc) { + top_priv->applied_axi_vote.uncompressed_bw = to_be_applied_axi_vote.uncompressed_bw; - top_priv->applied_axi_vote.compressed_bw = - to_be_applied_axi_vote.compressed_bw; - } else { - CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); + top_priv->applied_axi_vote.compressed_bw = + to_be_applied_axi_vote.compressed_bw; + } else { + CAM_ERR(CAM_ISP, "BW request failed, rc=%d", + rc); + } } } - return rc; } +static int cam_vfe_top_fs_update( + struct cam_vfe_top_ver2_priv *top_priv, + void *cmd_args, uint32_t arg_size) +{ + struct cam_vfe_fe_update_args *cmd_update = cmd_args; + + if (cmd_update->node_res->process_cmd) + return cmd_update->node_res->process_cmd(cmd_update->node_res, + CAM_ISP_HW_CMD_FE_UPDATE_IN_RD, cmd_args, arg_size); + + return 0; +} + static int cam_vfe_top_clock_update( struct cam_vfe_top_ver2_priv *top_priv, void *cmd_args, uint32_t arg_size) @@ -476,6 +510,14 @@ int cam_vfe_top_reserve(void *device_priv, break; } + if (acquire_args->res_id == CAM_ISP_HW_VFE_IN_RD) { + rc = cam_vfe_fe_ver1_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 = @@ -583,6 +625,7 @@ int cam_vfe_top_stop(void *device_priv, if ((mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) || (mux_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF_LITE) || + (mux_res->res_id == CAM_ISP_HW_VFE_IN_RD) || ((mux_res->res_id >= CAM_ISP_HW_VFE_IN_RDI0) && (mux_res->res_id <= CAM_ISP_HW_VFE_IN_RDI3))) { rc = mux_res->stop(mux_res); @@ -643,6 +686,10 @@ int cam_vfe_top_process_cmd(void *device_priv, uint32_t cmd_type, rc = cam_vfe_top_clock_update(top_priv, cmd_args, arg_size); break; + case CAM_ISP_HW_CMD_FE_UPDATE_IN_RD: + rc = cam_vfe_top_fs_update(top_priv, cmd_args, + arg_size); + break; case CAM_ISP_HW_CMD_BW_UPDATE: rc = cam_vfe_top_bw_update(top_priv, cmd_args, arg_size); @@ -669,6 +716,7 @@ int cam_vfe_top_ver2_init( 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; + struct cam_vfe_soc_private *soc_private = NULL; vfe_top = kzalloc(sizeof(struct cam_vfe_top), GFP_KERNEL); if (!vfe_top) { @@ -684,14 +732,22 @@ int cam_vfe_top_ver2_init( rc = -ENOMEM; goto free_vfe_top; } + + soc_private = soc_info->soc_private; + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error! soc_private NULL"); + rc = -ENODEV; + goto free_vfe_top_priv; + } vfe_top->top_priv = top_priv; top_priv->hw_clk_rate = 0; top_priv->applied_axi_vote.compressed_bw = 0; top_priv->applied_axi_vote.uncompressed_bw = 0; memset(top_priv->last_vote, 0x0, sizeof(struct cam_axi_vote) * - (CAM_VFE_TOP_VER2_MUX_MAX * + (CAM_VFE_TOP_VER2_MUX_MAX * CAM_CPAS_HANDLE_MAX * CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)); - top_priv->last_counter = 0; + top_priv->last_counter[0] = 0; + top_priv->last_counter[1] = 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; @@ -707,6 +763,7 @@ int cam_vfe_top_ver2_init( 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; + top_priv->cpashdl_type[i] = CAM_CPAS_HANDLE_CAMIF; rc = cam_vfe_camif_ver2_init(hw_intf, soc_info, &ver2_hw_info->camif_hw_info, @@ -717,6 +774,13 @@ int cam_vfe_top_ver2_init( CAM_VFE_CAMIF_LITE_VER_2_0) { top_priv->mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_CAMIF_LITE; + if (soc_private->cpas_version == + CAM_CPAS_TITAN_175_V120) + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_RAW; + else + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_CAMIF; rc = cam_vfe_camif_lite_ver2_init(hw_intf, soc_info, &ver2_hw_info->camif_lite_hw_info, @@ -729,12 +793,30 @@ int cam_vfe_top_ver2_init( /* set the RDI resource id */ top_priv->mux_rsrc[i].res_id = CAM_ISP_HW_VFE_IN_RDI0 + j++; + if (soc_private->cpas_version == + CAM_CPAS_TITAN_175_V120) + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_RAW; + else + top_priv->cpashdl_type[i] = + CAM_CPAS_HANDLE_CAMIF; 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; + } else if (ver2_hw_info->mux_type[i] == + CAM_VFE_IN_RD_VER_1_0) { + /* set the RD resource id */ + top_priv->mux_rsrc[i].res_id = + CAM_ISP_HW_VFE_IN_RD; + + rc = cam_vfe_fe_ver1_init(hw_intf, soc_info, + &ver2_hw_info->fe_hw_info, + &top_priv->mux_rsrc[i]); + if (rc) + goto deinit_resources; } else { CAM_WARN(CAM_ISP, "Invalid mux type: %u", ver2_hw_info->mux_type[i]); @@ -769,6 +851,12 @@ deinit_resources: if (cam_vfe_camif_lite_ver2_deinit( &top_priv->mux_rsrc[i])) CAM_ERR(CAM_ISP, "Camif lite deinit failed"); + } else if (ver2_hw_info->mux_type[i] == + CAM_ISP_HW_VFE_IN_RDI0) { + if (cam_vfe_rdi_ver2_init(hw_intf, soc_info, + &ver2_hw_info->rdi_hw_info, + &top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "RDI deinit failed"); } else { if (cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i])) CAM_ERR(CAM_ISP, "RDI Deinit failed"); @@ -776,7 +864,7 @@ deinit_resources: top_priv->mux_rsrc[i].res_state = CAM_ISP_RESOURCE_STATE_UNAVAILABLE; } - +free_vfe_top_priv: kfree(vfe_top->top_priv); free_vfe_top: kfree(vfe_top); @@ -829,6 +917,12 @@ int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top_ptr) rc = cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]); if (rc) CAM_ERR(CAM_ISP, "RDI deinit failed rc=%d", rc); + } else if (top_priv->mux_rsrc[i].res_type == + CAM_VFE_IN_RD_VER_1_0) { + rc = cam_vfe_fe_ver1_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); } } diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h index 11ca78cd8a2e..33435df476d1 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.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 @@ -16,8 +16,9 @@ #include "cam_vfe_camif_ver2.h" #include "cam_vfe_camif_lite_ver2.h" #include "cam_vfe_rdi.h" +#include "cam_vfe_fe_ver1.h" -#define CAM_VFE_TOP_VER2_MUX_MAX 5 +#define CAM_VFE_TOP_VER2_MUX_MAX 6 enum cam_vfe_top_ver2_module_type { CAM_VFE_TOP_VER2_MODULE_LENS, @@ -55,6 +56,7 @@ struct cam_vfe_top_ver2_hw_info { struct cam_vfe_camif_ver2_hw_info camif_hw_info; struct cam_vfe_camif_lite_ver2_hw_info camif_lite_hw_info; struct cam_vfe_rdi_ver2_hw_info rdi_hw_info; + struct cam_vfe_fe_ver1_hw_info fe_hw_info; uint32_t mux_type[CAM_VFE_TOP_VER2_MUX_MAX]; }; diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h index 90c75291bd73..cee2b4a96cb4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h +++ b/drivers/media/platform/msm/camera_v3/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.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 @@ -24,7 +24,8 @@ #define CAM_VFE_CAMIF_LITE_VER_2_0 0x02 -#define CAM_VFE_RDI_VER_1_0 0x1000 +#define CAM_VFE_RDI_VER_1_0 0x1000 +#define CAM_VFE_IN_RD_VER_1_0 0x2000 struct cam_vfe_top { void *top_priv; diff --git a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 24bb154f922c..f27b54a81e4a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -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 @@ -258,7 +258,7 @@ static int cam_jpeg_insert_cdm_change_base( struct cam_jpeg_hw_ctx_data *ctx_data, struct cam_jpeg_hw_mgr *hw_mgr) { - int rc; + int rc = 0; uint32_t dev_type; struct cam_cdm_bl_request *cdm_cmd; uint32_t size; @@ -275,6 +275,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); @@ -713,7 +719,7 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return -EINVAL; } - rc = cam_packet_util_validate_packet(packet); + rc = cam_packet_util_validate_packet(packet, prepare_args->remain_len); if (rc) { CAM_ERR(CAM_JPEG, "invalid packet %d", rc); return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile b/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile index 5e46bf2531f8..83a580c23bc2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include/ obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw_mgr/ diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h index dc1c8f4c10aa..b8d0357f6f3d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.h +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/cam_lrme_context.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 @@ -19,7 +19,7 @@ #include "cam_req_mgr_interface.h" #include "cam_sync_api.h" -#define CAM_LRME_CTX_INDEX_SHIFT 16 +#define CAM_LRME_CTX_INDEX_SHIFT 32 /** * struct cam_lrme_context diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile index a048afece9db..2a4fba727773 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/Makefile @@ -7,7 +7,7 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cdm ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw -ccflags-y += -Idrivers/media/platform/msm/camera +ccflags-y += -Idrivers/media/platform/msm/camera_v3 ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_cpas/include obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/ diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 0c236462b7f5..11e9069b3c79 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -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 @@ -83,7 +83,8 @@ static int cam_lrme_mgr_util_get_device(struct cam_lrme_hw_mgr *hw_mgr, return 0; } -static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet) +static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet, + size_t remain_len) { struct cam_cmd_buf_desc *cmd_desc = NULL; int i, rc; @@ -105,7 +106,7 @@ static int cam_lrme_mgr_util_packet_validate(struct cam_packet *packet) packet->patch_offset, packet->num_patches, packet->kmd_cmd_buf_offset, packet->kmd_cmd_buf_index); - if (cam_packet_util_validate_packet(packet)) { + if (cam_packet_util_validate_packet(packet, remain_len)) { CAM_ERR(CAM_LRME, "invalid packet:%d %d %d %d %d", packet->kmd_cmd_buf_index, packet->num_cmd_buf, packet->cmd_buf_offset, @@ -166,13 +167,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,6 +180,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, 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", @@ -194,6 +194,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, 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 = @@ -209,6 +215,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 = @@ -841,7 +853,7 @@ static int cam_lrme_mgr_hw_prepare_update(void *hw_mgr_priv, goto error; } - rc = cam_lrme_mgr_util_packet_validate(args->packet); + rc = cam_lrme_mgr_util_packet_validate(args->packet, args->remain_len); if (rc) { CAM_ERR(CAM_LRME, "Error in packet validation %d", rc); goto error; diff --git a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 8cb1c9c28e7a..4220e5993dd5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -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 @@ -42,7 +42,10 @@ static void cam_lrme_hw_util_fill_fe_reg(struct cam_lrme_hw_io_buffer *io_buf, uint32_t reg_val; /* 1. config buffer size */ - reg_val = io_buf->io_cfg->planes[0].width; + if (io_buf->io_cfg->format == CAM_FORMAT_PLAIN16_10) + reg_val = io_buf->io_cfg->planes[0].width * 2; + else + reg_val = io_buf->io_cfg->planes[0].width; reg_val |= (io_buf->io_cfg->planes[0].height << 16); cam_lrme_cdm_write_reg_val_pair(reg_val_pair, num_cmd, hw_info->bus_rd_reg.bus_client_reg[index].rd_buffer_size, @@ -736,6 +739,11 @@ int cam_lrme_hw_process_irq(void *priv, void *data) mutex_lock(&lrme_hw->hw_mutex); + if (lrme_hw->hw_state == CAM_HW_STATE_POWER_DOWN) { + CAM_DBG(CAM_LRME, "LRME HW is in off state"); + goto end; + } + if (top_irq_status & (1 << 3)) { CAM_DBG(CAM_LRME, "Error"); rc = cam_lrme_hw_util_process_err(lrme_hw); @@ -895,7 +903,7 @@ int cam_lrme_hw_stop(void *hw_priv, void *hw_stop_args, uint32_t arg_size) lrme_core->state = CAM_LRME_CORE_STATE_INIT; } else { CAM_ERR(CAM_LRME, "HW in wrong state %d", lrme_core->state); - return -EINVAL; + rc = -EINVAL; } unlock: diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c index 2d17f7b51cd7..284742ef33ee 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -23,6 +23,7 @@ #include "cam_debug_util.h" static struct cam_mem_table tbl; +static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); static int cam_mem_util_map_cpu_va(struct ion_handle *hdl, uintptr_t *vaddr, @@ -108,6 +109,7 @@ int cam_mem_mgr_init(void) tbl.bufq[i].buf_handle = -1; } mutex_init(&tbl.m_lock); + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); return rc; bitmap_fail: @@ -151,6 +153,11 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, { int rc = 0, idx; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "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; @@ -191,6 +198,11 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) uintptr_t kvaddr = 0; size_t klen = 0; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!buf_handle || !vaddr_ptr || !len) return -EINVAL; @@ -241,12 +253,24 @@ exit_func: } EXPORT_SYMBOL(cam_mem_get_cpu_buf); +int cam_mem_put_cpu_buf(int32_t buf_handle) +{ + int rc = 0; + return rc; +} +EXPORT_SYMBOL(cam_mem_put_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 (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd) return -EINVAL; @@ -409,11 +433,6 @@ static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) { - if (!cmd->flags) { - CAM_ERR(CAM_MEM, "Invalid flags"); - return -EINVAL; - } - if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", CAM_MEM_MMU_MAX_HANDLE); @@ -528,6 +547,11 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) dma_addr_t hw_vaddr = 0; size_t len; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd) { CAM_ERR(CAM_MEM, " Invalid argument"); return -EINVAL; @@ -626,6 +650,11 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) dma_addr_t hw_vaddr = 0; size_t len = 0; + if (!atomic_read(&cam_mem_mgr_state)) { + CAM_ERR(CAM_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd || (cmd->fd < 0)) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; @@ -811,6 +840,7 @@ 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); @@ -899,6 +929,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!cmd) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; @@ -946,6 +981,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp || !out) { CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; @@ -1064,6 +1104,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; @@ -1113,6 +1158,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp || !out) { CAM_ERR(CAM_MEM, "Invalid param(s)"); return -EINVAL; @@ -1205,6 +1255,11 @@ 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_CRM, "failed. mem_mgr not initialized"); + return -EINVAL; + } + if (!inp) { CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.h index 92c366d723f9..73f0eb3d3425 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -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, diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h index 64258e8fb5ee..79945cff1dd2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_mem_mgr_api.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 @@ -95,6 +95,15 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len); +/** + * @brief: This indicates end of CPU access + * + * @buf_handle: Handle for the buffer + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_mem_put_cpu_buf(int32_t buf_handle); + static inline bool cam_mem_is_secure_buf(int32_t buf_handle) { return CAM_MEM_MGR_IS_SECURE_HDL(buf_handle); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c index 275940f839e3..234c51453476 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -24,6 +24,31 @@ #include "cam_req_mgr_dev.h" static struct cam_req_mgr_core_device *g_crm_core_dev; +static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION]; + +void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link) +{ + link->link_hdl = 0; + link->num_devs = 0; + link->max_delay = CAM_PIPELINE_DELAY_0; + link->workq = NULL; + link->pd_mask = 0; + link->l_dev = NULL; + link->req.in_q = NULL; + link->req.l_tbl = NULL; + link->req.num_tbl = 0; + link->watchdog = NULL; + link->state = CAM_CRM_LINK_STATE_AVAILABLE; + link->parent = NULL; + link->subscribe_event = 0; + link->trigger_mask = 0; + link->sync_link = 0; + link->sync_link_sof_skip = false; + link->open_req_cnt = 0; + link->last_flush_id = 0; + link->initial_sync_req = -1; + link->in_msync_mode = false; +} void cam_req_mgr_handle_core_shutdown(void) { @@ -117,31 +142,35 @@ static void __cam_req_mgr_dec_idx(int32_t *val, int32_t step, int32_t max_val) } /** - * __cam_req_mgr_validate_inject_delay() + * __cam_req_mgr_inject_delay() * - * @brief : Check if any pd device is introducing inject delay + * @brief : Check if any pd device is injecting delay * @tbl : cam_req_mgr_req_tbl * @curr_idx : slot idx * * @return : 0 for success, negative for failure */ -static int __cam_req_mgr_validate_inject_delay( +static int __cam_req_mgr_inject_delay( struct cam_req_mgr_req_tbl *tbl, int32_t curr_idx) { struct cam_req_mgr_tbl_slot *slot = NULL; + int rc = 0; while (tbl) { slot = &tbl->slot[curr_idx]; if (slot->inject_delay > 0) { slot->inject_delay--; - return -EAGAIN; + CAM_DBG(CAM_CRM, + "Delay injected by pd %d device", + tbl->pd); + rc = -EAGAIN; } __cam_req_mgr_dec_idx(&curr_idx, tbl->pd_delta, tbl->num_slots); tbl = tbl->next; } - return 0; + return rc; } /** @@ -183,19 +212,6 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status, traverse_data->in_q->slot[curr_idx].skip_idx); - if ((traverse_data->self_link == true) && - (!traverse_data->inject_delay_chk)) { - rc = __cam_req_mgr_validate_inject_delay(tbl, curr_idx); - if (rc) { - CAM_DBG(CAM_CRM, "Injecting Delay of one frame"); - apply_data[tbl->pd].req_id = -1; - /* This pd tbl not ready to proceed with asked idx */ - SET_FAILURE_BIT(traverse_data->result, tbl->pd); - return -EAGAIN; - } - traverse_data->inject_delay_chk = true; - } - /* 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 || @@ -356,6 +372,30 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, } /** + * __cam_req_mgr_check_for_lower_pd_devices() + * + * @brief : Checks if there are any devices on the link having a lesser + * pd than the max pd of the link + * @link : Pointer to link which needs to be checked + * + * @return : 0 if a lower pd device is found negative otherwise + */ +static int __cam_req_mgr_check_for_lower_pd_devices( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + if (dev->dev_info.p_delay < link->max_delay) + return 0; + } + + return -EAGAIN; +} + +/** * __cam_req_mgr_check_next_req_slot() * * @brief : While streaming if input queue does not contain any pending @@ -363,11 +403,14 @@ static void __cam_req_mgr_reset_req_slot(struct cam_req_mgr_core_link *link, * devices with lower pipeline delay value. * @in_q : Pointer to input queue where req mgr wil peep into * + * @return : 0 for success, negative for failure */ -static void __cam_req_mgr_check_next_req_slot( - struct cam_req_mgr_req_queue *in_q) +static int __cam_req_mgr_check_next_req_slot( + struct cam_req_mgr_core_link *link) { - int32_t idx = in_q->rd_idx; + int rc = 0; + struct cam_req_mgr_req_queue *in_q = link->req.in_q; + int32_t idx = in_q->rd_idx; struct cam_req_mgr_slot *slot; __cam_req_mgr_inc_idx(&idx, 1, in_q->num_slots); @@ -377,12 +420,20 @@ static void __cam_req_mgr_check_next_req_slot( /* Check if there is new req from CSL, if not complete req */ if (slot->status == CRM_SLOT_STATUS_NO_REQ) { + rc = __cam_req_mgr_check_for_lower_pd_devices(link); + if (rc) { + CAM_DBG(CAM_CRM, "No lower pd devices on link 0x%x", + link->link_hdl); + return rc; + } __cam_req_mgr_in_q_skip_idx(in_q, idx); if (in_q->wr_idx != idx) CAM_WARN(CAM_CRM, "CHECK here wr %d, rd %d", in_q->wr_idx, idx); __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); } + + return rc; } /** @@ -483,8 +534,6 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, continue; } - trace_cam_req_mgr_apply_request(link, &apply_req, dev); - apply_req.trigger_point = trigger; CAM_DBG(CAM_REQ, "SEND: link_hdl: %x pd %d req_id %lld", @@ -497,6 +546,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, if (pd == link->max_delay) link->open_req_cnt--; } + trace_cam_req_mgr_apply_request(link, &apply_req, dev); } } if (rc < 0) { @@ -526,14 +576,12 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, * 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) + int32_t idx, bool validate_only) { int rc; struct cam_req_mgr_traverse traverse_data; @@ -555,19 +603,16 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.in_q = in_q; traverse_data.result = 0; traverse_data.validate_only = validate_only; - traverse_data.self_link = self_link; - traverse_data.inject_delay_chk = false; traverse_data.open_req_cnt = link->open_req_cnt; + /* * 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); + "SOF: idx %d result %x pd_mask %x rc %d", + idx, traverse_data.result, link->pd_mask, rc); if (!rc && traverse_data.result == link->pd_mask) { CAM_DBG(CAM_CRM, @@ -616,113 +661,218 @@ static int32_t __cam_req_mgr_find_slot_for_req( } /** - * __cam_req_mgr_reset_sof_cnt() + * __cam_req_mgr_check_sync_for_mslave() * - * @brief : the sof_count for both the links are reset - * @link : pointer to link whose input queue and req tbl are + * @brief : Processes requests during sync mode [master-slave] + * Here master corresponds to the link having a higher + * max_delay (pd) compared to the slave link. + * @link : Pointer to link whose input queue and req tbl are * traversed through + * @slot : Pointer to the current slot being processed + * @return : 0 for success, negative for failure * */ -static void __cam_req_mgr_reset_sof_cnt( - struct cam_req_mgr_core_link *link) +static int __cam_req_mgr_check_sync_for_mslave( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) { - link->sof_counter = -1; - link->sync_link->sof_counter = -1; - link->frame_skip_flag = false; + struct cam_req_mgr_core_link *sync_link = NULL; + struct cam_req_mgr_slot *sync_slot = NULL; + int sync_slot_idx = 0, prev_idx, next_idx, rd_idx, sync_rd_idx, rc = 0; + int64_t req_id = 0, sync_req_id = 0; - 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); -} + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } -/** - * __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; + sync_link = link->sync_link; + req_id = slot->req_id; + sync_rd_idx = sync_link->req.in_q->rd_idx; CAM_DBG(CAM_CRM, - "link_hdl %x self_counter %lld other_counter %lld", - link->link_hdl, link->sof_counter, - link->sync_link->sof_counter); -} + "link_hdl %x req %lld frame_skip_flag %d open_req_cnt:%d initial_sync_req [%lld,%lld] is_master:%d", + link->link_hdl, req_id, link->sync_link_sof_skip, + link->open_req_cnt, link->initial_sync_req, + sync_link->initial_sync_req, link->is_master); -/** - * __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; + if (sync_link->sync_link_sof_skip) { + CAM_DBG(CAM_CRM, + "No req applied on corresponding SOF on sync link: %x", + sync_link->link_hdl); + sync_link->sync_link_sof_skip = false; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; + } - 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); -} + if (link->in_msync_mode && + sync_link->in_msync_mode && + (req_id - sync_link->req.in_q->slot[sync_rd_idx].req_id > + link->max_delay - sync_link->max_delay)) { + CAM_DBG(CAM_CRM, + "Req: %lld on link:%x need to hold for link: %x req:%d", + req_id, + link->link_hdl, + sync_link->link_hdl, + sync_link->req.in_q->slot[sync_rd_idx].req_id); + return -EINVAL; + } -/** - * __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->is_master) { + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + if (sync_link->initial_skip) { + CAM_DBG(CAM_CRM, "Link 0x%x [slave] not streamed on", + sync_link->link_hdl); + return -EAGAIN; + } - if (link->sof_counter == MAX_SYNC_COUNT) - __cam_req_mgr_wrap_sof_cnt(link); + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [master] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } - sync_diff = link->sof_counter - sync_link->sof_counter; + prev_idx = slot->idx; + __cam_req_mgr_dec_idx(&prev_idx, + (link->max_delay - sync_link->max_delay), + link->req.in_q->num_slots); + + rd_idx = sync_link->req.in_q->rd_idx; + sync_req_id = link->req.in_q->slot[prev_idx].req_id; + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not found on link: %x [slave]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } - 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; + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + ((sync_slot_idx - rd_idx) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Prev Req: %lld [master] not next on link: %x [slave]", + sync_req_id, + sync_link->link_hdl); + return -EINVAL; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && + (sync_link->req.in_q->slot[sync_slot_idx].status + != CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [slave] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } + } else { + if (link->initial_skip) + link->initial_skip = false; + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [slave] not ready on link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + + next_idx = link->req.in_q->rd_idx; + rd_idx = sync_link->req.in_q->rd_idx; + __cam_req_mgr_inc_idx(&next_idx, + (sync_link->max_delay - link->max_delay), + link->req.in_q->num_slots); + + sync_req_id = link->req.in_q->slot[next_idx].req_id; + + if ((sync_link->initial_sync_req != -1) && + (sync_link->initial_sync_req <= sync_req_id)) { + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, sync_req_id); + if (sync_slot_idx == -1) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not found on link: %x [master]", + sync_req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; + } + + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + ((sync_slot_idx - rd_idx) >= 1) && + (sync_link->req.in_q->slot[rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not next on link: %x [master]", + sync_req_id, sync_link->link_hdl); + return -EINVAL; + } + + sync_slot = &sync_link->req.in_q->slot[sync_slot_idx]; + rc = __cam_req_mgr_check_link_is_ready(sync_link, + sync_slot_idx, true); + if (rc && (sync_slot->status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Next Req: %lld [slave] not ready on [master] link: %x, rc=%d", + sync_req_id, sync_link->link_hdl, rc); + link->sync_link_sof_skip = true; + return rc; + } + } } - return rc; + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); + + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; } /** - * __cam_req_mgr_process_sync_req() + * __cam_req_mgr_check_sync_request_is_ready() * * @brief : processes requests during sync mode * @link : pointer to link whose input queue and req tbl are @@ -731,13 +881,13 @@ static int __cam_req_mgr_validate_sof_cnt( * @return : 0 for success, negative for failure * */ -static int __cam_req_mgr_process_sync_req( +static int __cam_req_mgr_check_sync_req_is_ready( struct cam_req_mgr_core_link *link, struct cam_req_mgr_slot *slot) { struct cam_req_mgr_core_link *sync_link = NULL; int64_t req_id = 0; - int sync_slot_idx = 0, rc = 0; + int sync_slot_idx = 0, sync_rd_idx = 0, rc = 0; if (!link->sync_link) { CAM_ERR(CAM_CRM, "Sync link null"); @@ -748,94 +898,81 @@ static int __cam_req_mgr_process_sync_req( req_id = slot->req_id; CAM_DBG(CAM_REQ, - "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); + "link_hdl %x req %lld frame_skip_flag %d ", + link->link_hdl, req_id, link->sync_link_sof_skip); if (sync_link->sync_link_sof_skip) { CAM_DBG(CAM_REQ, "No req applied on corresponding SOF on sync link: %x", sync_link->link_hdl); sync_link->sync_link_sof_skip = false; - /*It is to manage compensate inject delay for each pd*/ - __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); - return -EINVAL; + __cam_req_mgr_inject_delay(link->req.l_tbl, slot->idx); + return -EAGAIN; } - 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_REQ, "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_inject_delay(link->req.l_tbl, slot->idx); + if (rc) { + CAM_DBG(CAM_CRM, + "Skip Process Req: %lld on link: %x", + req_id, link->link_hdl); + link->sync_link_sof_skip = true; + return rc; } - rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true); if (rc) { - CAM_DBG(CAM_REQ, + CAM_DBG(CAM_CRM, "Req: %lld [My link] not ready on link: %x, rc=%d", req_id, link->link_hdl, rc); link->sync_link_sof_skip = true; - goto failure; + return rc; } 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) { + CAM_DBG(CAM_CRM, "Req: %lld not found on link: %x [other link]", + req_id, sync_link->link_hdl); + link->sync_link_sof_skip = true; + return -EINVAL; } - 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_REQ, - "Req: %lld ready to apply on link: %x [validation successful]", - req_id, link->link_hdl); - /* - * At this point all validation is successfully done - * and we can proceed to apply the given request. - * Ideally the next call should return success. - */ - rc = __cam_req_mgr_check_link_is_ready(link, - slot->idx, false, true); - - if (rc) - CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); - } else { - CAM_DBG(CAM_REQ, - "Req: %lld [Other link] not ready to apply on link: %x", + sync_rd_idx = sync_link->req.in_q->rd_idx; + if ((sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED) && + ((sync_slot_idx - sync_rd_idx) >= 1) && + (sync_link->req.in_q->slot[sync_rd_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld [other link] not next req to be applied on link: %x", req_id, sync_link->link_hdl); - rc = -EPERM; + return -EAGAIN; + } + + rc = __cam_req_mgr_check_link_is_ready(sync_link, sync_slot_idx, true); + if (rc && (sync_link->req.in_q->slot[sync_slot_idx].status != + CRM_SLOT_STATUS_REQ_APPLIED)) { + CAM_DBG(CAM_CRM, + "Req: %lld not ready on [other link] link: %x, rc=%d", + req_id, sync_link->link_hdl, rc); link->sync_link_sof_skip = true; - goto failure; + return rc; } - return rc; + CAM_DBG(CAM_REQ, + "Req: %lld ready to apply on link: %x [validation successful]", + req_id, link->link_hdl); -failure: - link->sof_counter--; - return rc; + /* + * At this point all validation is successfully done + * and we can proceed to apply the given request. + * Ideally the next call should return success. + */ + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, false); + if (rc) + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + + return 0; } /** @@ -852,6 +989,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, uint32_t trigger) { int rc = 0, idx; + int reset_step = 0; struct cam_req_mgr_slot *slot = NULL; struct cam_req_mgr_req_queue *in_q; struct cam_req_mgr_core_session *session; @@ -896,11 +1034,41 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, 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 ((slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) && + (link->sync_link)) { + if (link->is_master || link->sync_link->is_master) { + if (!link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = true; + } + + rc = __cam_req_mgr_check_sync_for_mslave( + link, slot); + } else { + rc = __cam_req_mgr_check_sync_req_is_ready( + link, slot); + } + } else { + if (link->in_msync_mode) { + CAM_DBG(CAM_CRM, + "Settings master-slave non sync mode for link 0x%x", + link->link_hdl); + link->in_msync_mode = false; + link->initial_sync_req = -1; + if (link->sync_link) { + link->sync_link->initial_sync_req = -1; + link->sync_link->in_msync_mode = false; + } + } + + rc = __cam_req_mgr_inject_delay(link->req.l_tbl, + slot->idx); + if (!rc) + rc = __cam_req_mgr_check_link_is_ready(link, + slot->idx, false); + } if (rc < 0) { /* @@ -954,8 +1122,15 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, slot->req_id, link->link_hdl); idx = in_q->rd_idx; + reset_step = link->max_delay; + if (link->sync_link) { + if ((link->in_msync_mode) && + (link->sync_link->is_master)) + reset_step = + link->sync_link->max_delay; + } __cam_req_mgr_dec_idx( - &idx, link->max_delay + 1, + &idx, reset_step + 1, in_q->num_slots); __cam_req_mgr_reset_req_slot(link, idx); } @@ -1344,25 +1519,25 @@ static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link( session->num_links, MAXIMUM_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; + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + if (!atomic_cmpxchg(&g_links[i].is_used, 0, 1)) { + link = &g_links[i]; + CAM_DBG(CAM_CRM, "alloc link index %d", i); + cam_req_mgr_core_link_reset(link); + break; + } } + if (i == MAXIMUM_LINKS_PER_SESSION) + return NULL; + in_q = (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, @@ -1399,7 +1574,6 @@ static struct cam_req_mgr_core_link *__cam_req_mgr_reserve_link( return link; error: mutex_unlock(&session->lock); - kfree(link); kfree(in_q); return NULL; } @@ -1414,9 +1588,12 @@ error: */ static void __cam_req_mgr_free_link(struct cam_req_mgr_core_link *link) { + ptrdiff_t i; kfree(link->req.in_q); link->req.in_q = NULL; - kfree(link); + i = link - g_links; + CAM_DBG(CAM_CRM, "free link index %d", i); + atomic_set(&g_links[i].is_used, 0); } /** @@ -1450,21 +1627,14 @@ static void __cam_req_mgr_unreserve_link( for (i = 0; i < MAXIMUM_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 < MAXIMUM_LINKS_PER_SESSION; i++) { - if (session->links[i]) + if (link->sync_link) { + if (link->sync_link == session->links[i]) session->links[i]->sync_link = NULL; } } + link->sync_link = NULL; session->num_links--; CAM_DBG(CAM_CRM, "Active session links (%d)", session->num_links); mutex_unlock(&session->lock); @@ -1544,6 +1714,9 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) mutex_lock(&link->req.lock); if (flush_info->flush_type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + link->last_flush_id = flush_info->req_id; + CAM_INFO(CAM_CRM, "Last request id to flush is %lld", + flush_info->req_id); for (i = 0; i < in_q->num_slots; i++) { slot = &in_q->slot[i]; slot->req_id = -1; @@ -1559,21 +1732,20 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) if (idx < 0) { CAM_ERR(CAM_CRM, "req_id %lld not found in input queue", flush_info->req_id); - mutex_unlock(&link->req.lock); - return -EINVAL; - } - 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; + } 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); } - __cam_req_mgr_in_q_skip_idx(in_q, idx); } for (i = 0; i < link->num_devs; i++) { @@ -1622,9 +1794,11 @@ int cam_req_mgr_process_sched_req(void *priv, void *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", + CAM_DBG(CAM_CRM, + "link_hdl %x req_id %lld at slot %d sync_mode %d is_master:%d", sched_req->link_hdl, sched_req->req_id, - in_q->wr_idx, sched_req->sync_mode); + in_q->wr_idx, sched_req->sync_mode, + link->is_master); mutex_lock(&link->req.lock); slot = &in_q->slot[in_q->wr_idx]; @@ -1640,6 +1814,16 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) slot->recover = sched_req->bubble_enable; link->open_req_cnt++; __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + + if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + if (link->initial_sync_req == -1) + link->initial_sync_req = slot->req_id; + } else { + link->initial_sync_req = -1; + if (link->sync_link) + link->sync_link->initial_sync_req = -1; + } + mutex_unlock(&link->req.lock); end: @@ -1736,8 +1920,9 @@ int cam_req_mgr_process_add_req(void *priv, void *data) trace_cam_req_mgr_add_req(link, idx, add_req, tbl, device); if (slot->req_ready_map == tbl->dev_mask) { - CAM_DBG(CAM_REQ, "idx %d req_id %lld pd %d SLOT READY", - idx, add_req->req_id, tbl->pd); + CAM_DBG(CAM_REQ, + "link 0x%x idx %d req_id %lld pd %d SLOT READY", + link->link_hdl, idx, add_req->req_id, tbl->pd); slot->state = CRM_REQ_STATE_READY; } mutex_unlock(&link->req.lock); @@ -1895,14 +2080,22 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) * 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", + 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); + rc = __cam_req_mgr_check_next_req_slot(link); + if (rc) { + CAM_DBG(CAM_REQ, + "No pending req to apply to lower pd devices"); + rc = 0; + goto release_lock; + } __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); } + rc = __cam_req_mgr_process_req(link, trigger_data->trigger); - mutex_unlock(&link->req.lock); +release_lock: + mutex_unlock(&link->req.lock); end: return rc; } @@ -2368,7 +2561,8 @@ static int __cam_req_mgr_unlink(struct cam_req_mgr_core_link *link) if (rc < 0) { CAM_ERR(CAM_CRM, "error destroying link hdl %x rc %d", link->link_hdl, rc); - } + } else + link->link_hdl = -1; mutex_unlock(&link->lock); return rc; @@ -2445,16 +2639,17 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) return -EINVAL; } + mutex_lock(&g_crm_core_dev->crm_lock); + /* session hdl's priv data is cam session struct */ cam_session = (struct cam_req_mgr_core_session *) cam_get_device_priv(link_info->session_hdl); if (!cam_session) { CAM_DBG(CAM_CRM, "NULL pointer"); + mutex_unlock(&g_crm_core_dev->crm_lock); 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) { @@ -2478,6 +2673,7 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) goto link_hdl_fail; } link_info->link_hdl = link->link_hdl; + link->last_flush_id = 0; /* Allocate memory to hold data of all linked devs */ rc = __cam_req_mgr_create_subdevs(&link->l_dev, @@ -2524,7 +2720,7 @@ 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_info->link_hdl = -1; link_hdl_fail: mutex_unlock(&link->lock); __cam_req_mgr_unreserve_link(cam_session, link); @@ -2603,6 +2799,17 @@ int cam_req_mgr_schedule_request( goto end; } + if (sched_req->req_id <= link->last_flush_id) { + CAM_INFO(CAM_CRM, + "request %lld is flushed, last_flush_id to flush %d", + sched_req->req_id, link->last_flush_id); + rc = -EINVAL; + goto end; + } + + if (sched_req->req_id > link->last_flush_id) + link->last_flush_id = 0; + CAM_DBG(CAM_CRM, "link 0x%x req %lld, sync_mode %d", sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); @@ -2627,6 +2834,33 @@ end: return rc; } +/** + * __cam_req_mgr_set_master_link() + * + * @brief : Each links sets its max pd delay based on the devices on the + * link. The link with higher pd is assigned master. + * @link1 : One of the sync links + * @link2 : The other sync link + */ +static void __cam_req_mgr_set_master_link( + struct cam_req_mgr_core_link *link1, + struct cam_req_mgr_core_link *link2) +{ + + if (link1->max_delay > link2->max_delay) { + link1->is_master = true; + link2->initial_skip = true; + } else if (link2->max_delay > link1->max_delay) { + link2->is_master = true; + link1->initial_skip = true; + } + + CAM_DBG(CAM_CRM, + "link_hdl1[0x%x] is_master [%u] link_hdl2[0x%x] is_master[%u]", + link1->link_hdl, link1->is_master, + link2->link_hdl, link2->is_master); +} + int cam_req_mgr_sync_config( struct cam_req_mgr_sync_mode *sync_info) { @@ -2647,6 +2881,12 @@ int cam_req_mgr_sync_config( return -EINVAL; } + if ((sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_SYNC) && + (sync_info->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC)) { + CAM_ERR(CAM_CRM, "Invalid sync mode %d", sync_info->sync_mode); + return -EINVAL; + } + if ((!sync_info->link_hdls[0]) || (!sync_info->link_hdls[1])) { CAM_WARN(CAM_CRM, "Invalid link handles 0x%x 0x%x", sync_info->link_hdls[0], sync_info->link_hdls[1]); @@ -2683,17 +2923,27 @@ int cam_req_mgr_sync_config( 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; + link1->sync_link = NULL; - link2->sof_counter = -1; - link2->sync_self_ref = -1; - link2->frame_skip_flag = false; link2->sync_link_sof_skip = false; - link2->sync_link = link1; + link2->sync_link = NULL; + + link1->is_master = false; + link2->is_master = false; + link1->initial_skip = false; + link2->initial_skip = false; + + link1->in_msync_mode = false; + link2->in_msync_mode = false; + link1->initial_sync_req = -1; + link2->initial_sync_req = -1; + + if (sync_info->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) { + link1->sync_link = link2; + link2->sync_link = link1; + __cam_req_mgr_set_master_link(link1, link2); + } cam_session->sync_mode = sync_info->sync_mode; CAM_DBG(CAM_REQ, @@ -2791,7 +3041,8 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) goto end; } - if (control->num_links > MAX_LINKS_PER_SESSION) { + if ((control->num_links <= 0) || + (control->num_links > MAX_LINKS_PER_SESSION)) { CAM_ERR(CAM_CRM, "Invalid number of links %d", control->num_links); rc = -EINVAL; @@ -2860,6 +3111,7 @@ end: int cam_req_mgr_core_device_init(void) { + int i; CAM_DBG(CAM_CRM, "Enter g_crm_core_dev %pK", g_crm_core_dev); if (g_crm_core_dev) { @@ -2876,6 +3128,12 @@ int cam_req_mgr_core_device_init(void) mutex_init(&g_crm_core_dev->crm_lock); cam_req_mgr_debug_register(g_crm_core_dev); + for (i = 0; i < MAXIMUM_LINKS_PER_SESSION; i++) { + mutex_init(&g_links[i].lock); + spin_lock_init(&g_links[i].link_state_spin_lock); + atomic_set(&g_links[i].is_used, 0); + cam_req_mgr_core_link_reset(&g_links[i]); + } return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h index b7222237473b..9bff66b36ebb 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -135,9 +135,6 @@ enum cam_req_mgr_link_state { * @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 - * @inject_delay_chk : if inject delay has been validated for all pd devices * @open_req_cnt : Count of open requests yet to be serviced in the kernel. */ struct cam_req_mgr_traverse { @@ -147,8 +144,6 @@ struct cam_req_mgr_traverse { struct cam_req_mgr_apply *apply_data; struct cam_req_mgr_req_queue *in_q; bool validate_only; - bool self_link; - bool inject_delay_chk; int32_t open_req_cnt; }; @@ -308,15 +303,20 @@ struct cam_req_mgr_connected_device { * 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. * @open_req_cnt : Counter to keep track of open requests that are yet * to be serviced in the kernel. + * @last_flush_id : Last request to flush + * @is_used : 1 if link is in use else 0 + * @is_master : Based on pd among links, the link with the highest pd + * is assigned as master + * @initial_skip : Flag to determine if slave has started streaming in + * master-slave sync + * @in_msync_mode : Flag to determine if a link is in master-slave mode + * @initial_sync_req : The initial req which is required to sync with the + * other link * */ struct cam_req_mgr_core_link { @@ -336,11 +336,14 @@ struct cam_req_mgr_core_link { 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; int32_t open_req_cnt; + uint32_t last_flush_id; + atomic_t is_used; + bool is_master; + bool initial_skip; + bool in_msync_mode; + int64_t initial_sync_req; }; /** diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h index 1df3122109e6..1d1df45c6ea5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_interface.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -50,7 +50,7 @@ typedef int (*cam_req_mgr_add_req)(struct cam_req_mgr_add_request *); * @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_flush_req : Flush or cancel request * cam_req_mgr_process_evt : generic events */ typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *); diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c index 12bc3ac47a8e..de6a2dc519df 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -224,8 +224,8 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, 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, + kcalloc(crm_workq->task.num_task, + sizeof(struct crm_workq_task), GFP_KERNEL); if (!crm_workq->task.pool) { CAM_WARN(CAM_CRM, "Insufficient memory %zu", diff --git a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h index af76ae467346..c24ee31959d6 100644 --- a/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/media/platform/msm/camera_v3/cam_req_mgr/cam_req_mgr_workq.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -26,7 +26,8 @@ /* Flag to create a high priority workq */ #define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0) -/* This flag ensures only one task from a given +/* + * This flag ensures only one task from a given * workq will execute at any given point on any * given CPU. */ diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c index b2a7dc0784f4..1262db7646dc 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -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 @@ -17,6 +17,7 @@ #include "cam_trace.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" int32_t cam_actuator_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -214,12 +215,12 @@ static int32_t cam_actuator_i2c_modes_util( } int32_t cam_actuator_slaveInfo_pkt_parser(struct cam_actuator_ctrl_t *a_ctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_i2c_info *i2c_info; - if (!a_ctrl || !cmd_buf) { + if (!a_ctrl || !cmd_buf || (len < sizeof(struct cam_cmd_i2c_info))) { CAM_ERR(CAM_ACTUATOR, "Invalid Args"); return -EINVAL; } @@ -413,9 +414,11 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, int32_t i = 0; uint32_t total_cmd_buf_in_bytes = 0; size_t len_of_buff = 0; + size_t remain_len = 0; uint32_t *offset = NULL; uint32_t *cmd_buf = NULL; uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; struct common_header *cmm_hdr = NULL; struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; @@ -442,23 +445,36 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, sizeof(config))) return -EFAULT; rc = cam_mem_get_cpu_buf(config.packet_handle, - &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); return rc; } - if (config.offset > len_of_buff) { + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { CAM_ERR(CAM_ACTUATOR, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buff); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto rel_pkt_buf; } - csl_packet = - (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); - CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); + remain_len -= (size_t)config.offset; + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_ACTUATOR, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } + + CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); if ((csl_packet->header.op_code & 0xFFFFFF) != CAM_ACTUATOR_PACKET_OPCODE_INIT && @@ -467,7 +483,8 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "reject request %lld, last request to flush %lld", csl_packet->header.request_id, a_ctrl->last_flush_req); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } if (csl_packet->header.request_id > a_ctrl->last_flush_req) @@ -488,13 +505,22 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, &generic_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf"); - return rc; + goto rel_pkt_buf; } cmd_buf = (uint32_t *)generic_ptr; if (!cmd_buf) { CAM_ERR(CAM_ACTUATOR, "invalid cmd buf"); - return -EINVAL; + goto rel_cmd_buf; + } + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_ACTUATOR, + "Invalid length for sensor cmd"); + rc = -EINVAL; + goto rel_cmd_buf; } + remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmm_hdr = (struct common_header *)cmd_buf; @@ -503,11 +529,11 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "Received slave info buffer"); rc = cam_actuator_slaveInfo_pkt_parser( - a_ctrl, cmd_buf); + a_ctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to parse slave info: %d", rc); - return rc; + goto rel_cmd_buf; } break; case CAMERA_SENSOR_CMD_TYPE_PWR_UP: @@ -517,12 +543,12 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - power_info); + power_info, remain_len); if (rc) { CAM_ERR(CAM_ACTUATOR, "Failed:parse power settings: %d", rc); - return rc; + goto rel_cmd_buf; } break; default: @@ -542,10 +568,14 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_ERR(CAM_ACTUATOR, "Failed:parse init settings: %d", rc); - return rc; + goto rel_cmd_buf; } break; } + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_ACTUATOR, + "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); } if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) { @@ -553,7 +583,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (rc < 0) { CAM_ERR(CAM_ACTUATOR, " Actuator Power up failed"); - return rc; + goto rel_pkt_buf; } a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; } @@ -562,7 +592,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, &a_ctrl->i2c_data.init_settings); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings"); - return rc; + goto rel_pkt_buf; } /* Delete the request even if the apply is failed */ @@ -579,7 +609,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_WARN(CAM_ACTUATOR, "Not in right state to move lens: %d", a_ctrl->cam_act_state); - return rc; + goto rel_pkt_buf; } a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_NOW; @@ -599,7 +629,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Auto move lens parsing failed: %d", rc); - return rc; + goto rel_pkt_buf; } cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; @@ -609,7 +639,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_WARN(CAM_ACTUATOR, "Not in right state to move lens: %d", a_ctrl->cam_act_state); - return rc; + goto rel_pkt_buf; } a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_LATER; @@ -630,7 +660,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Manual move lens parsing failed: %d", rc); - return rc; + goto rel_pkt_buf; } cam_actuator_update_req_mgr(a_ctrl, csl_packet); @@ -640,13 +670,32 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, CAM_WARN(CAM_ACTUATOR, "Received NOP packets in invalid state: %d", a_ctrl->cam_act_state); - return -EINVAL; + goto rel_pkt_buf; } - cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; + default: + CAM_ERR(CAM_ACTUATOR, "Wrong Opcode: %d", + csl_packet->header.op_code & 0xFFFFFF); + rc = -EINVAL; + goto rel_pkt_buf; } + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_ACTUATOR, "Fail to put cmd buffer: %llu", + config.packet_handle); + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_ACTUATOR, "Fail to put cmd buffer: %d", + cmd_desc[i].mem_handle); +rel_pkt_buf: + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_ACTUATOR, "Fail to put cmd buffer: %llu", + config.packet_handle); + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 26d73a446a5b..228ccb8a39b3 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -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 @@ -216,9 +216,7 @@ static int32_t cam_actuator_driver_i2c_probe(struct i2c_client *client, 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->last_flush_req = 0; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; return rc; @@ -245,19 +243,24 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev) return 0; } + CAM_INFO(CAM_ACTUATOR, "platform remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); + soc_private = (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; kfree(a_ctrl->io_master_info.cci_client); a_ctrl->io_master_info.cci_client = NULL; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; kfree(a_ctrl->soc_info.soc_private); + a_ctrl->soc_info.soc_private = NULL; kfree(a_ctrl->i2c_data.per_frame); a_ctrl->i2c_data.per_frame = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); + platform_set_drvdata(pdev, NULL); devm_kfree(&pdev->dev, a_ctrl); return rc; @@ -265,7 +268,6 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev) 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; @@ -277,6 +279,11 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) return -EINVAL; } + CAM_INFO(CAM_ACTUATOR, "i2c remove invoked"); + mutex_lock(&(a_ctrl->actuator_mutex)); + cam_actuator_shutdown(a_ctrl); + mutex_unlock(&(a_ctrl->actuator_mutex)); + cam_unregister_subdev(&(a_ctrl->v4l2_dev_str)); soc_private = (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; @@ -284,14 +291,11 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) /*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); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; a_ctrl->soc_info.soc_private = NULL; + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, NULL); kfree(a_ctrl); - return rc; + + return 0; } static const struct of_device_id cam_actuator_driver_dt_match[] = { @@ -376,7 +380,6 @@ static int32_t cam_actuator_driver_platform_probe( a_ctrl->last_flush_req = 0; 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; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c index b0e810711c5d..f41cb4753f39 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_core.c @@ -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 @@ -892,20 +892,39 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, 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 - */ + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req == true) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - goto rel_mutex; + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto rel_master; } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -916,24 +935,24 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, master, queue); if (rc < 0) { CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); - goto rel_mutex; + goto rel_mutex_q; } if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { CAM_ERR(CAM_CCI, "More than max retries"); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->data == NULL) { CAM_ERR(CAM_CCI, "Data ptr is NULL"); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", read_cfg->addr_type); rc = -EINVAL; - goto rel_mutex; + goto rel_mutex_q; } CAM_DBG(CAM_CCI, "set param sid 0x%x retries %d id_map %d", @@ -945,14 +964,14 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, 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; + goto rel_mutex_q; } val = CCI_I2C_LOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); @@ -964,21 +983,21 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, 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; + goto rel_mutex_q; } val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_UNLOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR @@ -1009,7 +1028,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, cam_cci_dump_registers(cci_dev, master, queue); #endif cam_cci_flush_queue(cci_dev, master); - goto rel_mutex; + goto rel_mutex_q; } read_words = cam_io_r_mb(base + @@ -1090,7 +1109,7 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, master, queue); #endif cam_cci_flush_queue(cci_dev, master); - goto rel_mutex; + goto rel_mutex_q; } break; } @@ -1099,8 +1118,15 @@ static int32_t cam_cci_burst_read(struct v4l2_subdev *sd, CAM_DBG(CAM_CCI, "Burst read successful words_read %d", total_read_words); -rel_mutex: +rel_mutex_q: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); return rc; } @@ -1132,20 +1158,38 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, 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 - */ + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req == true) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { + mutex_unlock(&cci_dev->cci_master_info[master].mutex); CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - goto rel_mutex; + goto rel_master; } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + mutex_lock(&cci_dev->cci_master_info[master].mutex_q[queue]); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_read call. This is to @@ -1156,17 +1200,17 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, master, queue); if (rc < 0) { CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); - goto rel_mutex; + goto rel_mutex_q; } if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { CAM_ERR(CAM_CCI, "More than max retries"); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->data == NULL) { CAM_ERR(CAM_CCI, "Data ptr is NULL"); - goto rel_mutex; + goto rel_mutex_q; } CAM_DBG(CAM_CCI, "master %d, queue %d", master, queue); @@ -1179,21 +1223,21 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, 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; + goto rel_mutex_q; } val = CCI_I2C_LOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } if (read_cfg->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) { CAM_ERR(CAM_CCI, "failed : Invalid addr type: %u", read_cfg->addr_type); rc = -EINVAL; - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_WRITE_DISABLE_P_CMD | (read_cfg->addr_type << 4); @@ -1205,21 +1249,21 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, 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; + goto rel_mutex_q; } val = CCI_I2C_READ_CMD | (read_cfg->num_byte << 4); rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = CCI_I2C_UNLOCK_CMD; rc = cam_cci_write_i2c_queue(cci_dev, val, master, queue); if (rc < 0) { CAM_DBG(CAM_CCI, "failed rc: %d", rc); - goto rel_mutex; + goto rel_mutex_q; } val = cam_io_r_mb(base + CCI_I2C_M0_Q0_CUR_WORD_CNT_ADDR @@ -1247,7 +1291,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, "wait_for_completion_timeout rc = %d FIFO buf_lvl: 0x%x", rc, val); cam_cci_flush_queue(cci_dev, master); - goto rel_mutex; + goto rel_mutex_q; } else { rc = 0; } @@ -1260,7 +1304,7 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, read_words, exp_words); memset(read_cfg->data, 0, read_cfg->num_byte); rc = -EINVAL; - goto rel_mutex; + goto rel_mutex_q; } index = 0; CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); @@ -1284,8 +1328,15 @@ static int32_t cam_cci_read(struct v4l2_subdev *sd, } read_words--; } -rel_mutex: +rel_mutex_q: mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); +rel_master: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); return rc; } @@ -1309,12 +1360,36 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, c_ctrl->cci_info->sid, c_ctrl->cci_info->retries, c_ctrl->cci_info->id_map); + mutex_lock(&cci_dev->cci_master_info[master].mutex); + if (cci_dev->cci_master_info[master].is_first_req == true) { + cci_dev->cci_master_info[master].is_first_req = false; + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else if (c_ctrl->cci_info->i2c_freq_mode + != cci_dev->i2c_freq_mode[master]) { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + down(&cci_dev->cci_master_info[master].master_sem); + } else { + CAM_DBG(CAM_CCI, "Master: %d, curr_freq: %d, req_freq: %d", + master, cci_dev->i2c_freq_mode[master], + c_ctrl->cci_info->i2c_freq_mode); + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + cci_dev->cci_master_info[master].freq_ref_cnt++; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); + } + /* Set the I2C Frequency */ rc = cam_cci_set_clk_param(cci_dev, c_ctrl); if (rc < 0) { CAM_ERR(CAM_CCI, "cam_cci_set_clk_param failed rc = %d", rc); - return rc; + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + goto ERROR; } + mutex_unlock(&cci_dev->cci_master_info[master].mutex); /* * Call validate queue to make sure queue is empty before starting. * If this call fails, don't proceed with i2c_write call. This is to @@ -1326,18 +1401,25 @@ static int32_t cam_cci_i2c_write(struct v4l2_subdev *sd, if (rc < 0) { CAM_ERR(CAM_CCI, "Initial validataion failed rc %d", rc); - return rc; + goto ERROR; } if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { CAM_ERR(CAM_CCI, "More than max retries"); - return rc; + goto ERROR; } rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en); if (rc < 0) { CAM_ERR(CAM_CCI, "failed rc: %d", rc); - return rc; + goto ERROR; } +ERROR: + spin_lock(&cci_dev->cci_master_info[master].freq_cnt); + if (cci_dev->cci_master_info[master].freq_ref_cnt == 0) + up(&cci_dev->cci_master_info[master].master_sem); + else + cci_dev->cci_master_info[master].freq_ref_cnt--; + spin_unlock(&cci_dev->cci_master_info[master].freq_cnt); return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c index 5e522a8a5959..7934aa50767c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera_v3/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-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 @@ -151,7 +151,6 @@ irqreturn_t cam_cci_irq(int irq_num, void *data) complete(&cci_dev->cci_master_info[MASTER_1].th_complete); complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); } - rd_done_th_assert = false; if ((irq_status0 & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) && (!rd_done_th_assert)) { cci_dev->cci_master_info[MASTER_1].status = 0; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h index 12abeabe0a38..349effcc057b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera_v3/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-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 @@ -26,6 +26,7 @@ #include <linux/timer.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/semaphore.h> #include <media/cam_sensor.h> #include <media/v4l2-event.h> #include <media/v4l2-ioctl.h> @@ -144,6 +145,10 @@ struct cam_cci_master_info { struct completion report_q[NUM_QUEUES]; atomic_t done_pending[NUM_QUEUES]; spinlock_t lock_q[NUM_QUEUES]; + spinlock_t freq_cnt; + struct semaphore master_sem; + bool is_first_req; + uint16_t freq_ref_cnt; }; struct cam_cci_clk_params_t { diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c index da714af3fde2..7d71cd57573e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -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 @@ -196,7 +196,10 @@ static void cam_cci_init_cci_params(struct cci_device *new_cci_dev) for (i = 0; i < NUM_MASTERS; i++) { new_cci_dev->cci_master_info[i].status = 0; + new_cci_dev->cci_master_info[i].is_first_req = true; mutex_init(&new_cci_dev->cci_master_info[i].mutex); + sema_init(&new_cci_dev->cci_master_info[i].master_sem, 1); + spin_lock_init(&new_cci_dev->cci_master_info[i].freq_cnt); init_completion( &new_cci_dev->cci_master_info[i].reset_complete); init_completion( diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 9894b217ac2c..17499489184b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -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 @@ -15,6 +15,8 @@ #include "cam_csiphy_dev.h" #include "cam_csiphy_soc.h" #include "cam_common_util.h" +#include "cam_packet_util.h" + #include <soc/qcom/scm.h> #include <cam_mem_mgr.h> @@ -159,11 +161,13 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, { int32_t rc = 0; uintptr_t generic_ptr; + uintptr_t generic_pkt_ptr; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; uint32_t *cmd_buf = NULL; struct cam_csiphy_info *cam_cmd_csiphy_info = NULL; size_t len; + size_t remain_len; if (!cfg_dev || !csiphy_dev) { CAM_ERR(CAM_CSIPHY, "Invalid Args"); @@ -171,21 +175,32 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, } rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle, - &generic_ptr, &len); + &generic_pkt_ptr, &len); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc); return rc; } - if (cfg_dev->offset > len) { + remain_len = len; + if ((sizeof(struct cam_packet) > len) || + ((size_t)cfg_dev->offset >= len - sizeof(struct cam_packet))) { CAM_ERR(CAM_CSIPHY, - "offset is out of bounds: offset: %lld len: %zu", - cfg_dev->offset, len); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len); + rc = -EINVAL; + goto rel_pkt_buf; } + remain_len -= (size_t)cfg_dev->offset; csl_packet = (struct cam_packet *) - (generic_ptr + (uint32_t)cfg_dev->offset); + (generic_pkt_ptr + (uint32_t)cfg_dev->offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_CSIPHY, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *)&csl_packet->payload + @@ -196,7 +211,15 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed to get cmd buf Mem address : %d", rc); - return rc; + goto rel_pkt_buf; + } + + if ((len < sizeof(struct cam_csiphy_info)) || + (cmd_desc->offset > (len - sizeof(struct cam_csiphy_info)))) { + CAM_ERR(CAM_CSIPHY, + "Not enough buffer provided for cam_cisphy_info"); + rc = -EINVAL; + goto rel_pkt_buf; } cmd_buf = (uint32_t *)generic_ptr; @@ -221,6 +244,15 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, cam_csiphy_update_secure_info(csiphy_dev, cam_cmd_csiphy_info, cfg_dev); + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_CSIPHY, "Failed to put cmd buffer: %d", + cmd_desc->mem_handle); + +rel_pkt_buf: + if (cam_mem_put_cpu_buf((int32_t) cfg_dev->packet_handle)) + CAM_WARN(CAM_CSIPHY, "Failed to put packet Mem address: %llu", + cfg_dev->packet_handle); + return rc; } @@ -567,6 +599,14 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_create_dev_hdl bridge_params; + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + CAM_ERR(CAM_CSIPHY, + "Not in right state to acquire : %d", + csiphy_dev->csiphy_state); + rc = -EINVAL; + goto release_mutex; + } + rc = copy_from_user(&csiphy_acq_dev, u64_to_user_ptr(cmd->handle), sizeof(csiphy_acq_dev)); @@ -826,6 +866,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, if (rc < 0) { csiphy_dev->csiphy_info.secure_mode[offset] = CAM_SECURE_MODE_NON_SECURE; + cam_cpas_stop(csiphy_dev->cpas_handle); goto release_mutex; } } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index 32bb34bb257b..972b0a549f30 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -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 @@ -165,7 +165,6 @@ static int32_t cam_csiphy_platform_probe(struct platform_device *pdev) } 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; @@ -211,9 +210,17 @@ static int32_t cam_csiphy_device_remove(struct platform_device *pdev) struct csiphy_device *csiphy_dev = v4l2_get_subdevdata(subdev); + CAM_INFO(CAM_CSIPHY, "device remove invoked"); cam_cpas_unregister_client(csiphy_dev->cpas_handle); cam_csiphy_soc_release(csiphy_dev); + mutex_lock(&csiphy_dev->mutex); + cam_csiphy_shutdown(csiphy_dev); + mutex_unlock(&csiphy_dev->mutex); + cam_unregister_subdev(&(csiphy_dev->v4l2_dev_str)); kfree(csiphy_dev->ctrl_reg); + csiphy_dev->ctrl_reg = NULL; + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(csiphy_dev->v4l2_dev_str.sd), NULL); devm_kfree(&pdev->dev, csiphy_dev); return 0; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h index a16fb888edc6..945910e96a55 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_2_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* 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 @@ -20,7 +20,7 @@ struct csiphy_reg_parms_t csiphy_v1_2 = { .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, .csiphy_common_array_size = 4, - .csiphy_reset_array_size = 4, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 21, .csiphy_3ph_config_array_size = 31, .csiphy_2ph_clock_lane = 0x1, @@ -38,6 +38,7 @@ struct csiphy_reg_t csiphy_reset_reg_1_2[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h index 8d7a5b58215a..b7345d4abeeb 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_csiphy/include/cam_csiphy_2_0_hwreg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Linux Foundation. All rights reserved. +/* 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 @@ -19,8 +19,8 @@ struct csiphy_reg_parms_t csiphy_v2_0 = { .mipi_csiphy_interrupt_status0_addr = 0x8B0, .mipi_csiphy_interrupt_clear0_addr = 0x858, .mipi_csiphy_glbl_irq_cmd_addr = 0x828, - .csiphy_common_array_size = 6, - .csiphy_reset_array_size = 3, + .csiphy_common_array_size = 8, + .csiphy_reset_array_size = 5, .csiphy_2ph_config_array_size = 15, .csiphy_3ph_config_array_size = 17, .csiphy_2ph_clock_lane = 0x1, @@ -31,6 +31,8 @@ struct csiphy_reg_t csiphy_common_reg_2_0[] = { {0x0814, 0x00, 0x00, CSIPHY_LANE_ENABLE}, {0x0818, 0x01, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x06, 0x00, CSIPHY_3PH_REGS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x0164, 0x00, 0x00, CSIPHY_2PH_REGS}, {0x0364, 0x00, 0x00, CSIPHY_2PH_REGS}, {0x0564, 0x00, 0x00, CSIPHY_2PH_REGS}, @@ -40,6 +42,8 @@ struct csiphy_reg_t csiphy_reset_reg_2_0[] = { {0x0814, 0x00, 0x05, CSIPHY_LANE_ENABLE}, {0x0818, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, {0x081C, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x01, 0x01, CSIPHY_DEFAULT_PARAMS}, + {0x0800, 0x00, 0x00, CSIPHY_DEFAULT_PARAMS}, }; struct csiphy_reg_t csiphy_irq_reg_2_0[] = { diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 7d7c1a2977e5..220cd1598922 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -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 @@ -18,6 +18,7 @@ #include "cam_eeprom_soc.h" #include "cam_debug_util.h" #include "cam_common_util.h" +#include "cam_packet_util.h" /** * cam_eeprom_read_memory() - read map data into buffer @@ -413,7 +414,7 @@ static int32_t cam_eeprom_update_slaveInfo(struct cam_eeprom_ctrl_t *e_ctrl, 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) + int *num_map, size_t remain_buf_len) { int32_t rc = 0; int32_t cnt = 0; @@ -427,8 +428,21 @@ static int32_t cam_eeprom_parse_memory_map( struct cam_cmd_i2c_continuous_rd *i2c_cont_rd = NULL; struct cam_cmd_conditional_wait *i2c_poll = NULL; struct cam_cmd_unconditional_wait *i2c_uncond_wait = NULL; + size_t validate_size = 0; generic_op_code = cmm_hdr->third_byte; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR) + validate_size = sizeof(struct cam_cmd_i2c_random_wr); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_I2C_CONT_RD) + validate_size = sizeof(struct cam_cmd_i2c_continuous_rd); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf_len < validate_size) { + CAM_ERR(CAM_EEPROM, "not enough buffer"); + return -EINVAL; + } switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; @@ -535,6 +549,7 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, uint32_t *cmd_buf = NULL; uintptr_t generic_pkt_addr; size_t pkt_len = 0; + size_t remain_len = 0; uint32_t total_cmd_buf_in_bytes = 0; uint32_t processed_cmd_buf_in_bytes = 0; struct common_header *cmm_hdr = NULL; @@ -575,15 +590,43 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, cmd_buf = (uint32_t *)generic_pkt_addr; if (!cmd_buf) { CAM_ERR(CAM_EEPROM, "invalid cmd buf"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + + if ((pkt_len < sizeof(struct common_header)) || + (cmd_desc[i].offset > (pkt_len - + sizeof(struct common_header)))) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } + remain_len = pkt_len - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + if (total_cmd_buf_in_bytes > remain_len) { + CAM_ERR(CAM_EEPROM, "Not enough buffer for command"); + rc = -EINVAL; + goto rel_cmd_buf; + } /* Loop through multiple cmd formats in one cmd buffer */ while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct common_header)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto rel_cmd_buf; + } cmm_hdr = (struct common_header *)cmd_buf; switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if ((remain_len - processed_cmd_buf_in_bytes) < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_EEPROM, "Not enough buf"); + rc = -EINVAL; + goto rel_cmd_buf; + } /* Configure the following map slave address */ map[num_map + 1].saddr = i2c_info->slave_addr; rc = cam_eeprom_update_slaveInfo(e_ctrl, @@ -599,14 +642,16 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, 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); + cmd_length_in_bytes, power_info, + (remain_len - + processed_cmd_buf_in_bytes)); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/ sizeof(uint32_t); if (rc) { CAM_ERR(CAM_EEPROM, "Failed"); - return rc; + goto rel_cmd_buf; } break; case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: @@ -616,7 +661,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, rc = cam_eeprom_parse_memory_map( &e_ctrl->cal_data, cmd_buf, total_cmd_buf_in_bytes, - &cmd_length_in_bytes, &num_map); + &cmd_length_in_bytes, &num_map, + (remain_len - + processed_cmd_buf_in_bytes)); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/sizeof(uint32_t); @@ -626,7 +673,18 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, } } e_ctrl->cal_data.num_map = num_map + 1; + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_EEPROM, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); } + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_EEPROM, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); + return rc; } @@ -647,6 +705,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, uintptr_t buf_addr; size_t buf_size; uint8_t *read_buffer; + size_t remain_len = 0; io_cfg = (struct cam_buf_io_cfg *) ((uint8_t *) &csl_packet->payload + @@ -660,6 +719,18 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, if (io_cfg->direction == CAM_BUF_OUTPUT) { rc = cam_mem_get_cpu_buf(io_cfg->mem_handle[0], &buf_addr, &buf_size); + if (rc) { + CAM_ERR(CAM_EEPROM, "Fail in get buffer: %d", + rc); + return rc; + } + if (buf_size <= io_cfg->offsets[0]) { + CAM_ERR(CAM_EEPROM, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } + + remain_len = buf_size - io_cfg->offsets[0]; CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", (void *)buf_addr, buf_size); @@ -667,26 +738,38 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, if (!read_buffer) { CAM_ERR(CAM_EEPROM, "invalid buffer to copy data"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } read_buffer += io_cfg->offsets[0]; - if (buf_size < e_ctrl->cal_data.num_data) { + if (remain_len < e_ctrl->cal_data.num_data) { CAM_ERR(CAM_EEPROM, "failed to copy, Invalid size"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } 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); - + if (cam_mem_put_cpu_buf(io_cfg->mem_handle[0])) + CAM_WARN(CAM_EEPROM, "Fail in put buffer: 0x%x", + io_cfg->mem_handle[0]); } else { CAM_ERR(CAM_EEPROM, "Invalid direction"); rc = -EINVAL; } } + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(io_cfg->mem_handle[0])) + CAM_WARN(CAM_EEPROM, "Fail in put buffer : %d", + io_cfg->mem_handle[0]); + return rc; } @@ -704,6 +787,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) struct cam_config_dev_cmd dev_config; uintptr_t generic_pkt_addr; size_t pkt_len; + size_t remain_len = 0; struct cam_packet *csl_packet = NULL; struct cam_eeprom_soc_private *soc_private = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; @@ -723,15 +807,28 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) return rc; } - if (dev_config.offset > pkt_len) { + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { CAM_ERR(CAM_EEPROM, - "Offset is out of bound: off: %lld, %zu", - dev_config.offset, pkt_len); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + rc = -EINVAL; + goto release_buf; } + remain_len -= (size_t)dev_config.offset; csl_packet = (struct cam_packet *) - (generic_pkt_addr + (uint32_t)dev_config.offset); + (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_EEPROM, "Invalid packet params"); + rc = -EINVAL; + goto release_buf; + } + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_EEPROM_PACKET_OPCODE_INIT: if (e_ctrl->userspace_probe == false) { @@ -739,7 +836,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) e_ctrl->soc_info.dev->of_node, e_ctrl); if (rc < 0) { CAM_ERR(CAM_EEPROM, "Failed: rc : %d", rc); - return rc; + goto release_buf; } rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); vfree(e_ctrl->cal_data.mapdata); @@ -754,7 +851,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) if (rc) { CAM_ERR(CAM_EEPROM, "Failed in parsing the pkt"); - return rc; + goto release_buf; } e_ctrl->cal_data.mapdata = @@ -797,7 +894,13 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) default: break; } + + if (cam_mem_put_cpu_buf(dev_config.packet_handle)) + CAM_WARN(CAM_EEPROM, "Put cpu buffer failed : %llu", + dev_config.packet_handle); + return rc; + power_down: cam_eeprom_power_down(e_ctrl); memdata_free: @@ -811,6 +914,11 @@ error: e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; +release_buf: + if (cam_mem_put_cpu_buf(dev_config.packet_handle)) + CAM_WARN(CAM_EEPROM, "Put cpu buffer failed : %llu", + dev_config.packet_handle); + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index 6d8820abb7d7..cf6854c7a527 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -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 @@ -219,7 +219,6 @@ static int cam_eeprom_i2c_driver_probe(struct i2c_client *client, 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; @@ -257,13 +256,17 @@ static int cam_eeprom_i2c_driver_remove(struct i2c_client *client) return -EINVAL; } + CAM_INFO(CAM_EEPROM, "i2c driver remove invoked"); soc_info = &e_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); kfree(soc_private); - kfree(e_ctrl->io_master_info.cci_client); v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); kfree(e_ctrl); @@ -388,14 +391,21 @@ static int cam_eeprom_spi_driver_remove(struct spi_device *sdev) for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); + mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); kfree(e_ctrl->io_master_info.spi_client); + e_ctrl->io_master_info.spi_client = NULL; soc_private = (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; if (soc_private) { kfree(soc_private->power_info.gpio_num_info); + soc_private->power_info.gpio_num_info = NULL; kfree(soc_private); + soc_private = NULL; } - mutex_destroy(&(e_ctrl->eeprom_mutex)); v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); kfree(e_ctrl); @@ -459,10 +469,7 @@ static int32_t cam_eeprom_platform_driver_probe( 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; @@ -472,6 +479,7 @@ free_cci_client: kfree(e_ctrl->io_master_info.cci_client); free_e_ctrl: kfree(e_ctrl); + return rc; } @@ -487,17 +495,23 @@ static int cam_eeprom_platform_driver_remove(struct platform_device *pdev) return -EINVAL; } + CAM_INFO(CAM_EEPROM, "Platform driver remove invoked"); soc_info = &e_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(e_ctrl->eeprom_mutex)); + cam_eeprom_shutdown(e_ctrl); + mutex_unlock(&(e_ctrl->eeprom_mutex)); mutex_destroy(&(e_ctrl->eeprom_mutex)); + cam_unregister_subdev(&(e_ctrl->v4l2_dev_str)); kfree(soc_info->soc_private); kfree(e_ctrl->io_master_info.cci_client); platform_set_drvdata(pdev, NULL); v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, NULL); kfree(e_ctrl); + return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c index 5c9df8ac7abf..4302d4897ea9 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.c @@ -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 @@ -16,43 +16,78 @@ #include "cam_flash_core.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" static int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, bool regulator_enable) { int rc = 0; + struct cam_flash_private_soc *soc_private = + (struct cam_flash_private_soc *) + flash_ctrl->soc_info.soc_private; if (!(flash_ctrl->switch_trigger)) { CAM_ERR(CAM_FLASH, "Invalid argument"); return -EINVAL; } - if (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; + if (soc_private->is_wled_flash) { + if (regulator_enable && + flash_ctrl->is_regulator_enabled == false) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + ENABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "enable reg failed: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = true; + } else if (!regulator_enable && + flash_ctrl->is_regulator_enabled == true) { + rc = wled_flash_led_prepare(flash_ctrl->switch_trigger, + DISABLE_REGULATOR, NULL); + if (rc) { + CAM_ERR(CAM_FLASH, "disalbe reg fail: rc: %d", + rc); + return rc; + } + + flash_ctrl->is_regulator_enabled = false; + } else { + CAM_ERR(CAM_FLASH, "Wrong Wled flash state: %d", + flash_ctrl->flash_state); + rc = -EINVAL; } - flash_ctrl->is_regulator_enabled = false; } else { - CAM_ERR(CAM_FLASH, "Wrong Flash State : %d", - flash_ctrl->flash_state); - rc = -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; } @@ -171,6 +206,7 @@ int cam_flash_pmic_power_ops(struct cam_flash_ctrl *fctrl, "Enable Regulator Failed rc = %d", rc); return rc; } + fctrl->last_flush_req = 0; } if (!regulator_enable) { @@ -267,7 +303,6 @@ int cam_flash_pmic_flush_request(struct cam_flash_ctrl *fctrl, } if (type == FLUSH_ALL) { - cam_flash_off(fctrl); /* flush all requests*/ for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { fctrl->per_frame[i].cmn_attr.request_id = 0; @@ -360,7 +395,13 @@ int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush) } mutex_lock(&fctrl->flash_mutex); + if (fctrl->flash_state == CAM_FLASH_STATE_INIT) + goto end; + if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { + fctrl->last_flush_req = flush->req_id; + CAM_DBG(CAM_FLASH, "last reqest to flush is %lld", + flush->req_id); rc = fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); if (rc) { CAM_ERR(CAM_FLASH, "FLUSH_TYPE_ALL failed rc: %d", rc); @@ -398,37 +439,31 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, 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_PERF, - "Led_Current[%d] = %d", i, curr); - cam_res_mgr_led_trigger_event( - flash_ctrl->torch_trigger[i], - curr); + curr = max_current; } + CAM_DBG(CAM_FLASH, "Led_Torch[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->torch_trigger[i], curr); } } else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { for (i = 0; i < flash_ctrl->flash_num_sources; i++) { if (flash_ctrl->flash_trigger[i]) { max_current = soc_private->flash_max_current[i]; - if (flash_data->led_current_ma[i] <= max_current) curr = flash_data->led_current_ma[i]; else - curr = soc_private->flash_op_current[i]; - - CAM_DBG(CAM_PERF, "LED flash_current[%d]: %d", - i, curr); - cam_res_mgr_led_trigger_event( - flash_ctrl->flash_trigger[i], - curr); + curr = max_current; } + CAM_DBG(CAM_FLASH, "LED_Flash[%d]: Current: %d", + i, curr); + cam_res_mgr_led_trigger_event( + flash_ctrl->flash_trigger[i], curr); } } else { CAM_ERR(CAM_FLASH, "Wrong Operation: %d", op); @@ -438,7 +473,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; } @@ -452,7 +487,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; @@ -591,11 +626,15 @@ static int cam_flash_pmic_delete_req(struct cam_flash_ctrl *fctrl, } static int32_t cam_flash_slaveInfo_pkt_parser(struct cam_flash_ctrl *fctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_i2c_info *i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; + if (len < sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } if (fctrl->io_master_info.master_type == CCI_MASTER) { fctrl->io_master_info.cci_client->cci_i2c_master = fctrl->cci_i2c_master; @@ -870,6 +909,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) uint32_t *offset = NULL; uint32_t frm_offset = 0; size_t len_of_buffer; + size_t remain_len; struct cam_flash_init *flash_init = NULL; struct common_header *cmn_hdr = NULL; struct cam_control *ioctl_ctrl = NULL; @@ -897,19 +937,42 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_mem_get_cpu_buf(config.packet_handle, &generic_ptr, &len_of_buffer); if (rc) { - CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc); + CAM_ERR(CAM_FLASH, "Failed in getting the packet : %d", rc); return rc; } - - if (config.offset > len_of_buffer) { + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { CAM_ERR(CAM_FLASH, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buffer); + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); return -EINVAL; } + remain_len -= (size_t)config.offset; /* Add offset to the flash csl header */ csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + return -EINVAL; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_DBG(CAM_FLASH, + "reject request %lld, last request to flush %lld", + csl_packet->header.request_id, fctrl->last_flush_req); + return -EINVAL; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_FLASH_PACKET_OPCODE_INIT: { /* INIT packet*/ @@ -934,6 +997,15 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_ERR(CAM_FLASH, "invalid cmd buf"); return -EINVAL; } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buffer - + sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "invalid cmd buf length"); + return -EINVAL; + } + remain_len = len_of_buffer - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmn_hdr = (struct common_header *)cmd_buf; @@ -944,6 +1016,12 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) total_cmd_buf_in_bytes); switch (cmn_hdr->cmd_type) { case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_INFO: + if (len_of_buffer < + sizeof(struct cam_flash_init)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + return -EINVAL; + } + flash_init = (struct cam_flash_init *)cmd_buf; fctrl->flash_type = flash_init->flash_type; cmd_length_in_bytes = @@ -955,7 +1033,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) break; case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: rc = cam_flash_slaveInfo_pkt_parser( - fctrl, cmd_buf); + fctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_FLASH, "Failed parsing slave info: rc: %d", @@ -978,7 +1056,7 @@ int cam_flash_i2c_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - &fctrl->power_info); + &fctrl->power_info, remain_len); processed_cmd_buf_in_bytes += cmd_length_in_bytes; cmd_buf += cmd_length_in_bytes/ @@ -1171,11 +1249,12 @@ update_req_mgr: int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) { int rc = 0, i = 0; - uintptr_t generic_ptr; + uintptr_t generic_ptr, cmd_buf_ptr; uint32_t *cmd_buf = NULL; uint32_t *offset = NULL; uint32_t frm_offset = 0; size_t len_of_buffer; + size_t remain_len; struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -1187,11 +1266,16 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) struct cam_flash_set_on_off *flash_operation_info = NULL; struct cam_flash_query_curr *flash_query_info = NULL; struct cam_flash_frame_setting *flash_data = NULL; + struct cam_flash_private_soc *soc_private = NULL; if (!fctrl || !arg) { CAM_ERR(CAM_FLASH, "fctrl/arg is NULL"); return -EINVAL; } + + soc_private = (struct cam_flash_private_soc *) + fctrl->soc_info.soc_private; + /* getting CSL Packet */ ioctl_ctrl = (struct cam_control *)arg; @@ -1206,20 +1290,45 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) rc = cam_mem_get_cpu_buf(config.packet_handle, &generic_ptr, &len_of_buffer); if (rc) { - CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc); + CAM_ERR(CAM_FLASH, "Failed in getting the packet: %d", rc); return rc; } - if (config.offset > len_of_buffer) { + remain_len = len_of_buffer; + if ((sizeof(struct cam_packet) > len_of_buffer) || + ((size_t)config.offset >= len_of_buffer - + sizeof(struct cam_packet))) { CAM_ERR(CAM_FLASH, - "offset is out of bounds: offset: %lld len: %zu", - config.offset, len_of_buffer); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buffer); + rc = -EINVAL; + goto rel_pkt_buf; } + remain_len -= (size_t)config.offset; /* Add offset to the flash csl header */ - csl_packet = - (struct cam_packet *)(generic_ptr + (uint32_t)config.offset); + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_FLASH, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_FLASH_PACKET_OPCODE_INIT && + csl_packet->header.request_id <= fctrl->last_flush_req + && fctrl->last_flush_req != 0) { + CAM_WARN(CAM_FLASH, + "reject request %lld, last request to flush %u", + csl_packet->header.request_id, fctrl->last_flush_req); + rc = -EINVAL; + goto rel_pkt_buf; + } + + if (csl_packet->header.request_id > fctrl->last_flush_req) + fctrl->last_flush_req = 0; switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_FLASH_PACKET_OPCODE_INIT: { @@ -1228,8 +1337,20 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) csl_packet->cmd_buf_offset); cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - &generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + goto rel_pkt_buf; + } + if ((len_of_buffer < sizeof(struct cam_flash_init)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct cam_flash_init)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + cmd_desc->offset); cam_flash_info = (struct cam_flash_init *)cmd_buf; @@ -1248,7 +1369,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (rc) { CAM_ERR(CAM_FLASH, "Enable Regulator Failed rc = %d", rc); - return rc; + goto rel_cmd_buf; } fctrl->flash_state = @@ -1258,8 +1379,26 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: { CAM_DBG(CAM_FLASH, "INIT_FIRE Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } + flash_operation_info = (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; + } fctrl->nrt_info.cmn_attr.count = flash_operation_info->count; fctrl->nrt_info.cmn_attr.request_id = 0; @@ -1284,8 +1423,13 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) default: CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", cam_flash_info->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: %d", + cmd_desc->mem_handle); break; } case CAM_FLASH_PACKET_OPCODE_SET_OPS: { @@ -1306,13 +1450,28 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) flash_data->cmn_attr.is_settings_valid = true; cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - &generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + - cmd_desc->offset); + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: 0x%x", + cmd_desc->mem_handle); + goto rel_pkt_buf; + } - if (!cmd_buf) - return -EINVAL; + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + + cmd_desc->offset); + if (!cmd_buf) { + rc = -EINVAL; + goto rel_cmd_buf; + } cmn_hdr = (struct common_header *)cmd_buf; switch (cmn_hdr->cmd_type) { @@ -1325,7 +1484,12 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) CAM_WARN(CAM_FLASH, "Rxed Flash fire ops without linking"); flash_data->cmn_attr.is_settings_valid = false; - return 0; + goto rel_cmd_buf; + } + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; } flash_operation_info = @@ -1333,7 +1497,14 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (!flash_operation_info) { CAM_ERR(CAM_FLASH, "flash_operation_info Null"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; } flash_data->opcode = flash_operation_info->opcode; @@ -1350,8 +1521,12 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) default: CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", cmn_hdr->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: 0x%x", + cmd_desc->mem_handle); break; } case CAM_FLASH_PACKET_OPCODE_NON_REALTIME_SET_OPS: { @@ -1360,16 +1535,47 @@ int cam_flash_pmic_pkt_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, - &generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &cmd_buf_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail in get buffer: %d", rc); + goto rel_pkt_buf; + } + + if ((len_of_buffer < sizeof(struct common_header)) || + (cmd_desc->offset > + (len_of_buffer - sizeof(struct common_header)))) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len_of_buffer - cmd_desc->offset; + cmd_buf = (uint32_t *)((uint8_t *)cmd_buf_ptr + cmd_desc->offset); cmn_hdr = (struct common_header *)cmd_buf; switch (cmn_hdr->cmd_type) { case CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET: { CAM_DBG(CAM_FLASH, "Widget Flash Operation"); + if (remain_len < sizeof(struct cam_flash_set_on_off)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } flash_operation_info = (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_operation_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; + } + fctrl->nrt_info.cmn_attr.count = flash_operation_info->count; fctrl->nrt_info.cmn_attr.request_id = 0; @@ -1386,29 +1592,61 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) if (rc) CAM_ERR(CAM_FLASH, "Apply setting failed: %d", rc); - return rc; + goto rel_cmd_buf; } case CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR: { int query_curr_ma = 0; + if (remain_len < sizeof(struct cam_flash_query_curr)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } flash_query_info = (struct cam_flash_query_curr *)cmd_buf; - rc = qpnp_flash_led_prepare(fctrl->switch_trigger, - QUERY_MAX_CURRENT, &query_curr_ma); + if (soc_private->is_wled_flash) + rc = wled_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + else + rc = qpnp_flash_led_prepare( + fctrl->switch_trigger, + QUERY_MAX_AVAIL_CURRENT, + &query_curr_ma); + CAM_DBG(CAM_FLASH, "query_curr_ma = %d", query_curr_ma); if (rc) { CAM_ERR(CAM_FLASH, "Query current failed with rc=%d", rc); - return rc; + goto rel_cmd_buf; } flash_query_info->query_current_ma = query_curr_ma; break; } case CAMERA_SENSOR_FLASH_CMD_TYPE_RER: { rc = 0; + if (remain_len < sizeof(struct cam_flash_set_rer)) { + CAM_ERR(CAM_FLASH, "Not enough buffer"); + rc = -EINVAL; + goto rel_cmd_buf; + } flash_rer_info = (struct cam_flash_set_rer *)cmd_buf; + if (!flash_rer_info) { + CAM_ERR(CAM_FLASH, + "flash_rer_info Null"); + rc = -EINVAL; + goto rel_cmd_buf; + } + if (flash_rer_info->count > + CAM_FLASH_MAX_LED_TRIGGERS) { + CAM_ERR(CAM_FLASH, "led count out of limit"); + rc = -EINVAL; + goto rel_cmd_buf; + } + fctrl->nrt_info.cmn_attr.cmd_type = CAMERA_SENSOR_FLASH_CMD_TYPE_RER; fctrl->nrt_info.opcode = flash_rer_info->opcode; @@ -1425,18 +1663,21 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) fctrl->nrt_info.led_current_ma[i] = flash_rer_info->led_current_ma[i]; - rc = fctrl->func_tbl.apply_setting(fctrl, 0); if (rc) CAM_ERR(CAM_FLASH, "apply_setting failed: %d", rc); - return rc; + goto rel_cmd_buf; } default: CAM_ERR(CAM_FLASH, "Wrong cmd_type : %d", cmn_hdr->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: 0x%x", + cmd_desc->mem_handle); break; } case CAM_PKT_NOP_OPCODE: { @@ -1448,7 +1689,7 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) "Rxed NOP packets without linking"); fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; - return 0; + goto rel_pkt_buf; } fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; @@ -1456,14 +1697,15 @@ int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg) fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %llu", csl_packet->header.request_id); - goto update_req_mgr; + break; } default: CAM_ERR(CAM_FLASH, "Wrong Opcode : %d", (csl_packet->header.op_code & 0xFFFFFF)); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } -update_req_mgr: + if (((csl_packet->header.op_code & 0xFFFFF) == CAM_PKT_NOP_OPCODE) || ((csl_packet->header.op_code & 0xFFFFF) == @@ -1484,6 +1726,21 @@ update_req_mgr: CAM_DBG(CAM_FLASH, "add req to req_mgr= %lld", add_req.req_id); } + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_FLASH, "Failed in put the buffer: %llu ", + config.packet_handle); + + return 0; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_FLASH, "Fail in put buffer: %d", + cmd_desc->mem_handle); +rel_pkt_buf: + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_FLASH, "Failed in put the buffer: %llu ", + config.packet_handle); + return rc; } @@ -1534,6 +1791,7 @@ int cam_flash_release_dev(struct cam_flash_ctrl *fctrl) fctrl->bridge_intf.device_hdl = -1; fctrl->bridge_intf.link_hdl = -1; fctrl->bridge_intf.session_hdl = -1; + fctrl->last_flush_req = 0; } return rc; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h index 1bd3b31c1668..875d13c51ee0 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_core.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 @@ -13,15 +13,20 @@ #ifndef _CAM_FLASH_CORE_H_ #define _CAM_FLASH_CORE_H_ -#include <linux/leds-qpnp-flash.h> #include <media/cam_sensor.h> #include "cam_flash_dev.h" +#define QUERY_MAX_AVAIL_CURRENT BIT(2) + int cam_flash_publish_dev_info(struct cam_req_mgr_device_info *info); int cam_flash_establish_link(struct cam_req_mgr_core_dev_link_setup *link); int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply); int cam_flash_process_evt(struct cam_req_mgr_link_evt_data *event_data); int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush); - +static inline int wled_flash_led_prepare(struct led_trigger *trig, int options, + int *max_current) +{ + return -EINVAL; +} #endif /*_CAM_FLASH_CORE_H_*/ diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c index f5177d6796b5..948fc9a9c990 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -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 @@ -181,7 +181,9 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, goto release_mutex; } + cam_flash_off(fctrl); fctrl->func_tbl.flush_req(fctrl, FLUSH_ALL, 0); + fctrl->last_flush_req = 0; fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; break; } @@ -318,7 +320,14 @@ static int cam_flash_platform_remove(struct platform_device *pdev) return 0; } - devm_kfree(&pdev->dev, fctrl); + CAM_INFO(CAM_FLASH, "Platform remove invoked"); + mutex_lock(&fctrl->flash_mutex); + cam_flash_shutdown(fctrl); + mutex_unlock(&fctrl->flash_mutex); + cam_unregister_subdev(&(fctrl->v4l2_dev_str)); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&fctrl->v4l2_dev_str.sd, NULL); + kfree(fctrl); return 0; } @@ -332,6 +341,8 @@ static int32_t cam_flash_i2c_driver_remove(struct i2c_client *client) CAM_ERR(CAM_FLASH, "Flash device is NULL"); return -EINVAL; } + + CAM_INFO(CAM_FLASH, "i2c driver remove invoked"); /*Free Allocated Mem */ kfree(fctrl->i2c_data.per_frame); fctrl->i2c_data.per_frame = NULL; @@ -483,6 +494,7 @@ static int32_t cam_flash_platform_probe(struct platform_device *pdev) fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; mutex_init(&(fctrl->flash_mutex)); @@ -569,6 +581,7 @@ static int32_t cam_flash_i2c_driver_probe(struct i2c_client *client, fctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; fctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; fctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + fctrl->last_flush_req = 0; mutex_init(&(fctrl->flash_mutex)); fctrl->flash_state = CAM_FLASH_STATE_INIT; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h index 8e5deef871e5..ea5ea3c9997b 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_dev.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 @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/leds-qpnp-flash.h> #include <media/v4l2-subdev.h> #include <media/v4l2-ioctl.h> #include <media/v4l2-event.h> @@ -135,6 +136,7 @@ struct cam_flash_frame_setting { * @torch_trigger_name : Torch trigger name array * @torch_op_current : Torch operational current * @torch_max_current : Max supported current for LED in torch mode + * @is_wled_flash : Detection between WLED/LED flash */ struct cam_flash_private_soc { @@ -146,6 +148,7 @@ struct cam_flash_private_soc { const char *torch_trigger_name[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t torch_op_current[CAM_FLASH_MAX_LED_TRIGGERS]; uint32_t torch_max_current[CAM_FLASH_MAX_LED_TRIGGERS]; + bool is_wled_flash; }; struct cam_flash_func_tbl { @@ -180,6 +183,7 @@ struct cam_flash_func_tbl { * @cci_i2c_master : I2C structure * @io_master_info : Information about the communication master * @i2c_data : I2C register settings + * @last_flush_req : last request to flush */ struct cam_flash_ctrl { struct cam_hw_soc_info soc_info; @@ -205,6 +209,7 @@ struct cam_flash_ctrl { enum cci_i2c_master_t cci_i2c_master; struct camera_io_master io_master_info; struct i2c_data_settings i2c_data; + uint32_t last_flush_req; }; int cam_flash_pmic_pkt_parser(struct cam_flash_ctrl *fctrl, void *arg); diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c index 22a124d86f93..9195c8143d3c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -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 @@ -26,9 +26,12 @@ static int32_t cam_get_source_node_info( struct device_node *torch_src_node = NULL; struct device_node *switch_src_node = NULL; + soc_private->is_wled_flash = + of_property_read_bool(of_node, "wled-flash-support"); + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); if (!switch_src_node) { - CAM_DBG(CAM_FLASH, "switch_src_node NULL"); + CAM_WARN(CAM_FLASH, "switch_src_node NULL"); } else { rc = of_property_read_string(switch_src_node, "qcom,default-led-trigger", @@ -75,46 +78,61 @@ static int32_t cam_get_source_node_info( continue; } - CAM_DBG(CAM_FLASH, "default trigger %s", + CAM_DBG(CAM_FLASH, "Flash default trigger %s", soc_private->flash_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->flash_trigger_name[i], + &fctrl->flash_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->flash_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->flash_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED FLASH max_current read fail: %d", + rc); + of_node_put(flash_src_node); + rc = 0; + continue; + } + } else { + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &soc_private->flash_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED FLASH max-current read fail: %d", + rc); + of_node_put(flash_src_node); + continue; + } + } /* Read operational-current */ rc = of_property_read_u32(flash_src_node, "qcom,current-ma", &soc_private->flash_op_current[i]); if (rc) { - CAM_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; + CAM_INFO(CAM_FLASH, "op-current: read failed"); + rc = 0; } /* Read max-duration */ rc = of_property_read_u32(flash_src_node, "qcom,duration-ms", &soc_private->flash_max_duration[i]); - if (rc) - CAM_WARN(CAM_FLASH, - "max-duration: read failed"); - + if (rc) { + CAM_INFO(CAM_FLASH, + "max-duration prop unavailable: %d", + rc); + rc = 0; + } of_node_put(flash_src_node); - CAM_DBG(CAM_FLASH, "max_current[%d]: %d", + CAM_DBG(CAM_FLASH, "MainFlashMaxCurrent[%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]); } } @@ -147,35 +165,51 @@ static int32_t cam_get_source_node_info( continue; } + CAM_DBG(CAM_FLASH, "Torch default trigger %s", + soc_private->torch_trigger_name[i]); + cam_res_mgr_led_trigger_register( + soc_private->torch_trigger_name[i], + &fctrl->torch_trigger[i]); + + if (soc_private->is_wled_flash) { + rc = wled_flash_led_prepare( + fctrl->torch_trigger[i], + QUERY_MAX_CURRENT, + &soc_private->torch_max_current[i]); + if (rc) { + CAM_ERR(CAM_FLASH, + "WLED TORCH max_current read fail: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } else { + rc = of_property_read_u32(torch_src_node, + "qcom,max-current", + &soc_private->torch_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "LED-TORCH max-current read failed: %d", + rc); + of_node_put(torch_src_node); + continue; + } + } + /* Read operational-current */ rc = of_property_read_u32(torch_src_node, "qcom,current-ma", &soc_private->torch_op_current[i]); if (rc < 0) { - CAM_WARN(CAM_FLASH, "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; + "op-current prop unavailable: %d", rc); + rc = 0; } of_node_put(torch_src_node); - CAM_DBG(CAM_FLASH, "max_current[%d]: %d", + CAM_DBG(CAM_FLASH, "TorchMaxCurrent[%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]); } } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c index b8ebc15e7fd5..a5c7039cc2da 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.c @@ -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 @@ -19,6 +19,7 @@ #include "cam_debug_util.h" #include "cam_res_mgr_api.h" #include "cam_common_util.h" +#include "cam_packet_util.h" int32_t cam_ois_construct_default_power_setting( struct cam_sensor_power_ctrl_t *power_info) @@ -256,12 +257,12 @@ static int cam_ois_apply_settings(struct cam_ois_ctrl_t *o_ctrl, } static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, - uint32_t *cmd_buf) + uint32_t *cmd_buf, size_t len) { int32_t rc = 0; struct cam_cmd_ois_info *ois_info; - if (!o_ctrl || !cmd_buf) { + if (!o_ctrl || !cmd_buf || len < sizeof(struct cam_cmd_ois_info)) { CAM_ERR(CAM_OIS, "Invalid Args"); return -EINVAL; } @@ -274,7 +275,8 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, 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); + memcpy(o_ctrl->ois_name, ois_info->ois_name, OIS_NAME_LEN); + o_ctrl->ois_name[OIS_NAME_LEN - 1] = '\0'; o_ctrl->io_master_info.cci_client->retries = 3; o_ctrl->io_master_info.cci_client->id_map = 0; memcpy(&(o_ctrl->opcode), &(ois_info->opcode), @@ -433,6 +435,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) struct cam_cmd_buf_desc *cmd_desc = NULL; uintptr_t generic_pkt_addr; size_t pkt_len; + size_t remain_len = 0; struct cam_packet *csl_packet = NULL; size_t len_of_buff = 0; uint32_t *offset = NULL, *cmd_buf; @@ -453,15 +456,29 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) return rc; } - if (dev_config.offset > pkt_len) { + remain_len = pkt_len; + if ((sizeof(struct cam_packet) > pkt_len) || + ((size_t)dev_config.offset >= pkt_len - + sizeof(struct cam_packet))) { CAM_ERR(CAM_OIS, - "offset is out of bound: off: %lld len: %zu", - dev_config.offset, pkt_len); - return -EINVAL; + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), pkt_len); + rc = -EINVAL; + goto rel_pkt; } + remain_len -= (size_t)dev_config.offset; csl_packet = (struct cam_packet *) (generic_pkt_addr + (uint32_t)dev_config.offset); + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_OIS, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt; + } + + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_OIS_PACKET_OPCODE_INIT: offset = (uint32_t *)&csl_packet->payload; @@ -477,25 +494,37 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, &generic_ptr, &len_of_buff); if (rc < 0) { - CAM_ERR(CAM_OIS, "Failed to get cpu buf"); - return rc; + CAM_ERR(CAM_OIS, "Failed to get cpu buf : 0x%x", + cmd_desc[i].mem_handle); + goto rel_pkt; } cmd_buf = (uint32_t *)generic_ptr; if (!cmd_buf) { CAM_ERR(CAM_OIS, "invalid cmd buf"); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; + } + + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > (len_of_buff - + sizeof(struct common_header)))) { + CAM_ERR(CAM_OIS, + "Invalid length for sensor cmd"); + rc = -EINVAL; + goto rel_cmd_buf; } + remain_len = len_of_buff - cmd_desc[i].offset; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); cmm_hdr = (struct common_header *)cmd_buf; switch (cmm_hdr->cmd_type) { case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: rc = cam_ois_slaveInfo_pkt_parser( - o_ctrl, cmd_buf); + o_ctrl, cmd_buf, remain_len); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed in parsing slave info"); - return rc; + goto rel_cmd_buf; } break; case CAMERA_SENSOR_CMD_TYPE_PWR_UP: @@ -505,11 +534,11 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) rc = cam_sensor_update_power_settings( cmd_buf, total_cmd_buf_in_bytes, - power_info); + power_info, remain_len); if (rc) { CAM_ERR(CAM_OIS, "Failed: parse power settings"); - return rc; + goto rel_cmd_buf; } break; default: @@ -527,7 +556,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "init parsing failed: %d", rc); - return rc; + goto rel_cmd_buf; } } else if ((o_ctrl->is_ois_calib != 0) && (o_ctrl->i2c_calib_data.is_settings_valid == @@ -544,18 +573,21 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) if (rc < 0) { CAM_ERR(CAM_OIS, "Calib parsing failed: %d", rc); - return rc; + goto rel_cmd_buf; } } break; } + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_OIS, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); } 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; + goto rel_pkt; } o_ctrl->cam_ois_state = CAM_OIS_CONFIG; } @@ -602,7 +634,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_WARN(CAM_OIS, "Not in right state to control OIS: %d", o_ctrl->cam_ois_state); - return rc; + goto rel_pkt; } offset = (uint32_t *)&csl_packet->payload; offset += (csl_packet->cmd_buf_offset / sizeof(uint32_t)); @@ -615,26 +647,43 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) cmd_desc, 1); if (rc < 0) { CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); - return rc; + goto rel_pkt; } rc = cam_ois_apply_settings(o_ctrl, i2c_reg_settings); if (rc < 0) { CAM_ERR(CAM_OIS, "Cannot apply mode settings"); - return rc; + goto rel_pkt; } rc = delete_request(i2c_reg_settings); - if (rc < 0) + if (rc < 0) { CAM_ERR(CAM_OIS, "Fail deleting Mode data: rc: %d", rc); + goto rel_pkt; + } break; default: - break; + CAM_ERR(CAM_OIS, "Invalid Opcode: %d", + (csl_packet->header.op_code & 0xFFFFFF)); + rc = -EINVAL; + goto rel_pkt; } - return rc; + + if (!rc) + goto rel_pkt; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_OIS, "Failed to put cpu buf: %d", + cmd_desc[i].mem_handle); pwr_dwn: cam_ois_power_down(o_ctrl); +rel_pkt: + if (cam_mem_put_cpu_buf(dev_config.packet_handle)) + CAM_WARN(CAM_OIS, "Fail in put buffer: %llu", + dev_config.packet_handle); + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h index d6f0ec564508..06022ababf4e 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_core.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 @@ -16,6 +16,8 @@ #include <linux/dma-contiguous.h> #include "cam_ois_dev.h" +#define OIS_NAME_LEN 32 + /** * @power_info: power setting info to control the power * diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c index 5d16a4e54d04..db583340dad4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -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 @@ -229,20 +229,23 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client) return -EINVAL; } + CAM_INFO(CAM_OIS, "i2c driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + soc_private = (struct cam_ois_soc_private *)soc_info->soc_private; power_info = &soc_private->power_info; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; kfree(o_ctrl->soc_info.soc_private); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); kfree(o_ctrl); return 0; @@ -303,8 +306,6 @@ static int32_t cam_ois_platform_driver_probe( 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; @@ -333,21 +334,26 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) return -EINVAL; } + CAM_INFO(CAM_OIS, "platform driver remove invoked"); soc_info = &o_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); + mutex_lock(&(o_ctrl->ois_mutex)); + cam_ois_shutdown(o_ctrl); + mutex_unlock(&(o_ctrl->ois_mutex)); + cam_unregister_subdev(&(o_ctrl->v4l2_dev_str)); + soc_private = (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; power_info = &soc_private->power_info; - kfree(power_info->power_setting); - kfree(power_info->power_down_setting); - power_info->power_setting = NULL; - power_info->power_down_setting = NULL; kfree(o_ctrl->soc_info.soc_private); kfree(o_ctrl->io_master_info.cci_client); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, NULL); kfree(o_ctrl); + return 0; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index d03faef4d3a6..ed2f9ad945a5 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -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 @@ -178,8 +178,10 @@ int cam_res_mgr_shared_pinctrl_init(void) return 0; } + mutex_lock(&cam_res->gpio_res_lock); if (cam_res->pstatus != PINCTRL_STATUS_PUT) { CAM_DBG(CAM_RES, "The shared pinctrl already been got."); + mutex_unlock(&cam_res->gpio_res_lock); return 0; } @@ -190,6 +192,7 @@ int cam_res_mgr_shared_pinctrl_init(void) if (IS_ERR_OR_NULL(pinctrl_info->pinctrl)) { CAM_ERR(CAM_RES, "Pinctrl not available"); cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); return -EINVAL; } @@ -200,6 +203,7 @@ int cam_res_mgr_shared_pinctrl_init(void) CAM_ERR(CAM_RES, "Failed to get the active state pinctrl handle"); cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); return -EINVAL; } @@ -210,10 +214,10 @@ int cam_res_mgr_shared_pinctrl_init(void) CAM_ERR(CAM_RES, "Failed to get the active state pinctrl handle"); cam_res->shared_gpio_enabled = false; + mutex_unlock(&cam_res->gpio_res_lock); return -EINVAL; } - mutex_lock(&cam_res->gpio_res_lock); cam_res->pstatus = PINCTRL_STATUS_GOT; mutex_unlock(&cam_res->gpio_res_lock); @@ -313,6 +317,7 @@ int cam_res_mgr_shared_pinctrl_select_state(bool active) pinctrl_info->gpio_state_suspend); cam_res->pstatus = PINCTRL_STATUS_SUSPEND; } + mutex_unlock(&cam_res->gpio_res_lock); return rc; @@ -379,12 +384,14 @@ static bool cam_res_mgr_gpio_is_shared(uint gpio) bool found = false; struct cam_res_mgr_dt *dt = &cam_res->dt; + mutex_lock(&cam_res->gpio_res_lock); for (; index < dt->num_shared_gpio; index++) { if (gpio == dt->shared_gpio[index]) { found = true; break; } } + mutex_unlock(&cam_res->gpio_res_lock); return found; } @@ -441,13 +448,14 @@ int cam_res_mgr_gpio_request(struct device *dev, uint gpio, INIT_LIST_HEAD(&gpio_res->list); INIT_LIST_HEAD(&gpio_res->dev_list); + mutex_lock(&cam_res->gpio_res_lock); rc = cam_res_mgr_add_device(dev, gpio_res); if (rc) { kfree(gpio_res); + mutex_unlock(&cam_res->gpio_res_lock); return rc; } - 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); } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c index 2117cc1f9587..5f77ca0a5293 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -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 @@ -17,6 +17,8 @@ #include "cam_soc_util.h" #include "cam_trace.h" #include "cam_common_util.h" +#include "cam_packet_util.h" + static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, @@ -94,6 +96,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, struct cam_cmd_buf_desc *cmd_desc = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; size_t len_of_buff = 0; + size_t remain_len = 0; uint32_t *offset = NULL; struct cam_config_dev_cmd config; struct i2c_data_settings *i2c_data = NULL; @@ -115,27 +118,42 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, &generic_ptr, &len_of_buff); if (rc < 0) { - CAM_ERR(CAM_SENSOR, "Failed in getting the buffer: %d", rc); + CAM_ERR(CAM_SENSOR, "Failed in getting the packet: %d", rc); return rc; } + remain_len = len_of_buff; + if ((sizeof(struct cam_packet) > len_of_buff) || + ((size_t)config.offset >= len_of_buff - + sizeof(struct cam_packet))) { + CAM_ERR(CAM_SENSOR, + "Inval cam_packet strut size: %zu, len_of_buff: %zu", + sizeof(struct cam_packet), len_of_buff); + rc = -EINVAL; + goto rel_pkt_buf; + } + + remain_len -= (size_t)config.offset; csl_packet = (struct cam_packet *)(generic_ptr + (uint32_t)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; + + if (cam_packet_util_validate_packet(csl_packet, + remain_len)) { + CAM_ERR(CAM_SENSOR, "Invalid packet params"); + rc = -EINVAL; + goto rel_pkt_buf; + } if ((csl_packet->header.op_code & 0xFFFFFF) != CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG && csl_packet->header.request_id <= s_ctrl->last_flush_req && s_ctrl->last_flush_req != 0) { - CAM_DBG(CAM_SENSOR, - "reject request %lld, last request to flush %lld", + CAM_ERR(CAM_SENSOR, + "reject request %lld, last request to flush %u", csl_packet->header.request_id, s_ctrl->last_flush_req); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } if (csl_packet->header.request_id > s_ctrl->last_flush_req) @@ -158,7 +176,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, } case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { if (s_ctrl->streamon_count > 0) - return 0; + goto rel_pkt_buf; s_ctrl->streamon_count = s_ctrl->streamon_count + 1; i2c_reg_settings = &i2c_data->streamon_settings; @@ -168,7 +186,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, } case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { if (s_ctrl->streamoff_count > 0) - return 0; + goto rel_pkt_buf; s_ctrl->streamoff_count = s_ctrl->streamoff_count + 1; i2c_reg_settings = &i2c_data->streamoff_settings; @@ -182,7 +200,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { CAM_WARN(CAM_SENSOR, "Rxed Update packets without linking"); - return 0; + goto rel_pkt_buf; } i2c_reg_settings = @@ -202,7 +220,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, * fix it. */ cam_sensor_update_req_mgr(s_ctrl, csl_packet); - return 0; + goto rel_pkt_buf; } break; } @@ -211,15 +229,16 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, (s_ctrl->sensor_state == CAM_SENSOR_ACQUIRE)) { CAM_WARN(CAM_SENSOR, "Rxed NOP packets without linking"); - return 0; + goto rel_pkt_buf; } cam_sensor_update_req_mgr(s_ctrl, csl_packet); - return 0; + goto rel_pkt_buf; } default: CAM_ERR(CAM_SENSOR, "Invalid Packet Header"); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } offset = (uint32_t *)&csl_packet->payload; @@ -230,7 +249,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, i2c_reg_settings, cmd_desc, 1); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); - return rc; + goto rel_pkt_buf; } if ((csl_packet->header.op_code & 0xFFFFFF) == @@ -240,6 +259,11 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, cam_sensor_update_req_mgr(s_ctrl, csl_packet); } +rel_pkt_buf: + if (cam_mem_put_cpu_buf(config.packet_handle)) + CAM_WARN(CAM_SENSOR, "Failed in put the buffer: %llu", + config.packet_handle); + return rc; } @@ -359,7 +383,7 @@ int32_t cam_sensor_update_slave_info(struct cam_cmd_probe *probe_info, 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 cmd_buf_num, uint32_t cmd_buf_length, size_t remain_len) { int32_t rc = 0; @@ -368,6 +392,13 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, struct cam_cmd_i2c_info *i2c_info = NULL; struct cam_cmd_probe *probe_info; + if (remain_len < + (sizeof(struct cam_cmd_i2c_info) + + sizeof(struct cam_cmd_probe))) { + CAM_ERR(CAM_SENSOR, + "not enough buffer for cam_cmd_i2c_info"); + return -EINVAL; + } i2c_info = (struct cam_cmd_i2c_info *)cmd_buf; rc = cam_sensor_update_i2c_info(i2c_info, s_ctrl); if (rc < 0) { @@ -386,7 +417,8 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, break; case 1: { rc = cam_sensor_update_power_settings(cmd_buf, - cmd_buf_length, &s_ctrl->sensordata->power_info); + cmd_buf_length, &s_ctrl->sensordata->power_info, + remain_len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in updating power settings"); @@ -407,10 +439,11 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) 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; + size_t remain_len = 0; rc = cam_mem_get_cpu_buf(handle, &packet, &len); @@ -418,18 +451,35 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); return -EINVAL; } + pkt = (struct cam_packet *)packet; + if (pkt == NULL) { + CAM_ERR(CAM_SENSOR, "packet pos is invalid"); + rc = -EINVAL; + goto rel_pkt_buf; + } + + if ((len < sizeof(struct cam_packet)) || + (pkt->cmd_buf_offset >= (len - sizeof(struct cam_packet)))) { + CAM_ERR(CAM_SENSOR, "Not enough buf provided"); + rc = -EINVAL; + goto rel_pkt_buf; + } + 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; + rc = -EINVAL; + goto rel_pkt_buf; } if (pkt->num_cmd_buf != 2) { CAM_ERR(CAM_SENSOR, "Expected More Command Buffers : %d", pkt->num_cmd_buf); - return -EINVAL; + rc = -EINVAL; + goto rel_pkt_buf; } + for (i = 0; i < pkt->num_cmd_buf; i++) { if (!(cmd_desc[i].length)) continue; @@ -438,20 +488,54 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); - return -EINVAL; + goto rel_pkt_buf; + } + if (cmd_desc[i].offset >= len) { + CAM_ERR(CAM_SENSOR, + "offset past length of buffer"); + rc = -EINVAL; + goto rel_pkt_buf; + } + remain_len = len - cmd_desc[i].offset; + if (cmd_desc[i].length > remain_len) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided for cmd"); + rc = -EINVAL; + goto rel_pkt_buf; } 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); + i, cmd_desc[i].length, remain_len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); - return -EINVAL; + goto rel_cmd_buf; } + + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, + "Failed to put command Buffer : %d", + cmd_desc[i].mem_handle); } + + if (cam_mem_put_cpu_buf(handle)) + CAM_WARN(CAM_SENSOR, "Failed to put the command Buffer: %llu", + handle); + + return rc; + +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, "Failed to put command Buffer : 0x%x", + cmd_desc[i].mem_handle); +rel_pkt_buf: + if (cam_mem_put_cpu_buf(handle)) + CAM_WARN(CAM_SENSOR, "Failed to put the command Buffer: %llu", + handle); + return rc; } @@ -507,11 +591,13 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) cam_sensor_release_stream_rsc(s_ctrl); cam_sensor_release_per_frame_resource(s_ctrl); - cam_sensor_power_down(s_ctrl); + + if (s_ctrl->sensor_state != CAM_SENSOR_INIT) + 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"); + CAM_ERR(CAM_SENSOR, "dhdl already destroyed: rc = %d", rc); s_ctrl->bridge_intf.device_hdl = -1; s_ctrl->bridge_intf.link_hdl = -1; s_ctrl->bridge_intf.session_hdl = -1; @@ -843,7 +929,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, 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); + CAM_ERR(CAM_SENSOR, "Failed i2c pkt parse: %d", rc); goto release_mutex; } if (s_ctrl->i2c_data.init_settings.is_settings_valid && @@ -1210,12 +1296,19 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + if (s_ctrl->sensor_state != CAM_SENSOR_START || + s_ctrl->sensor_state != CAM_SENSOR_CONFIG) { + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; + } + if (s_ctrl->i2c_data.per_frame == NULL) { CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return -EINVAL; } - mutex_lock(&(s_ctrl->cam_sensor_mutex)); if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) { s_ctrl->last_flush_req = flush_req->req_id; CAM_DBG(CAM_SENSOR, "last reqest to flush is %lld", diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c index 8dcb6c73312f..5c5c97099d43 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -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 @@ -199,7 +199,7 @@ static int32_t cam_sensor_driver_i2c_probe(struct i2c_client *client, 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)); @@ -220,11 +220,18 @@ static int cam_sensor_platform_remove(struct platform_device *pdev) return 0; } + CAM_INFO(CAM_SENSOR, "platform remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); soc_info = &s_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); kfree(s_ctrl->i2c_data.per_frame); + platform_set_drvdata(pdev, NULL); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); devm_kfree(&pdev->dev, s_ctrl); return 0; @@ -241,11 +248,17 @@ static int cam_sensor_driver_i2c_remove(struct i2c_client *client) return 0; } + CAM_INFO(CAM_SENSOR, "i2c remove invoked"); + mutex_lock(&(s_ctrl->cam_sensor_mutex)); + cam_sensor_shutdown(s_ctrl); + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + cam_unregister_subdev(&(s_ctrl->v4l2_dev_str)); soc_info = &s_ctrl->soc_info; for (i = 0; i < soc_info->num_clk; i++) devm_clk_put(soc_info->dev, soc_info->clk[i]); kfree(s_ctrl->i2c_data.per_frame); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), NULL); kfree(s_ctrl); return 0; @@ -323,8 +336,6 @@ static int32_t cam_sensor_driver_platform_probe( 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; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h index 1e9ec3db054a..7a2c56e3b686 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.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 @@ -325,6 +325,9 @@ enum msm_sensor_camera_id_t { CAMERA_1, CAMERA_2, CAMERA_3, + CAMERA_4, + CAMERA_5, + CAMERA_6, MAX_CAMERAS, }; diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 713bcaa8643a..7f6f3aa40998 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -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 @@ -298,6 +298,8 @@ int cam_sensor_i2c_command_parser( size_t len_of_buff = 0; uintptr_t generic_ptr; uint16_t cmd_length_in_bytes = 0; + size_t remain_len = 0; + size_t tot_size = 0; for (i = 0; i < num_cmd_buffers; i++) { uint32_t *cmd_buf = NULL; @@ -319,16 +321,35 @@ int cam_sensor_i2c_command_parser( rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, &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: %zd", cmd_desc[i].mem_handle, rc, len_of_buff); return rc; } + + remain_len = len_of_buff; + if ((len_of_buff < sizeof(struct common_header)) || + (cmd_desc[i].offset > + (len_of_buff - sizeof(struct common_header)))) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + cmd_buf = (uint32_t *)generic_ptr; cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + if (remain_len < cmd_desc[i].length) { + CAM_ERR(CAM_SENSOR, "buffer provided too small"); + return -EINVAL; + } + while (byte_cnt < cmd_desc[i].length) { + if ((remain_len - byte_cnt) < + sizeof(struct common_header)) { + CAM_ERR(CAM_SENSOR, "Not enough buffer"); + rc = -EINVAL; + goto rel_buf; + } cmm_hdr = (struct common_header *)cmd_buf; generic_op_code = cmm_hdr->third_byte; switch (cmm_hdr->cmd_type) { @@ -338,6 +359,24 @@ int cam_sensor_i2c_command_parser( *cam_cmd_i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_random_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto rel_buf; + } + tot_size = sizeof(struct i2c_rdwr_header) + + (sizeof(struct i2c_random_wr_payload) * + cam_cmd_i2c_random_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + rc = -EINVAL; + goto rel_buf; + } + rc = cam_sensor_handle_random_write( cam_cmd_i2c_random_wr, i2c_reg_settings, @@ -345,7 +384,7 @@ int cam_sensor_i2c_command_parser( if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in random write %d", rc); - return rc; + return -EINVAL; } cmd_buf += cmd_length_in_bytes / @@ -360,6 +399,24 @@ int cam_sensor_i2c_command_parser( (struct cam_cmd_i2c_continuous_wr *) cmd_buf; + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_i2c_continuous_wr)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + + tot_size = sizeof(struct i2c_rdwr_header) + + sizeof(cam_cmd_i2c_continuous_wr->reg_addr) + + (sizeof(struct cam_cmd_read) * + cam_cmd_i2c_continuous_wr->header.count); + + if (tot_size > (remain_len - byte_cnt)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer provided"); + return -EINVAL; + } + rc = cam_sensor_handle_continuous_write( cam_cmd_i2c_continuous_wr, i2c_reg_settings, @@ -376,11 +433,16 @@ int cam_sensor_i2c_command_parser( break; } case CAMERA_SENSOR_CMD_TYPE_WAIT: { + if ((remain_len - byte_cnt) < + sizeof(struct cam_cmd_unconditional_wait)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + return -EINVAL; + } 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, @@ -412,13 +474,20 @@ int cam_sensor_i2c_command_parser( break; } case CAMERA_SENSOR_CMD_TYPE_I2C_INFO: { + if (remain_len - byte_cnt < + sizeof(struct cam_cmd_i2c_info)) { + CAM_ERR(CAM_SENSOR, + "Not enough buffer space"); + rc = -EINVAL; + goto rel_buf; + } rc = cam_sensor_handle_slave_info( io_master, cmd_buf); if (rc) { CAM_ERR(CAM_SENSOR, - "Handle slave info failed with rc: %d", - rc); - return rc; + "Handle slave info failed with rc: %d", + rc); + goto rel_buf; } cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_info); @@ -430,13 +499,23 @@ int cam_sensor_i2c_command_parser( default: CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", cmm_hdr->cmd_type); - return -EINVAL; + rc = -EINVAL; + goto rel_buf; } } i2c_reg_settings->is_settings_valid = 1; + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, "put failed for buffer :%d", + cmd_desc[i].mem_handle); } return rc; + +rel_buf: + if (cam_mem_put_cpu_buf(cmd_desc[i].mem_handle)) + CAM_WARN(CAM_SENSOR, "put failed for buffer :%d", + cmd_desc[i].mem_handle); + return rc; } int cam_sensor_util_i2c_apply_setting( @@ -750,8 +829,32 @@ int cam_sensor_util_request_gpio_table( return rc; } + +static int32_t cam_sensor_validate(void *ptr, size_t remain_buf) +{ + struct common_header *cmm_hdr = (struct common_header *)ptr; + size_t validate_size = 0; + + if (remain_buf < sizeof(struct common_header)) + return -EINVAL; + + if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP || + cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) + validate_size = sizeof(struct cam_cmd_power); + else if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_WAIT) + validate_size = sizeof(struct cam_cmd_unconditional_wait); + + if (remain_buf < validate_size) { + CAM_ERR(CAM_SENSOR, "Invalid cmd_buf len %zu min %zu", + remain_buf, validate_size); + return -EINVAL; + } + return 0; +} + int32_t cam_sensor_update_power_settings(void *cmd_buf, - int cmd_length, struct cam_sensor_power_ctrl_t *power_info) + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len) { int32_t rc = 0, tot_size = 0, last_cmd_type = 0; int32_t i = 0, pwr_up = 0, pwr_down = 0; @@ -760,7 +863,8 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, 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) { + if (!pwr_cmd || !cmd_length || cmd_buf_len < (size_t)cmd_length || + cam_sensor_validate(cmd_buf, cmd_buf_len)) { CAM_ERR(CAM_SENSOR, "Invalid Args: pwr_cmd %pK, cmd_length: %d", pwr_cmd, cmd_length); return -EINVAL; @@ -787,16 +891,29 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, } while (tot_size < cmd_length) { + if (cam_sensor_validate(ptr, (cmd_length - tot_size))) { + rc = -EINVAL; + goto free_power_settings; + } if (cmm_hdr->cmd_type == CAMERA_SENSOR_CMD_TYPE_PWR_UP) { struct cam_cmd_power *pwr_cmd = (struct cam_cmd_power *)ptr; + if ((U16_MAX - power_info->power_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow occurs"); + rc = -EINVAL; + goto free_power_settings; + } + power_info->power_setting_size += pwr_cmd->count; - if (power_info->power_setting_size > MAX_POWER_CONFIG) { + if ((power_info->power_setting_size > MAX_POWER_CONFIG) + || (pwr_cmd->count >= SENSOR_SEQ_TYPE_MAX)) { CAM_ERR(CAM_SENSOR, - "Invalid: power up setting size %d", - power_info->power_setting_size); + "pwr_up setting size %d, pwr_cmd->count: %d", + power_info->power_setting_size, + pwr_cmd->count); rc = -EINVAL; goto free_power_settings; } @@ -891,12 +1008,21 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, scr = ptr + sizeof(struct cam_cmd_power); tot_size = tot_size + sizeof(struct cam_cmd_power); + if ((U16_MAX - power_info->power_down_setting_size) < + pwr_cmd->count) { + CAM_ERR(CAM_SENSOR, "ERR: Overflow"); + rc = -EINVAL; + goto free_power_settings; + } + power_info->power_down_setting_size += pwr_cmd->count; - if (power_info->power_down_setting_size > - MAX_POWER_CONFIG) { + if ((power_info->power_down_setting_size > + MAX_POWER_CONFIG) || (pwr_cmd->count >= + SENSOR_SEQ_TYPE_MAX)) { CAM_ERR(CAM_SENSOR, - "Invalid: power down setting size %d", - power_info->power_down_setting_size); + "pwr_down_setting_size %d, pwr_cmd->count: %d", + power_info->power_down_setting_size, + pwr_cmd->count); rc = -EINVAL; goto free_power_settings; } diff --git a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h index 583ddb14243b..85497fda011c 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_sensor_module/cam_sensor_utils/cam_sensor_util.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 @@ -60,7 +60,8 @@ int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, 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); + uint32_t cmd_length, struct cam_sensor_power_ctrl_t *power_info, + size_t cmd_buf_len); int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, int bob_reg_idx, bool flag); diff --git a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c index 7a772f1c4269..1be244bb7c3a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera_v3/cam_sync/cam_sync.c @@ -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 @@ -196,8 +196,8 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) 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); + "Sync object already signaled sync_obj = %d state = %d", + sync_obj, row->state); return -EALREADY; } @@ -323,8 +323,8 @@ int cam_sync_get_obj_ref(int32_t 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); + "accessing an uninitialized sync obj = %d state = %d", + sync_obj, row->state); return -EINVAL; } @@ -433,6 +433,7 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) { + int rc = 0; struct cam_sync_signal sync_signal; if (k_ioctl->size != sizeof(struct cam_sync_signal)) @@ -447,7 +448,14 @@ static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) return -EFAULT; /* need to get ref for UMD signaled fences */ - cam_sync_get_obj_ref(sync_signal.sync_obj); + rc = cam_sync_get_obj_ref(sync_signal.sync_obj); + if (rc) { + CAM_DBG(CAM_SYNC, + "Error: cannot signal an uninitialized sync obj = %d", + sync_signal.sync_obj); + return rc; + } + return cam_sync_signal(sync_signal.sync_obj, sync_signal.sync_state); } diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/Makefile b/drivers/media/platform/msm/camera_v3/cam_utils/Makefile index 7e1ebd3b7c64..9b14dfb9f6a4 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/Makefile +++ b/drivers/media/platform/msm/camera_v3/cam_utils/Makefile @@ -3,3 +3,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_req_mgr/ ccflags-y += -Idrivers/media/platform/msm/camera_v3/cam_smmu/ obj-$(CONFIG_SPECTRA_CAMERA) += cam_soc_util.o cam_io_util.o cam_packet_util.o cam_debug_util.o cam_trace.o cam_common_util.o +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cx_ipeak.o diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.c new file mode 100644 index 000000000000..99de0cba82ad --- /dev/null +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.c @@ -0,0 +1,135 @@ +/* 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 <linux/of.h> +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <soc/qcom/cx_ipeak.h> +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +static struct cx_ipeak_client *cam_cx_ipeak; +static int cx_ipeak_level = CAM_NOMINAL_VOTE; +static int cx_default_ipeak_mask; +static int cx_current_ipeak_mask; +static int cam_cx_client_cnt; + +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + + soc_info->cam_cx_ipeak_enable = true; + soc_info->cam_cx_ipeak_bit = 1 << cam_cx_client_cnt++; + cx_default_ipeak_mask |= soc_info->cam_cx_ipeak_bit; + + if (cam_cx_ipeak) + goto exit; + + cam_cx_ipeak = cx_ipeak_register(soc_info->dev->of_node, + "qcom,cam-cx-ipeak"); + + if (cam_cx_ipeak) { + goto exit; + } else { + rc = -EINVAL; + goto exit; + } + +exit: + CAM_DBG(CAM_UTIL, "cam_cx_ipeak is enabled for %s\n" + "mask = %x cx_default_ipeak_mask = %x", + soc_info->dev_name, soc_info->cam_cx_ipeak_bit, + cx_default_ipeak_mask); + return rc; +} + +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + int ret = 0; + + CAM_DBG(CAM_UTIL, "E: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + + if (apply_level < cx_ipeak_level && + (cx_current_ipeak_mask & soc_cx_ipeak_bit)) { + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, false); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s UNVOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s DISABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + goto exit; + } else if (apply_level < cx_ipeak_level) { + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x NO AI", + apply_level, cx_current_ipeak_mask, soc_cx_ipeak_bit); + goto exit; + } + + cx_current_ipeak_mask |= soc_cx_ipeak_bit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s ENABLE_BIT", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + ret = cx_ipeak_update(cam_cx_ipeak, true); + if (ret) + goto exit; + CAM_DBG(CAM_UTIL, + "X: apply_level = %d cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x %s VOTE", + apply_level, cx_current_ipeak_mask, + soc_cx_ipeak_bit, soc_info->dev_name); + } + +exit: + return ret; +} + +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info) +{ + int32_t soc_cx_ipeak_bit = soc_info->cam_cx_ipeak_bit; + + CAM_DBG(CAM_UTIL, "E:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + if (cx_current_ipeak_mask == cx_default_ipeak_mask) { + if (cam_cx_ipeak) + cx_ipeak_update(cam_cx_ipeak, false); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x UNVOTE", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + } + cx_current_ipeak_mask &= (~soc_cx_ipeak_bit); + CAM_DBG(CAM_UTIL, "X:cx_current_ipeak_mask = %x\n" + "soc_cx_ipeak_bit = %x", + cx_current_ipeak_mask, soc_cx_ipeak_bit); + + return 0; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_log.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.h index 321248a3e0eb..f811ac549429 100644 --- a/drivers/media/platform/msm/camera_v3/cam_isp/cam_isp_log.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_cx_ipeak.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -10,17 +10,17 @@ * GNU General Public License for more details. */ -#ifndef _CAM_ISP_LOG_H_ -#define _CAM_ISP_LOG_H_ +#ifndef _CAM_CX_IPEAK_H_ +#define _CAM_CX_IPEAK_H_ -#include <linux/kernel.h> +#include <linux/clk/qcom.h> +#include <soc/qcom/cx_ipeak.h> +#include "cam_io_util.h" -#define ISP_TRACE_ENABLE 1 +int cam_cx_ipeak_register_cx_ipeak(struct cam_hw_soc_info *soc_info); -#if (ISP_TRACE_ENABLE == 1) - #define ISP_TRACE(args...) trace_printk(args) -#else - #define ISP_TRACE(arg...) -#endif +int cam_cx_ipeak_update_vote_cx_ipeak(struct cam_hw_soc_info *soc_info, + int32_t apply_level); +int cam_cx_ipeak_unvote_cx_ipeak(struct cam_hw_soc_info *soc_info); -#endif /* __CAM_ISP_LOG_H__ */ +#endif /* _CAM_CX_IPEAK_H_ */ diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c index acfae3622130..ba244e780336 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.c @@ -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 @@ -50,23 +50,44 @@ int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) return 0; } -int cam_packet_util_validate_packet(struct cam_packet *packet) +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len) { + size_t sum_cmd_desc = 0; + size_t sum_io_cfgs = 0; + size_t sum_patch_desc = 0; + size_t pkt_wo_payload = 0; + if (!packet) return -EINVAL; + if ((size_t)packet->header.size > remain_len) { + CAM_ERR(CAM_UTIL, + "Invalid packet size: %zu, CPU buf length: %zu", + (size_t)packet->header.size, remain_len); + return -EINVAL; + } + + CAM_DBG(CAM_UTIL, "num cmd buf:%d num of io config:%d kmd buf index:%d", packet->num_cmd_buf, packet->num_io_configs, packet->kmd_cmd_buf_index); - 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); + sum_cmd_desc = packet->num_cmd_buf * sizeof(struct cam_cmd_buf_desc); + sum_io_cfgs = packet->num_io_configs * sizeof(struct cam_buf_io_cfg); + sum_patch_desc = packet->num_patches * sizeof(struct cam_patch_desc); + pkt_wo_payload = offsetof(struct cam_packet, payload); + + if ((!packet->header.size) || + ((pkt_wo_payload + (size_t)packet->cmd_buf_offset + + sum_cmd_desc) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->io_configs_offset + + sum_io_cfgs) > (size_t)packet->header.size) || + ((pkt_wo_payload + (size_t)packet->patch_offset + + sum_patch_desc) > (size_t)packet->header.size)) { + CAM_ERR(CAM_UTIL, "params not within mem len:%zu %zu %zu %zu", + (size_t)packet->header.size, sum_cmd_desc, + sum_io_cfgs, sum_patch_desc); return -EINVAL; } @@ -78,6 +99,7 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, { int rc = 0; size_t len = 0; + size_t remain_len = 0; struct cam_cmd_buf_desc *cmd_desc; uint32_t *cpu_addr; @@ -86,6 +108,13 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, return -EINVAL; } + if ((packet->kmd_cmd_buf_index < 0) || + (packet->kmd_cmd_buf_index > packet->num_cmd_buf)) { + CAM_ERR(CAM_UTIL, "Invalid kmd buf index: %d", + packet->kmd_cmd_buf_index); + return -EINVAL; + } + /* Take first command descriptor and add offset to it for kmd*/ cmd_desc = (struct cam_cmd_buf_desc *) ((uint8_t *) &packet->payload + packet->cmd_buf_offset); @@ -100,10 +129,21 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, if (rc) return rc; - if (len < cmd_desc->size) { + remain_len = len; + if (((size_t)cmd_desc->offset >= len) || + ((size_t)cmd_desc->size > (len - (size_t)cmd_desc->offset))) { CAM_ERR(CAM_UTIL, "invalid memory len:%zd and cmd desc size:%d", len, cmd_desc->size); - return -EINVAL; + rc = -EINVAL; + goto rel_kmd_buf; + } + + remain_len -= (size_t)cmd_desc->offset; + if ((size_t)packet->kmd_cmd_buf_offset >= remain_len) { + CAM_ERR(CAM_UTIL, "Invalid kmd cmd buf offset: %zu", + (size_t)packet->kmd_cmd_buf_offset); + rc = -EINVAL; + goto rel_kmd_buf; } cpu_addr += (cmd_desc->offset / 4) + (packet->kmd_cmd_buf_offset / 4); @@ -120,6 +160,11 @@ int cam_packet_util_get_kmd_buffer(struct cam_packet *packet, kmd_buf->size = cmd_desc->size - cmd_desc->length; kmd_buf->used_bytes = 0; +rel_kmd_buf: + if (cam_mem_put_cpu_buf(cmd_desc->mem_handle)) + CAM_WARN(CAM_UTIL, "Put KMD Buf failed for: 0x%x", + cmd_desc->mem_handle); + return rc; } @@ -128,7 +173,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet, { struct cam_patch_desc *patch_desc = NULL; dma_addr_t iova_addr; - uintptr_t cpu_addr; + uintptr_t cpu_addr = 0; uint32_t temp; uint32_t *dst_cpu_addr; uint32_t *src_buf_iova_addr; @@ -147,7 +192,6 @@ int cam_packet_util_process_patches(struct cam_packet *packet, 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, @@ -161,7 +205,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; } @@ -171,6 +215,20 @@ int cam_packet_util_process_patches(struct cam_packet *packet, patch_desc[i].dst_buf_hdl, patch_desc[i].dst_offset, patch_desc[i].src_buf_hdl, patch_desc[i].src_offset); + if ((size_t)patch_desc[i].src_offset >= src_buf_size) { + CAM_ERR(CAM_UTIL, + "Invalid src buf patch offset"); + return -EINVAL; + } + + if ((dst_buf_len < sizeof(void *)) || + ((dst_buf_len - sizeof(void *)) < + (size_t)patch_desc[i].dst_offset)) { + CAM_ERR(CAM_UTIL, + "Invalid dst buf patch offset"); + return -EINVAL; + } + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + patch_desc[i].dst_offset); temp += patch_desc[i].src_offset; @@ -181,6 +239,9 @@ int cam_packet_util_process_patches(struct cam_packet *packet, "patch is done for dst %pK with src %pK value %llx", dst_cpu_addr, src_buf_iova_addr, *((uint64_t *)dst_cpu_addr)); + if (cam_mem_put_cpu_buf(patch_desc[i].dst_buf_hdl)) + CAM_WARN(CAM_UTIL, "unable to put dst buf address:0x%x", + patch_desc[i].dst_buf_hdl); } return rc; @@ -191,8 +252,9 @@ int cam_packet_util_process_generic_cmd_buffer( cam_packet_generic_blob_handler blob_handler_cb, void *user_data) { int rc; - uintptr_t cpu_addr; + uintptr_t cpu_addr = 0; size_t buf_size; + size_t remain_len = 0; uint32_t *blob_ptr; uint32_t blob_type, blob_size, blob_block_size, len_read; @@ -215,6 +277,21 @@ int cam_packet_util_process_generic_cmd_buffer( return rc; } + remain_len = buf_size; + if ((buf_size < sizeof(uint32_t)) || + ((size_t)cmd_buf->offset > (buf_size - sizeof(uint32_t)))) { + CAM_ERR(CAM_UTIL, "Invalid offset for cmd buf: %zu", + (size_t)cmd_buf->offset); + goto rel_cmd_buf; + } + remain_len -= (size_t)cmd_buf->offset; + + if (remain_len < (size_t)cmd_buf->length) { + CAM_ERR(CAM_UTIL, "Invalid length for cmd buf: %zu", + (size_t)cmd_buf->length); + goto rel_cmd_buf; + } + blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) + cmd_buf->offset); @@ -244,7 +321,8 @@ int cam_packet_util_process_generic_cmd_buffer( CAM_ERR(CAM_UTIL, "Invalid Blob %d %d %d %d", blob_type, blob_size, len_read, cmd_buf->length); - return -EINVAL; + rc = -EINVAL; + goto rel_cmd_buf; } len_read += blob_block_size; @@ -254,11 +332,16 @@ int cam_packet_util_process_generic_cmd_buffer( if (rc) { CAM_ERR(CAM_UTIL, "Error in handling blob type %d %d", blob_type, blob_size); - return rc; + goto rel_cmd_buf; } blob_ptr += (blob_block_size / sizeof(uint32_t)); } - return 0; +rel_cmd_buf: + if (cam_mem_put_cpu_buf(cmd_buf->mem_handle)) + CAM_WARN(CAM_UTIL, "unable to put dst buf address: 0x%x", + cmd_buf->mem_handle); + + return rc; } diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h index b2315232262d..412eba52b05a 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_packet_util.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 @@ -37,6 +37,9 @@ struct cam_kmd_buf_info { typedef int (*cam_packet_generic_blob_handler)(void *user_data, uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data); +/* set resource bitmap callback function type */ +typedef void (*cam_fill_res_bitmap)(uint32_t res_type, unsigned long *bitmap); + /** * cam_packet_util_get_cmd_mem_addr() * @@ -59,10 +62,13 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, * * @packet: Packet to be validated * + * @remain_len: CPU buff length after config offset + * * @return: 0 for success * -EINVAL for Fail */ -int cam_packet_util_validate_packet(struct cam_packet *packet); +int cam_packet_util_validate_packet(struct cam_packet *packet, + size_t remain_len); /** * cam_packet_util_validate_cmd_desc() diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c index 4972a2a8cd08..693b0da29be2 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -18,6 +18,7 @@ #include <soc/qcom/socinfo.h> #include "cam_soc_util.h" #include "cam_debug_util.h" +#include "cam_cx_ipeak.h" #include <linux/nvmem-consumer.h> uint32_t cam_soc_util_get_soc_id(void) @@ -75,6 +76,33 @@ uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info) static char supported_clk_info[256]; static char debugfs_dir_name[64]; +static int cam_soc_util_get_clk_level(struct cam_hw_soc_info *soc_info, + int32_t src_clk_idx, int32_t clk_rate) +{ + int i; + long clk_rate_round; + + clk_rate_round = clk_round_rate(soc_info->clk[src_clk_idx], clk_rate); + if (clk_rate_round < 0) { + CAM_ERR(CAM_UTIL, "round failed rc = %ld", + clk_rate_round); + return -EINVAL; + } + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_rate[i][src_clk_idx] >= clk_rate_round) { + CAM_DBG(CAM_UTIL, + "soc = %d round rate = %ld actual = %d", + soc_info->clk_rate[i][src_clk_idx], + clk_rate_round, clk_rate); + return i; + } + } + + CAM_WARN(CAM_UTIL, "Invalid clock rate %ld", clk_rate_round); + return -EINVAL; +} + /** * cam_soc_util_get_string_from_level() * @@ -461,6 +489,7 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, { int32_t src_clk_idx; struct clk *clk = NULL; + int32_t apply_level; if (!soc_info || (soc_info->src_clk_idx < 0)) return -EINVAL; @@ -471,6 +500,17 @@ int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, src_clk_idx = soc_info->src_clk_idx; clk = soc_info->clk[src_clk_idx]; + if (soc_info->cam_cx_ipeak_enable && clk_rate >= 0) { + apply_level = cam_soc_util_get_clk_level(soc_info, src_clk_idx, + clk_rate); + CAM_DBG(CAM_UTIL, "set %s, rate %d dev_name = %s\n" + "apply level = %d", + soc_info->clk_name[src_clk_idx], clk_rate, + soc_info->dev_name, apply_level); + if (apply_level >= 0) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, + apply_level); + } return cam_soc_util_set_clk_rate(clk, soc_info->clk_name[src_clk_idx], clk_rate); @@ -623,17 +663,29 @@ int cam_soc_util_clk_enable_default(struct cam_hw_soc_info *soc_info, if (rc) return rc; + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + for (i = 0; i < soc_info->num_clk; i++) { rc = cam_soc_util_clk_enable(soc_info->clk[i], soc_info->clk_name[i], soc_info->clk_rate[apply_level][i]); if (rc) goto clk_disable; + if (soc_info->cam_cx_ipeak_enable) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk name = %s idx = %d\n" + "apply_level = %d clc idx = %d", + soc_info->dev_name, soc_info->clk_name[i], i, + apply_level, i); + } } return rc; clk_disable: + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); for (i--; i >= 0; i--) { cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); @@ -659,6 +711,8 @@ void cam_soc_util_clk_disable_default(struct cam_hw_soc_info *soc_info) if (soc_info->num_clk == 0) return; + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_unvote_cx_ipeak(soc_info); for (i = soc_info->num_clk - 1; i >= 0; i--) cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); @@ -700,7 +754,8 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) count = of_property_count_strings(of_node, "clock-names"); - CAM_DBG(CAM_UTIL, "count = %d", count); + CAM_DBG(CAM_UTIL, "E: dev_name = %s count = %d", + soc_info->dev_name, count); if (count > CAM_SOC_MAX_CLK) { CAM_ERR(CAM_UTIL, "invalid count of clocks, count=%d", count); rc = -EINVAL; @@ -819,6 +874,8 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) if (strcmp("true", clk_control_debugfs) == 0) soc_info->clk_control_enable = true; + CAM_DBG(CAM_UTIL, "X: dev_name = %s count = %d", + soc_info->dev_name, count); end: return rc; } @@ -841,12 +898,23 @@ int cam_soc_util_set_clk_rate_level(struct cam_hw_soc_info *soc_info, if (rc) return rc; + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, apply_level); + for (i = 0; i < soc_info->num_clk; i++) { rc = cam_soc_util_set_clk_rate(soc_info->clk[i], soc_info->clk_name[i], soc_info->clk_rate[apply_level][i]); - if (rc) + if (rc < 0) { + CAM_DBG(CAM_UTIL, + "dev name = %s clk_name = %s idx = %d\n" + "apply_level = %d", + soc_info->dev_name, soc_info->clk_name[i], + i, apply_level); + if (soc_info->cam_cx_ipeak_enable) + cam_cx_ipeak_update_vote_cx_ipeak(soc_info, 0); break; + } } return rc; @@ -1214,6 +1282,9 @@ int cam_soc_util_get_dt_properties(struct cam_hw_soc_info *soc_info) if (rc) return rc; + if (of_find_property(of_node, "qcom,cam-cx-ipeak", NULL)) + rc = cam_cx_ipeak_register_cx_ipeak(soc_info); + return rc; } @@ -1322,7 +1393,8 @@ int cam_soc_util_regulator_enable(struct regulator *rgltr, } static int cam_soc_util_request_pinctrl( - struct cam_hw_soc_info *soc_info) { + struct cam_hw_soc_info *soc_info) +{ struct cam_soc_pinctrl_info *device_pctrl = &soc_info->pinctrl_info; struct device *dev = soc_info->dev; @@ -1698,3 +1770,25 @@ int cam_soc_util_reg_dump(struct cam_hw_soc_info *soc_info, return 0; } + +uint32_t cam_soc_util_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate) +{ + int i = 0; + + if (!clock_rate) + return CAM_SVS_VOTE; + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_level_valid[i] && + soc_info->clk_rate[i][soc_info->src_clk_idx] >= + clock_rate) { + CAM_DBG(CAM_UTIL, + "Clock rate %lld, selected clock level %d", + clock_rate, i); + return i; + } + } + + return CAM_TURBO_VOTE; +} diff --git a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h index 91cc50daea83..ee07f0eb0a5d 100644 --- a/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera_v3/cam_utils/cam_soc_util.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -156,6 +156,7 @@ struct cam_soc_gpio_data { * @clk: Array of associated clock resources * @clk_rate: 2D array of clock rates representing clock rate * values at different vote levels + * @prev_clk_level Last vote level * @src_clk_idx: Source clock index that is rate-controllable * @clk_level_valid: Indicates whether corresponding level is valid * @gpio_data: Pointer to gpio info @@ -163,6 +164,8 @@ struct cam_soc_gpio_data { * @dentry: Debugfs entry * @clk_level_override: Clk level set from debugfs * @clk_control: Enable/disable clk rate control through debugfs + * @cam_cx_ipeak_enable cx-ipeak enable/disable flag + * @cam_cx_ipeak_bit cx-ipeak mask for driver * @soc_private: Soc private data */ struct cam_hw_soc_info { @@ -198,6 +201,7 @@ struct cam_hw_soc_info { const char *clk_name[CAM_SOC_MAX_CLK]; struct clk *clk[CAM_SOC_MAX_CLK]; int32_t clk_rate[CAM_MAX_VOTE][CAM_SOC_MAX_CLK]; + int32_t prev_clk_level; int32_t src_clk_idx; bool clk_level_valid[CAM_MAX_VOTE]; @@ -207,6 +211,8 @@ struct cam_hw_soc_info { struct dentry *dentry; uint32_t clk_level_override; bool clk_control_enable; + bool cam_cx_ipeak_enable; + int32_t cam_cx_ipeak_bit; void *soc_private; }; @@ -631,6 +637,10 @@ 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); + +uint32_t cam_soc_util_get_vote_level(struct cam_hw_soc_info *soc_info, + uint64_t clock_rate); + /** * cam_soc_util_get_soc_id() * diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index 0cdcbd6e0df1..225bd239d9c8 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -384,9 +384,10 @@ static int hfi_process_session_error(u32 device_id, } static int hfi_process_event_notify(u32 device_id, - struct hfi_msg_event_notify_packet *pkt, + 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)) { @@ -425,9 +426,10 @@ static int hfi_process_event_notify(u32 device_id, } static int hfi_process_sys_init_done(u32 device_id, - struct hfi_msg_sys_init_done_packet *pkt, + 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; @@ -464,9 +466,10 @@ err_no_prop: } static int hfi_process_sys_rel_resource_done(u32 device_id, - struct hfi_msg_sys_release_resource_done_packet *pkt, + 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; @@ -776,6 +779,11 @@ static int hfi_fill_codec_info(u8 *data_ptr, 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; @@ -787,6 +795,11 @@ static int hfi_fill_codec_info(u8 *data_ptr, 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; @@ -1264,9 +1277,10 @@ static void hfi_process_sess_get_prop_buf_req( } static int hfi_process_session_prop_info(u32 device_id, - struct hfi_msg_session_property_info_packet *pkt, + 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} } }; @@ -1305,9 +1319,10 @@ static int hfi_process_session_prop_info(u32 device_id, } static int hfi_process_session_init_done(u32 device_id, - struct hfi_msg_sys_session_init_done_packet *pkt, + 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} }; @@ -1332,9 +1347,10 @@ static int hfi_process_session_init_done(u32 device_id, } static int hfi_process_session_load_res_done(u32 device_id, - struct hfi_msg_session_load_resources_done_packet *pkt, + 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", @@ -1360,9 +1376,10 @@ static int hfi_process_session_load_res_done(u32 device_id, } static int hfi_process_session_flush_done(u32 device_id, - struct hfi_msg_session_flush_done_packet *pkt, + 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", @@ -1403,9 +1420,10 @@ static int hfi_process_session_flush_done(u32 device_id, } static int hfi_process_session_etb_done(u32 device_id, - struct hfi_msg_session_empty_buffer_done_packet *pkt, + 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; @@ -1457,9 +1475,10 @@ static int hfi_process_session_etb_done(u32 device_id, } static int hfi_process_session_ftb_done( - u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + 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; @@ -1585,9 +1604,10 @@ static int hfi_process_session_ftb_done( } static int hfi_process_session_start_done(u32 device_id, - struct hfi_msg_session_start_done_packet *pkt, + 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", @@ -1611,9 +1631,10 @@ static int hfi_process_session_start_done(u32 device_id, } static int hfi_process_session_stop_done(u32 device_id, - struct hfi_msg_session_stop_done_packet *pkt, + 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", @@ -1638,9 +1659,10 @@ static int hfi_process_session_stop_done(u32 device_id, } static int hfi_process_session_rel_res_done(u32 device_id, - struct hfi_msg_session_release_resources_done_packet *pkt, + 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", @@ -1665,9 +1687,10 @@ static int hfi_process_session_rel_res_done(u32 device_id, } static int hfi_process_session_rel_buf_done(u32 device_id, - struct hfi_msg_session_release_buffers_done_packet *pkt, + 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 < @@ -1698,9 +1721,10 @@ static int hfi_process_session_rel_buf_done(u32 device_id, } static int hfi_process_session_end_done(u32 device_id, - struct hfi_msg_sys_session_end_done_packet *pkt, + 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); @@ -1723,9 +1747,10 @@ static int hfi_process_session_end_done(u32 device_id, } static int hfi_process_session_abort_done(u32 device_id, - struct hfi_msg_sys_session_abort_done_packet *pkt, + 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", @@ -1793,9 +1818,10 @@ static void hfi_process_sys_get_prop_image_version( } static int hfi_process_sys_property_info(u32 device_id, - struct hfi_msg_sys_property_info_packet *pkt, + 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; @@ -1827,7 +1853,7 @@ static int hfi_process_sys_property_info(u32 device_id, } static int hfi_process_ignore(u32 device_id, - struct vidc_hal_msg_pkt_hdr *msg_hdr, + void *_pkt, struct msm_vidc_cb_info *info) { *info = (struct msm_vidc_cb_info) { @@ -1908,5 +1934,6 @@ int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, break; } - return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP; + return pkt_func ? + pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; } diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index f69b98e828b6..f1fbf990daef 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -66,6 +66,9 @@ /* 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, diff --git a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c index ca9edc8bebd1..9f85f5d8b0f0 100644 --- a/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc_3x/hfi_response_handler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -322,9 +322,10 @@ static int hfi_process_session_error(u32 device_id, } static int hfi_process_event_notify(u32 device_id, - struct hfi_msg_event_notify_packet *pkt, + 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)) { @@ -363,9 +364,10 @@ static int hfi_process_event_notify(u32 device_id, } static int hfi_process_sys_init_done(u32 device_id, - struct hfi_msg_sys_init_done_packet *pkt, + 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; @@ -402,9 +404,10 @@ err_no_prop: } static int hfi_process_sys_rel_resource_done(u32 device_id, - struct hfi_msg_sys_release_resource_done_packet *pkt, + 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; @@ -608,6 +611,11 @@ static int hfi_fill_codec_info(u8 *data_ptr, 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\n"); + break; + } } } codecs = sys_init_done->enc_codec_supported; @@ -619,6 +627,11 @@ static int hfi_fill_codec_info(u8 *data_ptr, 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\n"); + break; + } } } sys_init_done->codec_count = codec_count; @@ -1218,9 +1231,10 @@ static void hfi_process_sess_get_prop_buf_req( } static int hfi_process_session_prop_info(u32 device_id, - struct hfi_msg_session_property_info_packet *pkt, + 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 hfi_profile_level profile_level = {0}; enum hal_h264_entropy entropy = HAL_UNUSED_ENTROPY; @@ -1293,9 +1307,10 @@ static int hfi_process_session_prop_info(u32 device_id, } static int hfi_process_session_init_done(u32 device_id, - struct hfi_msg_sys_session_init_done_packet *pkt, + 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} }; @@ -1327,9 +1342,10 @@ static int hfi_process_session_init_done(u32 device_id, } static int hfi_process_session_load_res_done(u32 device_id, - struct hfi_msg_session_load_resources_done_packet *pkt, + 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", @@ -1357,9 +1373,10 @@ static int hfi_process_session_load_res_done(u32 device_id, } static int hfi_process_session_flush_done(u32 device_id, - struct hfi_msg_session_flush_done_packet *pkt, + 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", @@ -1402,9 +1419,10 @@ static int hfi_process_session_flush_done(u32 device_id, } static int hfi_process_session_etb_done(u32 device_id, - struct hfi_msg_session_empty_buffer_done_packet *pkt, + 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; @@ -1453,9 +1471,10 @@ static int hfi_process_session_etb_done(u32 device_id, } static int hfi_process_session_ftb_done( - u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + 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; @@ -1580,9 +1599,10 @@ static int hfi_process_session_ftb_done( } static int hfi_process_session_start_done(u32 device_id, - struct hfi_msg_session_start_done_packet *pkt, + 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", @@ -1608,9 +1628,10 @@ static int hfi_process_session_start_done(u32 device_id, } static int hfi_process_session_stop_done(u32 device_id, - struct hfi_msg_session_stop_done_packet *pkt, + 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", @@ -1637,9 +1658,10 @@ static int hfi_process_session_stop_done(u32 device_id, } static int hfi_process_session_rel_res_done(u32 device_id, - struct hfi_msg_session_release_resources_done_packet *pkt, + 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", @@ -1666,9 +1688,10 @@ static int hfi_process_session_rel_res_done(u32 device_id, } static int hfi_process_session_rel_buf_done(u32 device_id, - struct hfi_msg_session_release_buffers_done_packet *pkt, + 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 < @@ -1701,9 +1724,10 @@ static int hfi_process_session_rel_buf_done(u32 device_id, } static int hfi_process_session_end_done(u32 device_id, - struct hfi_msg_sys_session_end_done_packet *pkt, + 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); @@ -1728,9 +1752,10 @@ static int hfi_process_session_end_done(u32 device_id, } static int hfi_process_session_abort_done(u32 device_id, - struct hfi_msg_sys_session_abort_done_packet *pkt, + 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", @@ -1836,9 +1861,10 @@ static void hfi_process_sys_get_prop_image_version( } static int hfi_process_sys_property_info(u32 device_id, - struct hfi_msg_sys_property_info_packet *pkt, + 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; @@ -1870,7 +1896,7 @@ static int hfi_process_sys_property_info(u32 device_id, } static int hfi_process_ignore(u32 device_id, - struct vidc_hal_msg_pkt_hdr *msg_hdr, + void *_pkt, struct msm_vidc_cb_info *info) { *info = (struct msm_vidc_cb_info) { @@ -1954,5 +1980,6 @@ int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, break; } - return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP; + return pkt_func ? + pkt_func(device_id, (void *)msg_hdr, info) : -ENOTSUPP; } diff --git a/drivers/media/platform/msm/vidc_3x/msm_smem.c b/drivers/media/platform/msm/vidc_3x/msm_smem.c index a6d54765bd88..b67da1fc75b7 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_smem.c +++ b/drivers/media/platform/msm/vidc_3x/msm_smem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -476,7 +476,8 @@ bool msm_smem_compare_buffers(void *clt, int fd, void *priv) } handle = ion_import_dma_buf_fd(client->clnt, fd); ret = handle == priv; - handle ? ion_free(client->clnt, handle) : 0; + if (!IS_ERR_OR_NULL(handle)) + ion_free(client->clnt, handle); return ret; } diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc.c b/drivers/media/platform/msm/vidc_3x/msm_vidc.c index 983e600c6480..0a2d380dbbd7 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -1278,13 +1278,12 @@ void *msm_vidc_open(int core_id, int session_type) return inst; fail_init: + mutex_lock(&core->lock); v4l2_fh_del(&inst->event_handler); v4l2_fh_exit(&inst->event_handler); - vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); - - mutex_lock(&core->lock); list_del(&inst->list); mutex_unlock(&core->lock); + vb2_queue_release(&inst->bufq[OUTPUT_PORT].vb2_bufq); fail_bufq_output: vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq); diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c index 22f49ce02e47..af2514c60065 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -1638,11 +1638,11 @@ static void msm_comm_clean_notify_client(struct msm_vidc_core *core) 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(&inst->lock); } mutex_unlock(&core->lock); } diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h index 552e578e15c0..e383a6c56ffe 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_internal.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -40,8 +40,8 @@ #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 DEFAULT_HEIGHT 144 +#define DEFAULT_WIDTH 176 #define MIN_SUPPORTED_WIDTH 32 #define MIN_SUPPORTED_HEIGHT 32 #define DEFAULT_FPS 15 diff --git a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h index 875db097d9b2..a53d0b0f4f83 100644 --- a/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc_3x/vidc_hfi_api.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -66,6 +66,9 @@ /* 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, diff --git a/drivers/misc/hdcp_qseecom.c b/drivers/misc/hdcp_qseecom.c index 6ce377667623..f45dca30b11a 100644 --- a/drivers/misc/hdcp_qseecom.c +++ b/drivers/misc/hdcp_qseecom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -42,7 +42,7 @@ #define HDCP1_APP_NAME "hdcp1" #define QSEECOM_SBUFF_SIZE 0x1000 -#define MAX_TX_MESSAGE_SIZE 129 +#define MAX_TX_MESSAGE_SIZE 132 #define MAX_RX_MESSAGE_SIZE 534 #define MAX_TOPOLOGY_ELEMS 32 #define HDCP1_AKSV_SIZE 8 @@ -2037,6 +2037,30 @@ bool hdcp1_check_if_supported_load_app(void) return hdcp1_supported; } +void hdcp1_unload_app(void) +{ + int rc = 0; + + if (!hdcp1_supported) { + pr_debug("hdcp1 is not supported\n"); + return; + } + + if (!hdcp1_handle) { + pr_debug("invalid hdcp1 handle\n"); + return; + } + + rc = qseecom_shutdown_app(&hdcp1_handle); + if (rc) { + pr_debug("qseecom_shutdown_app failed with ERR = %d\n", rc); + return; + } + + hdcp1_handle = NULL; + pr_debug("hdcp1 app unloaded\n"); +} + /* APIs exposed to all clients */ int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb) { diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 07dbf1740353..8c774bd72a6d 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -50,6 +50,7 @@ #include <linux/compat.h> #include "compat_qseecom.h" +#include <linux/kthread.h> #define QSEECOM_DEV "qseecom" #define QSEOS_VERSION_14 0x14 @@ -109,6 +110,9 @@ #define DEFAULT_CE_INFO_UNIT 0 #define DEFAULT_NUM_CE_INFO_UNIT 1 +#define FDE_FLAG_POS 4 +#define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS) + enum qseecom_clk_definitions { CLK_DFAB = 0, CLK_SFPB, @@ -137,6 +141,11 @@ enum qseecom_ce_hw_instance { CLK_INVALID, }; +enum qseecom_listener_unregister_kthread_state { + LSNR_UNREG_KT_SLEEP = 0, + LSNR_UNREG_KT_WAKEUP, +}; + static struct class *driver_class; static dev_t qseecom_device_no; @@ -285,6 +294,7 @@ struct qseecom_control { unsigned int ce_opp_freq_hz; bool appsbl_qseecom_support; uint32_t qsee_reentrancy_support; + bool enable_key_wrap_in_ks; uint32_t app_block_ref_cnt; wait_queue_head_t app_block_wq; @@ -294,6 +304,9 @@ struct qseecom_control { struct list_head unregister_lsnr_pending_list_head; wait_queue_head_t register_lsnr_pending_wq; + struct task_struct *unregister_lsnr_kthread_task; + wait_queue_head_t unregister_lsnr_kthread_wq; + atomic_t unregister_lsnr_kthread_state; }; struct qseecom_sec_buf_fd_info { @@ -318,6 +331,7 @@ struct qseecom_client_handle { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; + bool from_smcinvoke; }; struct qseecom_listener_handle { @@ -403,6 +417,29 @@ static int get_qseecom_keymaster_status(char *str) } __setup("androidboot.keymaster=", get_qseecom_keymaster_status); + +#define QSEECOM_SCM_EBUSY_WAIT_MS 30 +#define QSEECOM_SCM_EBUSY_MAX_RETRY 67 + +static int __qseecom_scm_call2_locked(uint32_t smc_id, struct scm_desc *desc) +{ + int ret = 0; + int retry_count = 0; + + do { + ret = scm_call2_noretry(smc_id, desc); + if (ret == -EBUSY) { + mutex_unlock(&app_access_lock); + msleep(QSEECOM_SCM_EBUSY_WAIT_MS); + mutex_lock(&app_access_lock); + } + if (retry_count == 33) + pr_warn("secure world has been busy for 1 second!\n"); + } while (ret == -EBUSY && + (retry_count++ < QSEECOM_SCM_EBUSY_MAX_RETRY)); + return ret; +} + static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, const void *req_buf, void *resp_buf) { @@ -430,7 +467,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, svc_id, tz_cmd_id); return -EINVAL; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case SCM_SVC_ES: { @@ -453,7 +490,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = p_hash_req->partition_id; desc.args[1] = virt_to_phys(tzbuf); desc.args[2] = SHA256_DIGEST_LENGTH; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -488,7 +525,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_APP_SHUTDOWN_COMMAND: { @@ -498,7 +535,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, smc_id = TZ_OS_APP_SHUTDOWN_ID; desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID; desc.args[0] = req->app_id; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_APP_LOOKUP_COMMAND: { @@ -517,7 +554,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = strlen(req->app_name); __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -541,7 +578,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[1] = req_64bit->size; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LOAD_SERV_IMAGE_COMMAND: { @@ -565,14 +602,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: { smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID; desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_REGISTER_LISTENER: { @@ -597,11 +634,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, } qseecom.smcinvoke_support = true; smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID; - ret = scm_call2(smc_id, &desc); - if (ret && ret != -EBUSY) { + ret = __qseecom_scm_call2_locked(smc_id, &desc); + if (ret == -EIO) { + /* smcinvoke is not supported */ qseecom.smcinvoke_support = false; smc_id = TZ_OS_REGISTER_LISTENER_ID; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); } break; } @@ -613,7 +651,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, smc_id = TZ_OS_DEREGISTER_LISTENER_ID; desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID; desc.args[0] = req->listener_id; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LISTENER_DATA_RSP_COMMAND: { @@ -626,7 +664,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID; desc.args[0] = req->listener_id; desc.args[1] = req->status; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: { @@ -654,7 +692,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64->sglistinfo_ptr; desc.args[3] = req_64->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: { @@ -676,14 +714,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[2] = req_64bit->phy_addr; } __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: { smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID; desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } @@ -711,7 +749,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->rsp_ptr; desc.args[4] = req_64bit->rsp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: { @@ -743,7 +781,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_PROVISION_KEY_COMMAND: { @@ -755,21 +793,21 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID; desc.args[0] = req->key_type; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_ERASE_COMMAND: { smc_id = TZ_OS_RPMB_ERASE_ID; desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: { smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID; desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_GENERATE_KEY: { @@ -790,7 +828,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -812,7 +850,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -834,7 +872,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -856,7 +894,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[0] = virt_to_phys(tzbuf); desc.args[1] = tzbuflen; __qseecom_reentrancy_check_if_no_app_blocked(smc_id); - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); kzfree(tzbuf); break; } @@ -882,7 +920,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_OPEN_SESSION_WHITELIST: { @@ -912,7 +950,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND: { @@ -937,7 +975,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: { @@ -967,7 +1005,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_CLOSE_SESSION: { @@ -992,7 +1030,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_TEE_REQUEST_CANCELLATION: { @@ -1018,7 +1056,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; } - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: { @@ -1033,7 +1071,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, desc.arginfo = TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID; desc.args[0] = req->app_or_session_id; - ret = scm_call2(smc_id, &desc); + ret = __qseecom_scm_call2_locked(smc_id, &desc); break; } default: { @@ -1144,8 +1182,14 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc, resp.result = QSEOS_RESULT_INCOMPLETE; + mutex_unlock(&listener_access_lock); + mutex_lock(&app_access_lock); + __qseecom_reentrancy_check_if_no_app_blocked( + TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); + mutex_lock(&listener_access_lock); if (ret) { pr_err("qseecom_scm_call failed with err: %d\n", ret); return -EINVAL; @@ -1241,8 +1285,14 @@ static int __qseecom_unregister_listener(struct qseecom_dev_handle *data, req.listener_id = data->listener.id; resp.result = QSEOS_RESULT_INCOMPLETE; + mutex_unlock(&listener_access_lock); + mutex_lock(&app_access_lock); + __qseecom_reentrancy_check_if_no_app_blocked( + TZ_OS_DEREGISTER_LISTENER_ID); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(req), &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); + mutex_lock(&listener_access_lock); if (ret) { pr_err("scm_call() failed with err: %d (lstnr id=%d)\n", ret, data->listener.id); @@ -1258,9 +1308,6 @@ static int __qseecom_unregister_listener(struct qseecom_dev_handle *data, goto exit; } - data->abort = 1; - wake_up_all(&ptr_svc->rcv_req_wq); - while (atomic_read(&data->ioctl_count) > 1) { if (wait_event_freezable(data->abort_wq, atomic_read(&data->ioctl_count) <= 1)) { @@ -1299,6 +1346,10 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) ptr_svc->abort = 1; wake_up_interruptible_all(&qseecom.send_resp_wq); + /* stop listener thread waiting for listener request */ + data->abort = 1; + wake_up_all(&ptr_svc->rcv_req_wq); + /* return directly if pending*/ if (ptr_svc->unregister_pending) return 0; @@ -1356,6 +1407,30 @@ static void __qseecom_processing_pending_lsnr_unregister(void) wake_up_interruptible(&qseecom.register_lsnr_pending_wq); } +static void __wakeup_unregister_listener_kthread(void) +{ + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_WAKEUP); + wake_up_interruptible(&qseecom.unregister_lsnr_kthread_wq); +} + +static int __qseecom_unregister_listener_kthread_func(void *data) +{ + while (!kthread_should_stop()) { + wait_event_freezable( + qseecom.unregister_lsnr_kthread_wq, + atomic_read(&qseecom.unregister_lsnr_kthread_state) + == LSNR_UNREG_KT_WAKEUP); + pr_debug("kthread to unregister listener is called %d\n", + atomic_read(&qseecom.unregister_lsnr_kthread_state)); + __qseecom_processing_pending_lsnr_unregister(); + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_SLEEP); + } + pr_warn("kthread to unregister listener stopped\n"); + return 0; +} + static int __qseecom_set_msm_bus_request(uint32_t mode) { int ret = 0; @@ -1832,7 +1907,7 @@ err_resp: else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) { + if (ptr_svc && ptr_svc->ihandle) { ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, @@ -1898,6 +1973,7 @@ static int __qseecom_process_reentrancy_blocked_on_listener( sigset_t old_sigset; unsigned long flags; bool found_app = false; + struct qseecom_registered_app_list dummy_app_entry = { {NULL} }; if (!resp || !data) { pr_err("invalid resp or data pointer\n"); @@ -1907,24 +1983,31 @@ static int __qseecom_process_reentrancy_blocked_on_listener( /* find app_id & img_name from list */ if (!ptr_app) { - spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); - list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, - list) { - if ((ptr_app->app_id == data->client.app_id) && - (!strcmp(ptr_app->app_name, + if (data->client.from_smcinvoke) { + pr_debug("This request is from smcinvoke\n"); + ptr_app = &dummy_app_entry; + ptr_app->app_id = data->client.app_id; + } else { + spin_lock_irqsave(&qseecom.registered_app_list_lock, + flags); + list_for_each_entry(ptr_app, + &qseecom.registered_app_list_head, list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp(ptr_app->app_name, data->client.app_name))) { - found_app = true; - break; + found_app = true; + break; + } + } + spin_unlock_irqrestore( + &qseecom.registered_app_list_lock, flags); + if (!found_app) { + pr_err("app_id %d (%s) is not found\n", + data->client.app_id, + (char *)data->client.app_name); + ret = -ENOENT; + goto exit; } - } - spin_unlock_irqrestore(&qseecom.registered_app_list_lock, - flags); - if (!found_app) { - pr_err("app_id %d (%s) is not found\n", - data->client.app_id, - (char *)data->client.app_name); - ret = -ENOENT; - goto exit; } } @@ -2143,7 +2226,7 @@ err_resp: else *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; - if (ptr_svc) { + if (ptr_svc && ptr_svc->ihandle) { ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, @@ -2627,6 +2710,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, bool unload = false; bool found_app = false; bool found_dead_app = false; + bool scm_called = false; if (!data) { pr_err("Invalid/uninitialized device handle\n"); @@ -2685,11 +2769,12 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(struct qseecom_unload_app_ireq), &resp, sizeof(resp)); + scm_called = true; if (ret) { pr_err("scm_call to unload app (id = %d) failed\n", req.app_id); ret = -EFAULT; - goto unload_exit; + goto scm_exit; } else { pr_warn("App id %d now unloaded\n", req.app_id); } @@ -2697,7 +2782,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, pr_err("app (%d) unload_failed!!\n", data->client.app_id); ret = -EFAULT; - goto unload_exit; + goto scm_exit; } if (resp.result == QSEOS_RESULT_SUCCESS) pr_debug("App (%d) is unloaded!!\n", @@ -2707,11 +2792,35 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (ret) { pr_err("process_incomplete_cmd fail err: %d\n", ret); - goto unload_exit; + goto scm_exit; } } } +scm_exit: + if (scm_called) { + /* double check if this app_entry still exists */ + bool doublecheck = false; + + spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); + list_for_each_entry(ptr_app, + &qseecom.registered_app_list_head, list) { + if ((ptr_app->app_id == data->client.app_id) && + (!strcmp((void *)ptr_app->app_name, + (void *)data->client.app_name))) { + doublecheck = true; + break; + } + } + spin_unlock_irqrestore(&qseecom.registered_app_list_lock, + flags1); + if (!doublecheck) { + pr_warn("app %d(%s) entry is already removed\n", + data->client.app_id, + (char *)data->client.app_name); + found_app = false; + } + } unload_exit: if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); @@ -3292,7 +3401,6 @@ exit: pr_err("cache operation failed %d\n", ret2); return ret2; } - __qseecom_processing_pending_lsnr_unregister(); return ret; } @@ -4139,6 +4247,7 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle, struct ion_handle *ihandle = NULL; u8 *img_data = NULL; int retry = 0; + int ion_flag = ION_FLAG_CACHED; do { if (retry++) { @@ -4147,7 +4256,7 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle, mutex_lock(&app_access_lock); } ihandle = ion_alloc(qseecom.ion_clnt, fw_size, - SZ_4K, ION_HEAP(ION_QSECOM_TA_HEAP_ID), 0); + SZ_4K, ION_HEAP(ION_QSECOM_TA_HEAP_ID), ion_flag); } while (IS_ERR_OR_NULL(ihandle) && (retry <= QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP)); @@ -4509,7 +4618,7 @@ int qseecom_start_app(struct qseecom_handle **handle, uint32_t fw_size, app_arch; uint32_t app_id = 0; - __qseecom_processing_pending_lsnr_unregister(); + __wakeup_unregister_listener_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", @@ -4684,7 +4793,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) unsigned long flags = 0; bool found_handle = false; - __qseecom_processing_pending_lsnr_unregister(); + __wakeup_unregister_listener_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", @@ -4734,7 +4843,7 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, struct qseecom_dev_handle *data; bool perf_enabled = false; - __qseecom_processing_pending_lsnr_unregister(); + __wakeup_unregister_listener_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", @@ -4859,6 +4968,7 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc) resp.data = desc->ret[2]; /*listener_id*/ dummy_private_data.client.app_id = desc->ret[1]; + dummy_private_data.client.from_smcinvoke = true; dummy_app_entry.app_id = desc->ret[1]; mutex_lock(&app_access_lock); @@ -5978,6 +6088,9 @@ static int qseecom_create_key(struct qseecom_dev_handle *data, else flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE; + if (qseecom.enable_key_wrap_in_ks == true) + flags |= ENABLE_KEY_WRAP_IN_KS; + generate_key_ireq.flags = flags; generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY; memset((void *)generate_key_ireq.key_id, @@ -6378,7 +6491,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) if (ret) break; - ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc); + ret = __qseecom_scm_call2_locked(TZ_MDTP_CIPHER_DIP_ID, &desc); __qseecom_disable_clk(CLK_QSEE); @@ -7028,7 +7141,7 @@ static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data) } } -static inline long qseecom_ioctl(struct file *file, +static long qseecom_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = 0; @@ -7049,7 +7162,7 @@ static inline long qseecom_ioctl(struct file *file, cmd != QSEECOM_IOCTL_SEND_RESP_REQ && cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) - __qseecom_processing_pending_lsnr_unregister(); + __wakeup_unregister_listener_kthread(); switch (cmd) { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { @@ -8649,11 +8762,14 @@ static int qseecom_probe(struct platform_device *pdev) spin_lock_init(&qseecom.registered_kclient_list_lock); init_waitqueue_head(&qseecom.send_resp_wq); init_waitqueue_head(&qseecom.register_lsnr_pending_wq); + init_waitqueue_head(&qseecom.unregister_lsnr_kthread_wq); qseecom.send_resp_flag = 0; qseecom.qsee_version = QSEEE_VERSION_00; + mutex_lock(&app_access_lock); rc = qseecom_scm_call(6, 3, &feature, sizeof(feature), &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); pr_info("qseecom.qsee_version = 0x%x\n", resp.result); if (rc) { pr_err("Failed to get QSEE version info %d\n", rc); @@ -8715,6 +8831,14 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee_reentrancy_support); } + qseecom.enable_key_wrap_in_ks = + of_property_read_bool((&pdev->dev)->of_node, + "qcom,enable-key-wrap-in-ks"); + if (qseecom.enable_key_wrap_in_ks) { + pr_warn("qseecom.enable_key_wrap_in_ks = %d\n", + qseecom.enable_key_wrap_in_ks); + } + /* * The qseecom bus scaling flag can not be enabled when * crypto clock is not handled by HLOS. @@ -8800,9 +8924,11 @@ static int qseecom_probe(struct platform_device *pdev) rc = -EIO; goto exit_deinit_clock; } + mutex_lock(&app_access_lock); rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); + mutex_unlock(&app_access_lock); __qseecom_disable_clk(CLK_QSEE); if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) { pr_err("send secapp reg fail %d resp.res %d\n", @@ -8841,6 +8967,17 @@ static int qseecom_probe(struct platform_device *pdev) if (!qseecom.qsee_perf_client) pr_err("Unable to register bus client\n"); + /*create a kthread to process pending listener unregister task */ + qseecom.unregister_lsnr_kthread_task = kthread_run( + __qseecom_unregister_listener_kthread_func, + NULL, "qseecom-unreg-lsnr"); + if (IS_ERR(qseecom.unregister_lsnr_kthread_task)) { + pr_err("failed to create kthread to unregister listener\n"); + rc = -EINVAL; + goto exit_deinit_clock; + } + atomic_set(&qseecom.unregister_lsnr_kthread_state, + LSNR_UNREG_KT_SLEEP); atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; @@ -8957,6 +9094,8 @@ static int qseecom_remove(struct platform_device *pdev) ion_client_destroy(qseecom.ion_clnt); + kthread_stop(qseecom.unregister_lsnr_kthread_task); + cdev_del(&qseecom.cdev); device_destroy(driver_class, qseecom_device_no); diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index eb9ff362184e..f0324ec5e1dc 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -3434,8 +3434,14 @@ int mmc_resume_bus(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); mmc_bus_get(host); - if (host->ops->get_cd) + if (host->ops->get_cd) { card_present = host->ops->get_cd(host); + if (!card_present) { + pr_err("%s: Card removed - card_present:%d\n", + mmc_hostname(host), card_present); + mmc_card_set_removed(host->card); + } + } if (host->bus_ops && !host->bus_dead && host->card && card_present) { mmc_power_up(host, host->card->ocr); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 71a1cfb82d7e..6dd88ff389a3 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1376,11 +1376,21 @@ static int mmc_sd_resume(struct mmc_host *host) MMC_TRACE(host, "%s: Enter\n", __func__); err = _mmc_sd_resume(host); - pm_runtime_set_active(&host->card->dev); - pm_runtime_mark_last_busy(&host->card->dev); - pm_runtime_enable(&host->card->dev); - MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); + if (err) { + pr_err("%s: sd resume err: %d\n", mmc_hostname(host), err); + if (host->ops->get_cd && !host->ops->get_cd(host)) { + err = -ENOMEDIUM; + mmc_card_set_removed(host->card); + } + } + if (err != -ENOMEDIUM) { + pm_runtime_set_active(&host->card->dev); + pm_runtime_mark_last_busy(&host->card->dev); + pm_runtime_enable(&host->card->dev); + } + + MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err); return err; } diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c index 87fc883e8a73..a4d35d94de0c 100644 --- a/drivers/mmc/host/cmdq_hci.c +++ b/drivers/mmc/host/cmdq_hci.c @@ -911,11 +911,13 @@ static void cmdq_finish_data(struct mmc_host *mmc, unsigned int tag) cmdq_runtime_pm_put(cq_host); - if (cq_host->ops->crypto_cfg_end) { - err = cq_host->ops->crypto_cfg_end(mmc, mrq); - if (err) { - pr_err("%s: failed to end ice config: err %d tag %d\n", - mmc_hostname(mmc), err, tag); + if (!(mrq->cmdq_req->cmdq_req_flags & DCMD)) { + if (cq_host->ops->crypto_cfg_end) { + err = cq_host->ops->crypto_cfg_end(mmc, mrq); + if (err) { + pr_err("%s: failed to end ice config: err %d tag %d\n", + mmc_hostname(mmc), err, tag); + } } } if (!(cq_host->caps & CMDQ_CAP_CRYPTO_SUPPORT) && diff --git a/drivers/net/ppp/pppolac.c b/drivers/net/ppp/pppolac.c index 3a45cf805288..8ed809153120 100644 --- a/drivers/net/ppp/pppolac.c +++ b/drivers/net/ppp/pppolac.c @@ -83,7 +83,7 @@ static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb) /* Put it back if it is a control packet. */ if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT) - return opt->backlog_rcv(sk_udp, skb); + return 2; /* Skip UDP header. */ skb_pull(skb, sizeof(struct udphdr)); @@ -190,9 +190,10 @@ drop: static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb) { + int retval; sock_hold(sk_udp); - sk_receive_skb(sk_udp, skb, 0); - return 0; + retval = sk_receive_skb(sk_udp, skb, 0); + return (retval >> 1); } static struct sk_buff_head delivery_queue; diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 37df1bf277ca..09e8d38f57ae 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -752,11 +752,7 @@ static void cpu_pm_pmu_setup(struct arm_pmu *armpmu, unsigned long cmd) if (!event) continue; - /* - * Check if an attempt was made to free this event during - * the CPU went offline. - */ - if (event->state == PERF_EVENT_STATE_ZOMBIE) + if (event->state != PERF_EVENT_STATE_ACTIVE) continue; switch (cmd) { @@ -882,10 +878,8 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node) if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus)) return 0; - data.cmd = CPU_PM_EXIT; - cpu_pm_pmu_common(&data); - if (data.ret == NOTIFY_DONE) - return 0; + if (pmu->reset) + pmu->reset(pmu); if (data.armpmu->pmu_state != ARM_PMU_STATE_OFF && data.armpmu->plat_device) { @@ -911,8 +905,6 @@ static int arm_perf_stopping_cpu(unsigned int cpu, struct hlist_node *node) if (!pmu || !cpumask_test_cpu(cpu, &pmu->supported_cpus)) return 0; - data.cmd = CPU_PM_ENTER; - cpu_pm_pmu_common(&data); /* Disarm the PMU IRQ before disappearing. */ if (data.armpmu->pmu_state == ARM_PMU_STATE_RUNNING && data.armpmu->plat_device) { diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index f1f6b900d474..b3c38b9d7f86 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -737,8 +737,14 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, IPADBG("msg=%pK\n", msg); locked = 0; mutex_unlock(&ipa_ctx->msg_lock); + if (count < sizeof(struct ipa_msg_meta)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } if (copy_to_user(buf, &msg->meta, - sizeof(struct ipa_msg_meta))) { + sizeof(struct ipa_msg_meta))) { kfree(msg); msg = NULL; ret = -EFAULT; @@ -747,8 +753,15 @@ ssize_t ipa_read(struct file *filp, char __user *buf, size_t count, buf += sizeof(struct ipa_msg_meta); count -= sizeof(struct ipa_msg_meta); if (msg->buff) { - if (copy_to_user(buf, msg->buff, - msg->meta.msg_len)) { + if (count >= msg->meta.msg_len) { + if (copy_to_user(buf, msg->buff, + msg->meta.msg_len)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } + } else { kfree(msg); msg = NULL; ret = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index c348e26b6b69..d41cdb7c2f90 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -745,6 +745,12 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, if (msg) { locked = 0; mutex_unlock(&ipa3_ctx->msg_lock); + if (count < sizeof(struct ipa_msg_meta)) { + kfree(msg); + msg = NULL; + ret = -EFAULT; + break; + } if (copy_to_user(buf, &msg->meta, sizeof(struct ipa_msg_meta))) { ret = -EFAULT; @@ -755,8 +761,15 @@ ssize_t ipa3_read(struct file *filp, char __user *buf, size_t count, buf += sizeof(struct ipa_msg_meta); count -= sizeof(struct ipa_msg_meta); if (msg->buff) { - if (copy_to_user(buf, msg->buff, - msg->meta.msg_len)) { + if (count >= msg->meta.msg_len) { + if (copy_to_user(buf, msg->buff, + msg->meta.msg_len)) { + ret = -EFAULT; + kfree(msg); + msg = NULL; + break; + } + } else { ret = -EFAULT; kfree(msg); msg = NULL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 92fa1ecc4864..1271175c031c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -4414,7 +4414,7 @@ int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res) return -EINVAL; } - if (iface < 0 || iface > IPA_VLAN_IF_MAX) { + if (iface < 0 || iface >= IPA_VLAN_IF_MAX) { IPAERR("invalid iface %d\n", iface); return -EINVAL; } diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index c7a7f6becd88..7f16f4bea79b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -3910,6 +3910,15 @@ int rmnet_ipa3_send_lan_client_msg( IPAWANERR("Can't allocate memory for tether_info\n"); return -ENOMEM; } + + if (data->client_event != IPA_PER_CLIENT_STATS_CONNECT_EVENT && + data->client_event != IPA_PER_CLIENT_STATS_DISCONNECT_EVENT) { + IPAWANERR("Wrong event given. Event:- %d\n", + data->client_event); + kfree(lan_client); + return -EINVAL; + } + data->lan_client.lanIface[IPA_RESOURCE_NAME_MAX-1] = '\0'; memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); memcpy(lan_client, &data->lan_client, sizeof(struct ipa_lan_client_msg)); diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index 05a8c66d57aa..465e0793951c 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -675,7 +675,8 @@ int sps_get_bam_debug_info(unsigned long dev, u32 option, u32 para, /* Search for the target BAM device */ bam = sps_h2bam(dev); if (bam == NULL) { - pr_err("sps:Can't find any BAM with handle 0x%lx.", dev); + pr_err("sps:Can't find any BAM with handle 0x%pK.", + (void *)dev); mutex_unlock(&sps->lock); return SPS_ERROR; } @@ -1226,7 +1227,7 @@ struct sps_bam *sps_h2bam(unsigned long h) { struct sps_bam *bam; - SPS_DBG1(sps, "sps:%s: BAM handle:0x%lx.", __func__, h); + SPS_DBG1(sps, "sps:%s: BAM handle:0x%pK.", __func__, (void *)h); if (h == SPS_DEV_HANDLE_MEM || h == SPS_DEV_HANDLE_INVALID) return NULL; @@ -1236,7 +1237,7 @@ struct sps_bam *sps_h2bam(unsigned long h) return bam; } - SPS_ERR(sps, "sps:Can't find BAM device for handle 0x%lx.", h); + SPS_ERR(sps, "sps:Can't find BAM device for handle 0x%pK.", (void *)h); return NULL; } @@ -1341,16 +1342,17 @@ int sps_connect(struct sps_pipe *h, struct sps_connect *connect) bam = sps_h2bam(dev); if (bam == NULL) { - SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%lx", dev); + SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%pK", + (void *)dev); result = SPS_ERROR; goto exit_err; } mutex_lock(&bam->lock); - SPS_DBG2(bam, "sps:sps_connect: bam %pa src 0x%lx dest 0x%lx mode %s", + SPS_DBG2(bam, "sps:sps_connect: bam %pa src 0x%pK dest 0x%pK mode %s", BAM_ID(bam), - connect->source, - connect->destination, + (void *)connect->source, + (void *)connect->destination, connect->mode == SPS_MODE_SRC ? "SRC" : "DEST"); /* Allocate resources for the specified connection */ @@ -1414,10 +1416,10 @@ int sps_disconnect(struct sps_pipe *h) } SPS_DBG2(bam, - "sps:sps_disconnect: bam %pa src 0x%lx dest 0x%lx mode %s", + "sps:sps_disconnect: bam %pa src 0x%pK dest 0x%pK mode %s", BAM_ID(bam), - pipe->connect.source, - pipe->connect.destination, + (void *)pipe->connect.source, + (void *)pipe->connect.destination, pipe->connect.mode == SPS_MODE_SRC ? "SRC" : "DEST"); result = SPS_ERROR; @@ -1813,7 +1815,8 @@ int sps_device_reset(unsigned long dev) /* Search for the target BAM device */ bam = sps_h2bam(dev); if (bam == NULL) { - SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%lx", dev); + SPS_ERR(sps, "sps:Invalid BAM device handle: 0x%pK", + (void *)dev); result = SPS_ERROR; goto exit_err; } @@ -1824,7 +1827,8 @@ int sps_device_reset(unsigned long dev) result = sps_bam_reset(bam); mutex_unlock(&bam->lock); if (result) { - SPS_ERR(sps, "sps:Fail to reset BAM device: 0x%lx", dev); + SPS_ERR(sps, "sps:Fail to reset BAM device: 0x%pK", + (void *)dev); goto exit_err; } diff --git a/drivers/platform/msm/sps/sps_bam.c b/drivers/platform/msm/sps/sps_bam.c index 7d6a7eb039f6..475e9db39bd8 100644 --- a/drivers/platform/msm/sps/sps_bam.c +++ b/drivers/platform/msm/sps/sps_bam.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -895,8 +895,8 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, else iova = bam_pipe->connect.source_iova; SPS_DBG2(dev, - "sps:BAM %pa pipe %d uses IOVA 0x%lx.\n", - BAM_ID(dev), pipe_index, iova); + "sps:BAM %pa pipe %d uses IOVA 0x%pK.\n", + BAM_ID(dev), pipe_index, (void *)iova); hw_params.peer_phys_addr = (u32)iova; } else { hw_params.peer_phys_addr = peer_bam->props.phys_addr; @@ -918,9 +918,9 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, hw_params.data_base = (phys_addr_t)bam_pipe->connect.data.iova; SPS_DBG2(dev, - "sps:BAM %pa pipe %d uses IOVA 0x%lx for data FIFO.\n", + "sps:BAM %pa pipe %d uses IOVA 0x%pK for data FIFO.\n", BAM_ID(dev), pipe_index, - bam_pipe->connect.data.iova); + (void *)(bam_pipe->connect.data.iova)); } else { hw_params.data_base = map->data.phys_base; } @@ -971,9 +971,9 @@ int sps_bam_pipe_connect(struct sps_pipe *bam_pipe, hw_params.desc_base = (phys_addr_t)bam_pipe->connect.desc.iova; SPS_DBG2(dev, - "sps:BAM %pa pipe %d uses IOVA 0x%lx for desc FIFO.\n", + "sps:BAM %pa pipe %d uses IOVA 0x%pK for desc FIFO.\n", BAM_ID(dev), pipe_index, - bam_pipe->connect.desc.iova); + (void *)(bam_pipe->connect.desc.iova)); } else { hw_params.desc_base = map->desc.phys_base; } @@ -1424,8 +1424,9 @@ int sps_bam_pipe_transfer_one(struct sps_bam *dev, u32 next_write; static int show_recom; - SPS_DBG(dev, "sps:BAM %pa pipe %d addr 0x%x size 0x%x flags 0x%x\n", - BAM_ID(dev), pipe_index, addr, size, flags); + SPS_DBG(dev, "sps:BAM %pa pipe %d addr 0x%pK size 0x%x flags 0x%x\n", + BAM_ID(dev), pipe_index, + (void *)(long)addr, size, flags); /* Is this a BAM-to-BAM or satellite connection? */ if ((pipe->state & (BAM_STATE_BAM2BAM | BAM_STATE_REMOTE))) { @@ -1951,8 +1952,8 @@ static void pipe_handler_eot(struct sps_bam *dev, struct sps_pipe *pipe) user = &pipe->sys.user_ptrs[offset / sizeof(struct sps_iovec)]; for (;;) { SPS_DBG(dev, - "sps:%s; pipe index:%d; iovec addr:0x%x; size:0x%x; flags:0x%x; enabled:0x%x; *user is %s NULL.\n", - __func__, pipe->pipe_index, cache->addr, + "sps:%s; pipe index:%d; iovec addr:0x%pK; size:0x%x; flags:0x%x; enabled:0x%x; *user is %s NULL.\n", + __func__, pipe->pipe_index, (void *)(long)cache->addr, cache->size, cache->flags, enabled, (*user == NULL) ? "" : "not"); @@ -2240,8 +2241,8 @@ int sps_bam_pipe_get_iovec(struct sps_bam *dev, u32 pipe_index, pipe->sys.acked_offset = 0; SPS_DBG(dev, - "sps:%s; pipe index:%d; iovec addr:0x%x; size:0x%x; flags:0x%x; acked_offset:0x%x.\n", - __func__, pipe->pipe_index, desc->addr, + "sps:%s; pipe index:%d; iovec addr:0x%pK; size:0x%x; flags:0x%x; acked_offset:0x%x.\n", + __func__, pipe->pipe_index, (void *)(long)desc->addr, desc->size, desc->flags, pipe->sys.acked_offset); return 0; diff --git a/drivers/platform/msm/sps/sps_dma.c b/drivers/platform/msm/sps/sps_dma.c index abdcabc8cddd..0cc428399ecf 100644 --- a/drivers/platform/msm/sps/sps_dma.c +++ b/drivers/platform/msm/sps/sps_dma.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 2015, 2017, The Linux Foundation. All rights +/* Copyright (c) 2011-2013, 2015, 2017, 2019, The Linux Foundation. All rights * reserved. * * This program is free software; you can redistribute it and/or modify @@ -381,7 +381,7 @@ int sps_dma_device_de_init(unsigned long h) dev = sps_dma_find_device(h); if (dev == NULL) { - SPS_ERR(sps, "sps:BAM-DMA: not registered: %lx", h); + SPS_ERR(sps, "sps:BAM-DMA: not registered: %pK", (void *)h); result = SPS_ERROR; goto exit_err; } @@ -547,8 +547,8 @@ int sps_alloc_dma_chan(const struct sps_alloc_dma_chan *alloc, dev = sps_dma_find_device(alloc->dev); if (dev == NULL) { - SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %lx", - alloc->dev); + SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK", + (void *)alloc->dev); goto exit_err; } @@ -621,7 +621,8 @@ int sps_free_dma_chan(struct sps_dma_chan *chan) dev = sps_dma_find_device(chan->dev); if (dev == NULL) { - SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %lx", chan->dev); + SPS_ERR(sps, "sps:BAM-DMA: invalid BAM handle: %pK", + (void *)chan->dev); result = SPS_ERROR; goto exit_err; } diff --git a/drivers/platform/msm/sps/sps_mem.c b/drivers/platform/msm/sps/sps_mem.c index 105135a0e022..f5e026ba62ed 100644 --- a/drivers/platform/msm/sps/sps_mem.c +++ b/drivers/platform/msm/sps/sps_mem.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2013, 2015, 2017, The Linux Foundation. +/* Copyright (c) 2011-2013, 2015, 2017, 2019, The Linux Foundation. * All rights reserved. * * This program is free software; you can redistribute it and/or modify @@ -75,8 +75,8 @@ phys_addr_t sps_mem_alloc_io(u32 bytes) return SPS_ADDR_INVALID; } - SPS_DBG3(sps, "sps:sps_mem_alloc_io.phys=%pa.virt=0x%lx.size=0x%x.", - &phys_addr, virt_addr, bytes); + SPS_DBG3(sps, "sps:sps_mem_alloc_io.phys=%pa.virt=0x%pK.size=0x%x.", + &phys_addr, (void *)virt_addr, bytes); return phys_addr; } @@ -92,8 +92,8 @@ void sps_mem_free_io(phys_addr_t phys_addr, u32 bytes) iomem_offset = phys_addr - iomem_phys; virt_addr = (uintptr_t) iomem_virt + iomem_offset; - SPS_DBG3(sps, "sps:sps_mem_free_io.phys=%pa.virt=0x%lx.size=0x%x.", - &phys_addr, virt_addr, bytes); + SPS_DBG3(sps, "sps:sps_mem_free_io.phys=%pa.virt=0x%pK.size=0x%x.", + &phys_addr, (void *)virt_addr, bytes); gen_pool_free(pool, virt_addr, bytes); total_free += bytes; diff --git a/drivers/platform/msm/sps/sps_rm.c b/drivers/platform/msm/sps/sps_rm.c index 276b847979e1..ef6029a9e518 100644 --- a/drivers/platform/msm/sps/sps_rm.c +++ b/drivers/platform/msm/sps/sps_rm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2015, 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 @@ -380,8 +380,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) map->src.bam = sps_h2bam(map->src.dev); if (map->src.bam == NULL) { if (map->src.dev != SPS_DEV_HANDLE_MEM) { - SPS_ERR(sps, "sps:Invalid BAM handle: %pa", - &map->src.dev); + SPS_ERR(sps, "sps:Invalid BAM handle: %pK", + (void *)(&map->src.dev)); goto exit_err; } map->src.pipe_index = SPS_BAM_PIPE_INVALID; @@ -389,8 +389,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) map->dest.bam = sps_h2bam(map->dest.dev); if (map->dest.bam == NULL) { if (map->dest.dev != SPS_DEV_HANDLE_MEM) { - SPS_ERR(sps, "sps:Invalid BAM handle: %pa", - &map->dest.dev); + SPS_ERR(sps, "sps:Invalid BAM handle: %pK", + (void *)(&map->dest.dev)); goto exit_err; } map->dest.pipe_index = SPS_BAM_PIPE_INVALID; @@ -399,8 +399,8 @@ static struct sps_connection *sps_rm_create(struct sps_pipe *pipe) /* Check the BAM device for the pipe */ if ((dir == SPS_MODE_SRC && map->src.bam == NULL) || (dir != SPS_MODE_SRC && map->dest.bam == NULL)) { - SPS_ERR(sps, "sps:Invalid BAM endpt: dir %d src %pa dest %pa", - dir, &map->src.dev, &map->dest.dev); + SPS_ERR(sps, "sps:Invalid BAM endpt: dir %d src %pK dest %pK", + dir, (void *)(&map->src.dev), (void *)(&map->dest.dev)); goto exit_err; } diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index bc1855ea5d48..f56b9837f259 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. +/* 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 @@ -1115,10 +1115,14 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CYCLE_COUNT: case POWER_SUPPLY_PROP_VOLTAGE_NOW: - case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_TEMP: rc = smblib_get_prop_from_bms(chg, psp, val); 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; break; diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 7994741ccb1c..a4410734f6c5 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1367,6 +1367,8 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CURRENT_NOW, val); + if (!rc) + val->intval *= (-1); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: val->intval = get_client_vote(chg->fcc_votable, diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 896509dac561..523fe47a4d54 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 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 @@ -308,6 +308,7 @@ enum pmic_subtype { PMI8950 = 17, PMI8996 = 19, PMI8937 = 55, + PMI8940 = 64, }; enum smbchg_wa { @@ -1133,6 +1134,28 @@ static int get_prop_batt_voltage_max_design(struct smbchg_chip *chip) return uv; } +static int get_prop_batt_charge_counter(struct smbchg_chip *chip) +{ + int bcc = 0, rc; + + rc = get_property_from_fg(chip, + POWER_SUPPLY_PROP_CHARGE_COUNTER, &bcc); + if (rc) + pr_smb(PR_STATUS, "Couldn't get charge_counter rc = %d\n", rc); + return bcc; +} + +static int get_prop_batt_cycle_count(struct smbchg_chip *chip) +{ + int bcc = 0, rc; + + rc = get_property_from_fg(chip, + POWER_SUPPLY_PROP_CYCLE_COUNT, &bcc); + if (rc) + pr_smb(PR_STATUS, "Couldn't get cycle_count rc = %d\n", rc); + return bcc; +} + static int get_prop_batt_health(struct smbchg_chip *chip) { if (chip->batt_hot) @@ -5899,6 +5922,8 @@ static enum power_supply_property smbchg_battery_properties[] = { POWER_SUPPLY_PROP_RESTRICTED_CHARGING, POWER_SUPPLY_PROP_ALLOW_HVDCP3, POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CYCLE_COUNT, }; static int smbchg_battery_set_property(struct power_supply *psy, @@ -6118,6 +6143,12 @@ static int smbchg_battery_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED: val->intval = chip->max_pulse_allowed; break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = get_prop_batt_charge_counter(chip); + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + val->intval = get_prop_batt_cycle_count(chip); + break; default: return -EINVAL; } @@ -8096,6 +8127,8 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) case PMI8950: chip->wa_flags |= SMBCHG_RESTART_WA; case PMI8937: + /* fall through */ + case PMI8940: chip->wa_flags |= SMBCHG_BATT_OV_WA; if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ { chip->wa_flags |= SMBCHG_AICL_DEGLITCH_WA; @@ -8110,7 +8143,9 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) ARRAY_SIZE(aicl_rerun_period_schg_lite); chip->schg_version = QPNP_SCHG_LITE; - if (pmic_rev_id->pmic_subtype == PMI8937) + /* PMI8937/PMI8940 doesn't support HVDCP */ + if ((pmic_rev_id->pmic_subtype == PMI8937) + || (pmic_rev_id->pmic_subtype == PMI8940)) chip->hvdcp_not_supported = true; break; case PMI8996: diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index e23f13e2236f..9b0ec47df85a 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2888,6 +2888,7 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) chg->pd_active = pd_active; if (chg->pd_active) { + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; vote(chg->apsd_disable_votable, PD_VOTER, true, 0); vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); diff --git a/drivers/power/supply/qcom/smb1360-charger-fg.c b/drivers/power/supply/qcom/smb1360-charger-fg.c index 4e98ec752fa7..41dcf1dca25d 100644 --- a/drivers/power/supply/qcom/smb1360-charger-fg.c +++ b/drivers/power/supply/qcom/smb1360-charger-fg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2015, 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 @@ -31,6 +31,7 @@ #include <linux/qpnp/qpnp-adc.h> #include <linux/completion.h> #include <linux/pm_wakeup.h> +#include <linux/of_irq.h> #define _SMB1360_MASK(BITS, POS) \ ((unsigned char)(((1 << (BITS)) - 1) << (POS))) @@ -405,6 +406,7 @@ struct smb1360_chip { bool otg_fet_present; bool fet_gain_enabled; int otg_fet_enable_gpio; + int usb_id_gpio; /* status tracking */ int voltage_now; @@ -466,6 +468,7 @@ struct smb1360_chip { int cold_hysteresis; int hot_hysteresis; struct extcon_dev *extcon; + int usb_id_irq; }; static int chg_time[] = { @@ -2885,6 +2888,28 @@ static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t smb1360_usb_id_irq_handler(int irq, void *dev_id) +{ + struct smb1360_chip *chip = dev_id; + int rc = 0; + bool id_state; + + id_state = gpio_get_value(chip->usb_id_gpio); + + rc = smb1360_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, + !id_state ? CMD_OTG_EN_BIT : 0); + if (rc) { + pr_err("Couldn't enable OTG mode rc=%d\n", rc); + return IRQ_HANDLED; + } + extcon_set_state_sync(chip->extcon, EXTCON_USB_HOST, + !id_state ? true : false); + + pr_debug("usb_id_irq triggered, id_state = %d\n", id_state); + + return IRQ_HANDLED; +} + static int show_irq_count(struct seq_file *m, void *data) { int i, j, total = 0; @@ -3421,6 +3446,10 @@ static int smb1360_regulator_init(struct smb1360_chip *chip) int rc = 0; struct regulator_config cfg = {}; + /* OTG is enabled by SMB1360 if usb-id config is defined */ + if (chip->usb_id_gpio > 0 && chip->usb_id_irq > 0) + return 0; + chip->otg_vreg.rdesc.owner = THIS_MODULE; chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE; chip->otg_vreg.rdesc.ops = &smb1360_otg_reg_ops; @@ -3557,6 +3586,7 @@ static int determine_initial_status(struct smb1360_chip *chip) { int rc; u8 reg = 0; + bool id_state; /* * It is okay to read the IRQ status as the irq's are @@ -3621,6 +3651,25 @@ static int determine_initial_status(struct smb1360_chip *chip) else extcon_set_cable_state_(chip->extcon, EXTCON_USB, true); + pr_debug("usb %s at boot\n", chip->usb_present ? "present" : "absent"); + + /*check otg presence and notify*/ + if (chip->usb_id_gpio != -EINVAL) { + id_state = gpio_get_value(chip->usb_id_gpio); + /* usb-id is low, enable OTG */ + if (!id_state) { + rc = smb1360_masked_write(chip, CMD_CHG_REG, + CMD_OTG_EN_BIT, CMD_OTG_EN_BIT); + if (rc) { + pr_err("Couldn't enable OTG mode rc=%d\n", rc); + return rc; + } + extcon_set_state_sync(chip->extcon, EXTCON_USB_HOST, + true); + pr_debug("OTG enabled at boot\n"); + } + } + power_supply_changed(chip->usb_psy); return 0; } @@ -4752,6 +4801,11 @@ static int smb_parse_dt(struct smb1360_chip *chip) return rc; } } + chip->usb_id_gpio = -EINVAL; + if (of_find_property(node, "qcom,usb-id-gpio", NULL)) { + chip->usb_id_gpio = of_get_named_gpio(node, + "qcom,usb-id-gpio", 0); + } chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); @@ -5073,6 +5127,28 @@ static int smb1360_probe(struct i2c_client *client, enable_irq_wake(client->irq); } + chip->usb_id_irq = of_irq_get_byname(chip->dev->of_node, + "smb1360_usb_id_irq"); + if (chip->usb_id_irq > 0) { + if (chip->usb_id_gpio == -EINVAL) { + pr_err("usb-id gpio not defined\n"); + } else { + rc = devm_request_threaded_irq(&client->dev, + chip->usb_id_irq, NULL, + smb1360_usb_id_irq_handler, + IRQF_ONESHOT + | IRQF_TRIGGER_FALLING + | IRQF_TRIGGER_RISING, + "smb1360_usb_id_irq", chip); + if (rc < 0) { + dev_err(&client->dev, + "usb-id request_irq for irq=%d failed rc = %d\n", + chip->usb_id_irq, rc); + goto unregister_batt_psy; + } + enable_irq_wake(chip->usb_id_irq); + } + } chip->debug_root = debugfs_create_dir("smb1360", NULL); if (!chip->debug_root) dev_err(chip->dev, "Couldn't create debug dir\n"); @@ -5201,7 +5277,8 @@ static int smb1360_probe(struct i2c_client *client, unregister_batt_psy: power_supply_unregister(chip->batt_psy); fail_hw_init: - regulator_unregister(chip->otg_vreg.rdev); + if (chip->otg_vreg.rdev) + regulator_unregister(chip->otg_vreg.rdev); destroy_mutex: power_supply_unregister(chip->usb_psy); wakeup_source_trash(&chip->smb1360_ws.source); @@ -5218,8 +5295,9 @@ destroy_mutex: static int smb1360_remove(struct i2c_client *client) { struct smb1360_chip *chip = i2c_get_clientdata(client); + if (chip->otg_vreg.rdev) + regulator_unregister(chip->otg_vreg.rdev); - regulator_unregister(chip->otg_vreg.rdev); power_supply_unregister(chip->usb_psy); power_supply_unregister(chip->batt_psy); wakeup_source_trash(&chip->smb1360_ws.source); diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 17b808ca843d..1b7af04730ba 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -526,9 +526,19 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) if (state->period != pwm->state.period || state->duty_cycle != pwm->state.duty_cycle) { - err = pwm->chip->ops->config(pwm->chip, pwm, - state->duty_cycle, - state->period); + if (pwm->chip->ops->config_extend) { + err = pwm->chip->ops->config_extend(pwm->chip, + pwm, state->duty_cycle, + state->period); + } else { + if (state->period > UINT_MAX) + pr_warn("period %llu duty_cycle %llu will be truncated\n", + state->period, + state->duty_cycle); + err = pwm->chip->ops->config(pwm->chip, pwm, + state->duty_cycle, + state->period); + } if (err) return err; @@ -1017,8 +1027,8 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) if (state.enabled) seq_puts(s, " enabled"); - seq_printf(s, " period: %u ns", state.period); - seq_printf(s, " duty: %u ns", state.duty_cycle); + seq_printf(s, " period: %llu ns", state.period); + seq_printf(s, " duty: %llu ns", state.duty_cycle); seq_printf(s, " polarity: %s", state.polarity ? "inverse" : "normal"); diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index d24bef10c1d7..f5c5e399af7f 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -164,7 +164,7 @@ struct lpg_pwm_config { u32 prediv; u32 clk_exp; u16 pwm_value; - u32 best_period_ns; + u64 best_period_ns; }; struct qpnp_lpg_lut { @@ -185,8 +185,8 @@ struct qpnp_lpg_channel { u8 src_sel; u8 subtype; bool lut_written; - int current_period_ns; - int current_duty_ns; + u64 current_period_ns; + u64 current_duty_ns; }; struct qpnp_lpg_chip { @@ -723,17 +723,17 @@ static int qpnp_lpg_set_ramp_config(struct qpnp_lpg_channel *lpg) return rc; } -static void __qpnp_lpg_calc_pwm_period(int period_ns, +static void __qpnp_lpg_calc_pwm_period(u64 period_ns, struct lpg_pwm_config *pwm_config) { struct qpnp_lpg_channel *lpg = container_of(pwm_config, struct qpnp_lpg_channel, pwm_config); struct lpg_pwm_config configs[NUM_PWM_SIZE]; int i, j, m, n; - int tmp1, tmp2; - int clk_period_ns = 0, pwm_clk_period_ns; - int clk_delta_ns = INT_MAX, min_clk_delta_ns = INT_MAX; - int pwm_period_delta = INT_MAX, min_pwm_period_delta = INT_MAX; + u64 tmp1, tmp2; + u64 clk_period_ns = 0, pwm_clk_period_ns; + u64 clk_delta_ns = U64_MAX, min_clk_delta_ns = U64_MAX; + u64 pwm_period_delta = U64_MAX, min_pwm_period_delta = U64_MAX; int pwm_size_step; /* @@ -755,7 +755,8 @@ static void __qpnp_lpg_calc_pwm_period(int period_ns, for (m = 0; m < ARRAY_SIZE(pwm_exponent); m++) { tmp1 = 1 << pwm_exponent[m]; tmp1 *= clk_prediv[j]; - tmp2 = NSEC_PER_SEC / clk_freq_hz[i]; + tmp2 = NSEC_PER_SEC; + do_div(tmp2, clk_freq_hz[i]); clk_period_ns = tmp1 * tmp2; @@ -785,10 +786,7 @@ static void __qpnp_lpg_calc_pwm_period(int period_ns, configs[n].best_period_ns *= 1 << pwm_size[n]; /* Find the closest setting for PWM period */ - if (min_clk_delta_ns < INT_MAX >> pwm_size[n]) - pwm_period_delta = min_clk_delta_ns << pwm_size[n]; - else - pwm_period_delta = INT_MAX; + pwm_period_delta = min_clk_delta_ns << pwm_size[n]; if (pwm_period_delta < min_pwm_period_delta) { min_pwm_period_delta = pwm_period_delta; memcpy(pwm_config, &configs[n], @@ -806,21 +804,20 @@ static void __qpnp_lpg_calc_pwm_period(int period_ns, pwm_config->clk_exp -= pwm_size_step; } } - pr_debug("PWM setting for period_ns %d: pwm_clk = %dHZ, prediv = %d, exponent = %d, pwm_size = %d\n", + pr_debug("PWM setting for period_ns %llu: pwm_clk = %dHZ, prediv = %d, exponent = %d, pwm_size = %d\n", period_ns, pwm_config->pwm_clk, pwm_config->prediv, pwm_config->clk_exp, pwm_config->pwm_size); - pr_debug("Actual period: %dns\n", pwm_config->best_period_ns); + pr_debug("Actual period: %lluns\n", pwm_config->best_period_ns); } -static void __qpnp_lpg_calc_pwm_duty(int period_ns, int duty_ns, +static void __qpnp_lpg_calc_pwm_duty(u64 period_ns, u64 duty_ns, struct lpg_pwm_config *pwm_config) { u16 pwm_value, max_pwm_value; + u64 tmp; - if ((1 << pwm_config->pwm_size) > (INT_MAX / duty_ns)) - pwm_value = duty_ns / (period_ns >> pwm_config->pwm_size); - else - pwm_value = (duty_ns << pwm_config->pwm_size) / period_ns; + tmp = (u64)duty_ns << pwm_config->pwm_size; + pwm_value = (u16)div64_u64(tmp, period_ns); max_pwm_value = (1 << pwm_config->pwm_size) - 1; if (pwm_value > max_pwm_value) @@ -828,20 +825,13 @@ static void __qpnp_lpg_calc_pwm_duty(int period_ns, int duty_ns, pwm_config->pwm_value = pwm_value; } -static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, - struct pwm_device *pwm, int duty_ns, int period_ns) +static int qpnp_lpg_config(struct qpnp_lpg_channel *lpg, + u64 duty_ns, u64 period_ns) { - struct qpnp_lpg_channel *lpg; - int rc = 0; - - lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); - if (lpg == NULL) { - dev_err(pwm_chip->dev, "lpg not found\n"); - return -ENODEV; - } + int rc; if (duty_ns > period_ns) { - dev_err(pwm_chip->dev, "Duty %dns is larger than period %dns\n", + dev_err(lpg->chip->dev, "Duty %lluns is larger than period %lluns\n", duty_ns, period_ns); return -EINVAL; } @@ -855,7 +845,7 @@ static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, lpg->ramp_config.pattern, lpg->ramp_config.pattern_length); if (rc < 0) { - dev_err(pwm_chip->dev, "set LUT pattern failed for LPG%d, rc=%d\n", + dev_err(lpg->chip->dev, "set LUT pattern failed for LPG%d, rc=%d\n", lpg->lpg_idx, rc); return rc; } @@ -869,7 +859,7 @@ static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, rc = qpnp_lpg_set_pwm_config(lpg); if (rc < 0) { - dev_err(pwm_chip->dev, "Config PWM failed for channel %d, rc=%d\n", + dev_err(lpg->chip->dev, "Config PWM failed for channel %d, rc=%d\n", lpg->lpg_idx, rc); return rc; } @@ -880,6 +870,34 @@ static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, return rc; } +static int qpnp_lpg_pwm_config(struct pwm_chip *pwm_chip, + struct pwm_device *pwm, int duty_ns, int period_ns) +{ + struct qpnp_lpg_channel *lpg; + + lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); + if (lpg == NULL) { + dev_err(pwm_chip->dev, "lpg not found\n"); + return -ENODEV; + } + + return qpnp_lpg_config(lpg, (u64)duty_ns, (u64)period_ns); +} + +static int qpnp_lpg_pwm_config_extend(struct pwm_chip *pwm_chip, + struct pwm_device *pwm, u64 duty_ns, u64 period_ns) +{ + struct qpnp_lpg_channel *lpg; + + lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); + if (lpg == NULL) { + dev_err(pwm_chip->dev, "lpg not found\n"); + return -ENODEV; + } + + return qpnp_lpg_config(lpg, duty_ns, period_ns); +} + static int qpnp_lpg_pbs_trigger_enable(struct qpnp_lpg_channel *lpg, bool en) { struct qpnp_lpg_chip *chip = lpg->chip; @@ -1065,8 +1083,9 @@ static int qpnp_lpg_pwm_set_output_pattern(struct pwm_chip *pwm_chip, struct pwm_device *pwm, struct pwm_output_pattern *output_pattern) { struct qpnp_lpg_channel *lpg; - int rc = 0, i, period_ns, duty_ns; + u64 period_ns, duty_ns, tmp; u32 *percentages; + int rc = 0, i; lpg = pwm_dev_to_qpnp_lpg(pwm_chip, pwm); if (lpg == NULL) { @@ -1086,19 +1105,17 @@ static int qpnp_lpg_pwm_set_output_pattern(struct pwm_chip *pwm_chip, if (!percentages) return -ENOMEM; - period_ns = pwm_get_period(pwm); + period_ns = pwm_get_period_extend(pwm); for (i = 0; i < output_pattern->num_entries; i++) { duty_ns = output_pattern->duty_pattern[i]; if (duty_ns > period_ns) { - dev_err(lpg->chip->dev, "duty %dns is larger than period %dns\n", + dev_err(lpg->chip->dev, "duty %lluns is larger than period %lluns\n", duty_ns, period_ns); goto err; } /* Translate the pattern in duty_ns to percentage */ - if ((INT_MAX / duty_ns) < 100) - percentages[i] = duty_ns / (period_ns / 100); - else - percentages[i] = (duty_ns * 100) / period_ns; + tmp = (u64)duty_ns * 100; + percentages[i] = (u32)div64_u64(tmp, period_ns); } rc = qpnp_lpg_set_lut_pattern(lpg, percentages, @@ -1114,12 +1131,10 @@ static int qpnp_lpg_pwm_set_output_pattern(struct pwm_chip *pwm_chip, output_pattern->num_entries); lpg->ramp_config.hi_idx = lpg->ramp_config.lo_idx + output_pattern->num_entries - 1; - if ((INT_MAX / period_ns) > output_pattern->cycles_per_duty) - lpg->ramp_config.step_ms = output_pattern->cycles_per_duty * - period_ns / NSEC_PER_MSEC; - else - lpg->ramp_config.step_ms = (period_ns / NSEC_PER_MSEC) * - output_pattern->cycles_per_duty; + + tmp = (u64)output_pattern->cycles_per_duty * period_ns; + do_div(tmp, NSEC_PER_MSEC); + lpg->ramp_config.step_ms = (u16)tmp; rc = qpnp_lpg_set_ramp_config(lpg); if (rc < 0) @@ -1241,8 +1256,8 @@ static void qpnp_lpg_pwm_dbg_show(struct pwm_chip *pwm_chip, struct seq_file *s) seq_printf(s, " prediv = %d\n", cfg->prediv); seq_printf(s, " exponent = %d\n", cfg->clk_exp); seq_printf(s, " pwm_value = %d\n", cfg->pwm_value); - seq_printf(s, " Requested period: %dns, best period = %dns\n", - pwm_get_period(pwm), cfg->best_period_ns); + seq_printf(s, " Requested period: %lluns, best period = %lluns\n", + pwm_get_period_extend(pwm), cfg->best_period_ns); ramp = &lpg->ramp_config; if (pwm_get_output_type(pwm) == PWM_OUTPUT_MODULATED) { @@ -1273,6 +1288,7 @@ static void qpnp_lpg_pwm_dbg_show(struct pwm_chip *pwm_chip, struct seq_file *s) static const struct pwm_ops qpnp_lpg_pwm_ops = { .config = qpnp_lpg_pwm_config, + .config_extend = qpnp_lpg_pwm_config_extend, .get_output_type_supported = qpnp_lpg_pwm_output_types_supported, .set_output_type = qpnp_lpg_pwm_set_output_type, .set_output_pattern = qpnp_lpg_pwm_set_output_pattern, diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index ea2b53d17199..50b7a3b278c1 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -50,7 +50,7 @@ static ssize_t period_show(struct device *child, pwm_get_state(pwm, &state); - return sprintf(buf, "%u\n", state.period); + return sprintf(buf, "%llu\n", state.period); } static ssize_t period_store(struct device *child, @@ -85,7 +85,7 @@ static ssize_t duty_cycle_show(struct device *child, pwm_get_state(pwm, &state); - return sprintf(buf, "%u\n", state.duty_cycle); + return sprintf(buf, "%llu\n", state.duty_cycle); } static ssize_t duty_cycle_store(struct device *child, @@ -220,7 +220,7 @@ static ssize_t capture_show(struct device *child, if (ret) return ret; - return sprintf(buf, "%u %u\n", result.period, result.duty_cycle); + return sprintf(buf, "%llu %llu\n", result.period, result.duty_cycle); } static ssize_t output_type_show(struct device *child, diff --git a/drivers/scsi/ufs/ufs-qcom-ice.c b/drivers/scsi/ufs/ufs-qcom-ice.c index d4fe6eede3b4..a2b725706667 100644 --- a/drivers/scsi/ufs/ufs-qcom-ice.c +++ b/drivers/scsi/ufs/ufs-qcom-ice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * 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 @@ -226,14 +226,17 @@ int ufs_qcom_ice_init(struct ufs_qcom_host *qcom_host) } qcom_host->dbg_print_en |= UFS_QCOM_ICE_DEFAULT_DBG_PRINT_EN; - ice_workqueue = alloc_workqueue("ice-set-key", - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); if (!ice_workqueue) { - dev_err(ufs_dev, "%s: workqueue allocation failed.\n", + ice_workqueue = alloc_workqueue("ice-set-key", + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!ice_workqueue) { + dev_err(ufs_dev, "%s: workqueue allocation failed.\n", __func__); - goto out; + err = -ENOMEM; + goto out; + } + INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work); } - INIT_WORK(&qcom_host->ice_cfg_work, ufs_qcom_ice_cfg_work); out: return err; @@ -286,6 +289,17 @@ int ufs_qcom_ice_req_setup(struct ufs_qcom_host *qcom_host, * propagate so it will be re-queued. */ if (err == -EAGAIN) { + if (!ice_workqueue) { + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + dev_err(qcom_host->hba->dev, + "%s: error %d workqueue NULL\n", + __func__, err); + return -EINVAL; + } + dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", __func__); @@ -405,6 +419,16 @@ int ufs_qcom_ice_cfg_start(struct ufs_qcom_host *qcom_host, * propagate so it will be re-queued. */ if (err == -EAGAIN) { + if (!ice_workqueue) { + spin_unlock_irqrestore( + &qcom_host->ice_work_lock, + flags); + + dev_err(qcom_host->hba->dev, + "%s: error %d workqueue NULL\n", + __func__, err); + return -EINVAL; + } dev_dbg(qcom_host->hba->dev, "%s: scheduling task for ice setup\n", diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index a44c988ae8ce..1167c45e3b59 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2018, Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1308,11 +1308,11 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) /* * If we are here to disable this clock it might be immediately * after entering into hibern8 in which case we need to make - * sure that device ref_clk is active at least 1us after the - * hibern8 enter. + * sure that device ref_clk is active for a given time after the + * hibern8 enter for pre UFS3.0 devices */ if (!enable) - udelay(1); + udelay(host->hba->dev_ref_clk_gating_wait); writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio); @@ -1321,11 +1321,16 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) /* * If we call hibern8 exit after this, we need to make sure that - * device ref_clk is stable for at least 1us before the hibern8 + * device ref_clk is stable for a given time before the hibern8 * exit command. */ - if (enable) - udelay(1); + if (enable) { + if (host->hba->dev_info.quirks & + UFS_DEVICE_QUIRK_WAIT_AFTER_REF_CLK_UNGATE) + usleep_range(50, 60); + else + udelay(1); + } host->is_dev_ref_clk_enabled = enable; } diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h index 0ae51b9b81fa..9dd8f951e67b 100644 --- a/drivers/scsi/ufs/ufs.h +++ b/drivers/scsi/ufs/ufs.h @@ -505,6 +505,7 @@ struct ufs_dev_info { u8 b_device_sub_class; u16 w_manufacturer_id; u8 i_product_name; + u16 w_spec_version; /* query flags */ bool f_power_on_wp_en; diff --git a/drivers/scsi/ufs/ufs_quirks.c b/drivers/scsi/ufs/ufs_quirks.c index a2b98fbc2b84..a12c651295f3 100644 --- a/drivers/scsi/ufs/ufs_quirks.c +++ b/drivers/scsi/ufs/ufs_quirks.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-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 @@ -28,6 +28,8 @@ static struct ufs_card_fix ufs_fixups[] = { UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), + UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_WAIT_AFTER_REF_CLK_UNGATE), UFS_FIX(UFS_VENDOR_SKHYNIX, "hB8aL1", UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8aL1", diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index 0fa7d93727bd..9d1343987ebf 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -138,6 +138,13 @@ struct ufs_card_fix { */ #define UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH (1 << 8) +/* + * Some UFS devices need more delay after device reference clk is turned on + * but before initiation of the state transition to STALL from a LS-MODE or + * from the HIBERN8 state. Enable this quirk to give UFS devices 50us delay + * instead of the default delay. + */ +#define UFS_DEVICE_QUIRK_WAIT_AFTER_REF_CLK_UNGATE (1 << 9) struct ufs_hba; void ufs_advertise_fixup_device(struct ufs_hba *hba); diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d70fc6bb9d72..cd7c68fbc387 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -244,6 +244,9 @@ static void ufshcd_update_uic_error_cnt(struct ufs_hba *hba, u32 reg, int type) /* default value of auto suspend is 3 seconds */ #define UFSHCD_AUTO_SUSPEND_DELAY_MS 3000 /* millisecs */ +/* default value of ref clock gating wait time is 100 micro seconds */ +#define UFSHCD_REF_CLK_GATING_WAIT_US 100 /* microsecs */ + #define UFSHCD_CLK_GATING_DELAY_MS_PWR_SAVE 10 #define UFSHCD_CLK_GATING_DELAY_MS_PERF 50 @@ -3445,18 +3448,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, int tag; struct completion wait; unsigned long flags; - bool has_read_lock = false; - - /* - * May get invoked from shutdown and IOCTL contexts. - * In shutdown context, it comes in with lock acquired. - * In error recovery context, it may come with lock acquired. - */ - - if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { - down_read(&hba->lock); - has_read_lock = true; - } /* * Get free slot, sleep if slots are unavailable. @@ -3489,8 +3480,6 @@ static int ufshcd_exec_dev_cmd(struct ufs_hba *hba, out_put_tag: ufshcd_put_dev_cmd_tag(hba, tag); wake_up(&hba->dev_cmd.tag_wq); - if (has_read_lock) - up_read(&hba->lock); return err; } @@ -3565,10 +3554,15 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, struct ufs_query_res *response = NULL; int err, index = 0, selector = 0; int timeout = QUERY_REQ_TIMEOUT; + bool has_read_lock = false; BUG_ON(!hba); ufshcd_hold_all(hba); + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3612,6 +3606,8 @@ int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); ufshcd_release_all(hba); return err; } @@ -3634,6 +3630,7 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, struct ufs_query_req *request = NULL; struct ufs_query_res *response = NULL; int err; + bool has_read_lock = false; BUG_ON(!hba); @@ -3645,6 +3642,16 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, goto out; } + /* + * May get invoked from shutdown and IOCTL contexts. + * In shutdown context, it comes in with lock acquired. + * In error recovery context, it may come with lock acquired. + */ + + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3677,6 +3684,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, out_unlock: mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); out: ufshcd_release_all(hba); return err; @@ -3727,6 +3736,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, struct ufs_query_req *request = NULL; struct ufs_query_res *response = NULL; int err; + bool has_read_lock = false; BUG_ON(!hba); @@ -3745,6 +3755,10 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, goto out; } + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); ufshcd_init_query(hba, &request, &response, opcode, idn, index, selector); @@ -3780,6 +3794,9 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, out_unlock: mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); + out: ufshcd_release_all(hba); return err; @@ -5301,8 +5318,13 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba) { int err = 0; int retries; + bool has_read_lock = false; ufshcd_hold_all(hba); + if (!ufshcd_is_shutdown_ongoing(hba) && !ufshcd_eh_in_progress(hba)) { + down_read(&hba->lock); + has_read_lock = true; + } mutex_lock(&hba->dev_cmd.lock); for (retries = NOP_OUT_RETRIES; retries > 0; retries--) { err = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_NOP, @@ -5314,6 +5336,8 @@ static int ufshcd_verify_dev_init(struct ufs_hba *hba) dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); } mutex_unlock(&hba->dev_cmd.lock); + if (has_read_lock) + up_read(&hba->lock); ufshcd_release_all(hba); if (err) @@ -7879,6 +7903,31 @@ out: return err; } +static int ufshcd_get_dev_ref_clk_gating_wait(struct ufs_hba *hba) +{ + int err = 0; + u32 gating_wait = UFSHCD_REF_CLK_GATING_WAIT_US; + + if (hba->dev_info.w_spec_version >= 0x300) { + err = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR, + QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME, 0, 0, + &gating_wait); + + if (err) + dev_err(hba->dev, "failed reading bRefClkGatingWait. err = %d, use default %uus\n", + err, gating_wait); + + if (gating_wait == 0) { + gating_wait = UFSHCD_REF_CLK_GATING_WAIT_US; + dev_err(hba->dev, "undefined ref clk gating wait time, use default %uus\n", + gating_wait); + } + } + + hba->dev_ref_clk_gating_wait = gating_wait; + return err; +} + static int ufs_read_device_desc_data(struct ufs_hba *hba) { int err = 0; @@ -7907,6 +7956,10 @@ static int ufs_read_device_desc_data(struct ufs_hba *hba) hba->dev_info.b_device_sub_class = desc_buf[DEVICE_DESC_PARAM_DEVICE_SUB_CLASS]; hba->dev_info.i_product_name = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; + hba->dev_info.w_spec_version = + desc_buf[DEVICE_DESC_PARAM_SPEC_VER] << 8 | + desc_buf[DEVICE_DESC_PARAM_SPEC_VER + 1]; + out: kfree(desc_buf); return err; @@ -8017,6 +8070,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) "%s: Failed getting max supported power mode\n", __func__); } else { + ufshcd_get_dev_ref_clk_gating_wait(hba); /* * Set the right value to bRefClkFreq before attempting to * switch to HS gears. @@ -10252,12 +10306,9 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) * e.g. link_recovery. Hence, release the rw_sem * before hibern8. */ - up_write(&hba->lock); ret = ufshcd_uic_hibern8_enter(hba); - down_write(&hba->lock); if (ret) - /* link will be bad state so no need to scale_up_gear */ - return ret; + goto scale_up_gear; ufshcd_custom_cmd_log(hba, "Hibern8-entered"); } @@ -10269,8 +10320,7 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) if (ufshcd_is_auto_hibern8_supported(hba)) { ret = ufshcd_uic_hibern8_exit(hba); if (ret) - /* link will be bad state so no need to scale_up_gear */ - return ret; + goto scale_up_gear; ufshcd_custom_cmd_log(hba, "Hibern8-Exited"); } diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 6e329c0c391d..0931eeedbcb0 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -3,7 +3,7 @@ * * This code is based on drivers/scsi/ufs/ufshcd.h * Copyright (C) 2011-2013 Samsung India Software Operations - * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * Authors: * Santosh Yaraganavi <santosh.sy@samsung.com> @@ -808,6 +808,7 @@ struct ufs_hba { unsigned int irq; bool is_irq_enabled; + u32 dev_ref_clk_gating_wait; u32 dev_ref_clk_freq; /* Interrupt aggregation support is broken */ diff --git a/drivers/slimbus/slim-msm-ngd.c b/drivers/slimbus/slim-msm-ngd.c index 34be2301be20..44f34cf4227e 100644 --- a/drivers/slimbus/slim-msm-ngd.c +++ b/drivers/slimbus/slim-msm-ngd.c @@ -2083,7 +2083,7 @@ static int ngd_slim_runtime_suspend(struct device *device) #ifdef CONFIG_PM_SLEEP static int ngd_slim_suspend(struct device *dev) { - int ret = -EBUSY; + int ret = 0; struct platform_device *pdev = to_platform_device(dev); struct msm_slim_ctrl *cdev; @@ -2092,6 +2092,13 @@ static int ngd_slim_suspend(struct device *dev) return 0; cdev = platform_get_drvdata(pdev); + + if (cdev->state == MSM_CTRL_AWAKE) { + ret = -EBUSY; + SLIM_INFO(cdev, "system suspend: %d\n", ret); + return ret; + + } if (!pm_runtime_enabled(dev) || (!pm_runtime_suspended(dev) && cdev->state == MSM_CTRL_IDLE)) { @@ -2109,17 +2116,6 @@ static int ngd_slim_suspend(struct device *dev) cdev->qmi.deferred_resp = false; } } - if (ret == -EBUSY) { - /* - * There is a possibility that some audio stream is active - * during suspend. We dont want to return suspend failure in - * that case so that display and relevant components can still - * go to suspend. - * If there is some other error, then it should be passed-on - * to system level suspend - */ - ret = 0; - } SLIM_INFO(cdev, "system suspend\n"); return ret; } diff --git a/drivers/soc/qcom/glink_spi_xprt.c b/drivers/soc/qcom/glink_spi_xprt.c index a08c4bfde4a2..efcd94cdda01 100644 --- a/drivers/soc/qcom/glink_spi_xprt.c +++ b/drivers/soc/qcom/glink_spi_xprt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* 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 @@ -484,6 +484,13 @@ static int glink_spi_xprt_rx_cmd(struct edge_info *einfo, void *dst, int ret; read_id = einfo->rx_fifo_read; + if ((read_id > (einfo->rx_fifo_start + einfo->fifo_size)) || + (read_id < einfo->rx_fifo_start)) { + pr_err("%s: Invalid rx_fifo_read: %d, start: %d, size: %d\n", + __func__, read_id, einfo->rx_fifo_start, + einfo->fifo_size); + return -EINVAL; + } do { if ((read_id + size_to_read) >= (einfo->rx_fifo_start + einfo->fifo_size)) @@ -722,11 +729,11 @@ static void process_rx_cmd(struct edge_info *einfo, struct rx_short_data_desc { unsigned char data[SHORT_PKT_SIZE]; }; - struct command *cmd; + struct command *cmd = NULL; struct intent_desc *intents; struct rx_desc *rx_descp; struct rx_short_data_desc *rx_sd_descp; - int offset = 0; + uint64_t offset = 0; int rcu_id; uint16_t rcid; uint16_t name_len; @@ -742,6 +749,8 @@ static void process_rx_cmd(struct edge_info *einfo, } while (offset < rx_size) { + if (offset + sizeof(*cmd) > rx_size) + goto err; cmd = (struct command *)(rx_data + offset); offset += sizeof(*cmd); switch (cmd->id) { @@ -760,7 +769,12 @@ static void process_rx_cmd(struct edge_info *einfo, case OPEN_CMD: rcid = cmd->param1; name_len = (uint16_t)(cmd->param2 & 0xFFFF); + if (name_len > GLINK_NAME_SIZE) + goto err; prio = (uint16_t)((cmd->param2 & 0xFFFF0000) >> 16); + if (offset + ALIGN(name_len, FIFO_ALIGNMENT) > + rx_size) + goto err; name = (char *)(rx_data + offset); offset += ALIGN(name_len, FIFO_ALIGNMENT); einfo->xprt_if.glink_core_if_ptr->rx_cmd_ch_remote_open( @@ -786,6 +800,8 @@ static void process_rx_cmd(struct edge_info *einfo, case RX_INTENT_CMD: for (i = 0; i < cmd->param2; i++) { + if (offset + sizeof(*intents) > rx_size) + goto err; intents = (struct intent_desc *) (rx_data + offset); offset += sizeof(*intents); @@ -821,6 +837,8 @@ static void process_rx_cmd(struct edge_info *einfo, case TX_DATA_CONT_CMD: case TRACER_PKT_CMD: case TRACER_PKT_CONT_CMD: + if (offset + sizeof(*rx_descp) > rx_size) + goto err; rx_descp = (struct rx_desc *)(rx_data + offset); offset += sizeof(*rx_descp); process_rx_data(einfo, cmd->id, cmd->param1, @@ -830,6 +848,8 @@ static void process_rx_cmd(struct edge_info *einfo, break; case TX_SHORT_DATA_CMD: + if (offset + sizeof(*rx_sd_descp) > rx_size) + goto err; rx_sd_descp = (struct rx_short_data_desc *) (rx_data + offset); offset += sizeof(*rx_sd_descp); @@ -858,6 +878,13 @@ static void process_rx_cmd(struct edge_info *einfo, } } srcu_read_unlock(&einfo->use_ref, rcu_id); + return; +err: + srcu_read_unlock(&einfo->use_ref, rcu_id); + if (cmd) + pr_err("%s: invalid size of rx_data: %d, cmd : %d\n", + __func__, rx_size, cmd->id); + return; } /** diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 15e10907c6ef..f3acd4113b06 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -76,6 +76,8 @@ module_param(qmi_timeout, ulong, 0600); #define ICNSS_MAX_PROBE_CNT 2 +#define PROBE_TIMEOUT 5000 + #define icnss_ipc_log_string(_x...) do { \ if (icnss_ipc_log_context) \ ipc_log_string(icnss_ipc_log_context, _x); \ @@ -286,6 +288,7 @@ enum icnss_driver_state { ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, ICNSS_MODE_ON, + ICNSS_BLOCK_SHUTDOWN, }; struct ce_irq_list { @@ -475,6 +478,7 @@ static struct icnss_priv { struct mutex dev_lock; uint32_t fw_error_fatal_irq; uint32_t fw_early_crash_irq; + struct completion unblock_shutdown; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -1164,6 +1168,21 @@ bool icnss_is_fw_ready(void) } EXPORT_SYMBOL(icnss_is_fw_ready); +void icnss_block_shutdown(bool status) +{ + if (!penv) + return; + + if (status) { + set_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + reinit_completion(&penv->unblock_shutdown); + } else { + clear_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + complete(&penv->unblock_shutdown); + } +} +EXPORT_SYMBOL(icnss_block_shutdown); + bool icnss_is_fw_down(void) { if (!penv) @@ -2256,6 +2275,7 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) icnss_hw_power_on(priv); + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = priv->ops->probe(&priv->pdev->dev); probe_cnt++; @@ -2265,9 +2285,11 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) if (ret < 0) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, priv->state, probe_cnt); + icnss_block_shutdown(false); goto out; } + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &priv->state); return 0; @@ -2406,6 +2428,7 @@ static int icnss_driver_event_register_driver(void *data) if (ret) goto out; + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = penv->ops->probe(&penv->pdev->dev); probe_cnt++; @@ -2415,9 +2438,11 @@ static int icnss_driver_event_register_driver(void *data) if (ret) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, penv->state, probe_cnt); + icnss_block_shutdown(false); goto power_off; } + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &penv->state); return 0; @@ -2436,9 +2461,14 @@ static int icnss_driver_event_unregister_driver(void *data) } set_bit(ICNSS_DRIVER_UNLOADING, &penv->state); + + icnss_block_shutdown(true); + if (penv->ops) penv->ops->remove(&penv->pdev->dev); + icnss_block_shutdown(false); + clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state); clear_bit(ICNSS_DRIVER_PROBED, &penv->state); @@ -2497,7 +2527,8 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, goto out; } - icnss_fw_crashed(priv, event_data); + if (!test_bit(ICNSS_PD_RESTART, &priv->state)) + icnss_fw_crashed(priv, event_data); out: kfree(data); @@ -2684,6 +2715,13 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && + test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { + if (!wait_for_completion_timeout(&priv->unblock_shutdown, + PROBE_TIMEOUT)) + icnss_pr_err("wlan driver probe timeout\n"); + } + if (test_bit(ICNSS_PDR_REGISTERED, &priv->state)) { set_bit(ICNSS_FW_DOWN, &priv->state); icnss_ignore_qmi_timeout(true); @@ -4049,6 +4087,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) continue; case ICNSS_MODE_ON: seq_puts(s, "MODE ON DONE"); + continue; + case ICNSS_BLOCK_SHUTDOWN: + seq_puts(s, "BLOCK SHUTDOWN"); } seq_printf(s, "UNKNOWN-%d", i); @@ -4720,6 +4761,8 @@ static int icnss_probe(struct platform_device *pdev) penv = priv; + init_completion(&priv->unblock_shutdown); + icnss_pr_info("Platform driver probed successfully\n"); return 0; @@ -4742,6 +4785,8 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); + complete_all(&penv->unblock_shutdown); + icnss_modem_ssr_unregister_notifier(penv); destroy_ramdump_device(penv->msa0_dump_dev); diff --git a/drivers/soc/qcom/pil-q6v5.c b/drivers/soc/qcom/pil-q6v5.c index d23b0506ef02..142a6cdfbf30 100644 --- a/drivers/soc/qcom/pil-q6v5.c +++ b/drivers/soc/qcom/pil-q6v5.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * 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 @@ -169,7 +169,7 @@ err_vreg_pll: err_cx_enable: regulator_set_load(drv->vreg_cx, 0); err_cx_mode: - regulator_set_voltage(drv->vreg_cx, 0, uv); + regulator_set_voltage(drv->vreg_cx, 0, INT_MAX); err_cx_voltage: clk_disable_unprepare(drv->axis2_clk); err_axis2_vote: @@ -203,7 +203,7 @@ void pil_q6v5_remove_proxy_votes(struct pil_desc *pil) } regulator_disable(drv->vreg_cx); regulator_set_load(drv->vreg_cx, 0); - regulator_set_voltage(drv->vreg_cx, 0, uv); + regulator_set_voltage(drv->vreg_cx, 0, INT_MAX); clk_disable_unprepare(drv->xo); clk_disable_unprepare(drv->pnoc_clk); clk_disable_unprepare(drv->qdss_clk); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index e78a49a011d7..cad75e76f1fe 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -602,8 +602,8 @@ static struct msm_soc_info cpu_of_id[] = { /* SDM710 ID */ [360] = {MSM_CPU_SDM710, "SDM710"}, - /* SDMNOBELIUM ID */ - [393] = {MSM_CPU_SDMNOBELIUM, "SDMNOBELIUM"}, + /* SDM712 ID */ + [393] = {MSM_CPU_SDM712, "SDM712"}, /* SXR1120 ID */ [370] = {MSM_CPU_SXR1120, "SXR1120"}, @@ -1560,9 +1560,9 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 360; strlcpy(dummy_socinfo.build_id, "sdm710 - ", sizeof(dummy_socinfo.build_id)); - } else if (early_machine_is_sdmnobelium()) { + } else if (early_machine_is_sdm712()) { dummy_socinfo.id = 393; - strlcpy(dummy_socinfo.build_id, "sdmnobelium - ", + strlcpy(dummy_socinfo.build_id, "sdm712 - ", sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_sda670()) { dummy_socinfo.id = 337; diff --git a/drivers/soc/qcom/subsys-pil-bg.c b/drivers/soc/qcom/subsys-pil-bg.c index 4f5e4d4f32c6..d1b5feadf989 100644 --- a/drivers/soc/qcom/subsys-pil-bg.c +++ b/drivers/soc/qcom/subsys-pil-bg.c @@ -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 @@ -303,6 +303,8 @@ static int bg_powerup(const struct subsys_desc *subsys) "%s: BG PIL Boot failed\n", __func__); return ret; } + /* wait for msm_gpio_irq_handler to get invoked before enable irq */ + usleep_range(5000, 6000); enable_irq(bg_data->status_irq); ret = wait_for_err_ready(bg_data); if (ret) { diff --git a/drivers/spmi/spmi-pmic-arb-debug.c b/drivers/spmi/spmi-pmic-arb-debug.c index 2c90bef1224f..48fe4e985ff5 100644 --- a/drivers/spmi/spmi-pmic-arb-debug.c +++ b/drivers/spmi/spmi-pmic-arb-debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * 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 @@ -365,17 +365,7 @@ static struct platform_driver spmi_pmic_arb_debug_driver = { }, }; -int __init spmi_pmic_arb_debug_init(void) -{ - return platform_driver_register(&spmi_pmic_arb_debug_driver); -} -arch_initcall(spmi_pmic_arb_debug_init); - -static void __exit spmi_pmic_arb_debug_exit(void) -{ - platform_driver_unregister(&spmi_pmic_arb_debug_driver); -} -module_exit(spmi_pmic_arb_debug_exit); +module_platform_driver(spmi_pmic_arb_debug_driver); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:spmi_pmic_arb_debug"); diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index f05471d3f4aa..b664f1686da3 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2019, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -275,6 +275,9 @@ static struct page_info *alloc_from_pool_preferred( struct page_info *info; int i; + if (buffer->flags & ION_FLAG_POOL_FORCE_ALLOC) + goto force_alloc; + info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; @@ -306,6 +309,7 @@ static struct page_info *alloc_from_pool_preferred( } kfree(info); +force_alloc: return alloc_largest_available(heap, buffer, size, max_order); } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index d9baac65bd0a..a866332b9e8e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -424,6 +424,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, dwc->ep0_usb_req.request.length = sizeof(*response_pkt); dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl; + dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } @@ -760,6 +761,7 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; dwc->ep0_usb_req.request.buf = dwc->setup_buf; dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; + dwc->ep0_usb_req.request.dma = DMA_ERROR_CODE; return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); } diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c index f8e44580df41..5344b42ee791 100644 --- a/drivers/video/fbdev/msm/mdp3.c +++ b/drivers/video/fbdev/msm/mdp3.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This software is licensed under the terms of the GNU General Public @@ -916,17 +916,6 @@ u64 mdp3_get_panic_lut_cfg(u32 panel_width) return panic_config; } -int mdp3_enable_panic_ctrl(void) -{ - int rc = 0; - - if (MDP3_REG_READ(MDP3_PANIC_ROBUST_CTRL) == 0) { - pr_err("%s: Enable Panic Control\n", __func__); - MDP3_REG_WRITE(MDP3_PANIC_ROBUST_CTRL, BIT(0)); - } - return rc; -} - int mdp3_qos_remapper_setup(struct mdss_panel_data *panel) { int rc = 0; diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h index 6b560521ec53..3ab4652d0c72 100644 --- a/drivers/video/fbdev/msm/mdp3.h +++ b/drivers/video/fbdev/msm/mdp3.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 2016-2019, The Linux Foundation. All rights reserved. * Copyright (C) 2007 Google Incorporated * * This program is free software; you can redistribute it and/or modify @@ -281,7 +281,6 @@ u64 mdp3_clk_round_off(u64 clk_rate); void mdp3_calc_dma_res(struct mdss_panel_info *panel_info, u64 *clk_rate, u64 *ab, u64 *ib, uint32_t bpp); void mdp3_clear_irq(u32 interrupt_mask); -int mdp3_enable_panic_ctrl(void); void mdss_spi_panel_bl_ctrl_update(struct mdss_panel_data *pdata, u32 bl_level); diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index ff7d7126df85..6e8cda0f1a8f 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -261,7 +261,8 @@ static void mdp3_vsync_retire_handle_vsync(void *arg) return; } - schedule_work(&mdp3_session->retire_work); + kthread_queue_work(&mdp3_session->retire_worker, + &mdp3_session->retire_work); } void mdp3_vsync_retire_signal(struct msm_fb_data_type *mfd, int val) @@ -282,7 +283,7 @@ void mdp3_vsync_retire_signal(struct msm_fb_data_type *mfd, int val) mutex_unlock(&mfd->mdp_sync_pt_data.sync_mutex); } -static void mdp3_vsync_retire_work_handler(struct work_struct *work) +static void mdp3_vsync_retire_work_handler(struct kthread_work *work) { struct mdp3_session_data *mdp3_session = container_of(work, struct mdp3_session_data, retire_work); @@ -954,14 +955,12 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd) mdp3_session->in_splash_screen) { /* Turn on panel so that it can exit low power mode */ mdp3_clk_enable(1, 0); - rc = panel->event_handler(panel, + rc = panel->event_handler(panel, MDSS_EVENT_LINK_READY, NULL); - rc |= panel->event_handler(panel, + rc |= panel->event_handler(panel, MDSS_EVENT_UNBLANK, NULL); - rc |= panel->event_handler(panel, + rc |= panel->event_handler(panel, MDSS_EVENT_PANEL_ON, NULL); - if (mdss_fb_is_power_on_lp(mfd)) - rc |= mdp3_enable_panic_ctrl(); mdp3_clk_enable(0, 0); } } @@ -2981,6 +2980,7 @@ static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd) struct mdp3_session_data *mdp3_session; struct mdp3_notification retire_client; char name[24]; + struct sched_param param = { .sched_priority = 16 }; mdp3_session = (struct mdp3_session_data *)mfd->mdp.private1; @@ -2998,7 +2998,20 @@ static int mdp3_vsync_retire_setup(struct msm_fb_data_type *mfd) if (mdp3_session->dma) mdp3_session->dma->retire_client = retire_client; - INIT_WORK(&mdp3_session->retire_work, mdp3_vsync_retire_work_handler); + kthread_init_worker(&mdp3_session->retire_worker); + kthread_init_work(&mdp3_session->retire_work, + mdp3_vsync_retire_work_handler); + + mdp3_session->retire_thread = kthread_run(kthread_worker_fn, + &mdp3_session->retire_worker, + "vsync_retire_work"); + if (IS_ERR(mdp3_session->retire_thread)) { + pr_err("unable to start vsync thread\n"); + mdp3_session->retire_thread = NULL; + return -ENOMEM; + } + + sched_setscheduler(mdp3_session->retire_thread, SCHED_FIFO, ¶m); return 0; } diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.h b/drivers/video/fbdev/msm/mdp3_ctrl.h index 032debe1aa85..07377a92981e 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.h +++ b/drivers/video/fbdev/msm/mdp3_ctrl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2014, 2016-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2014, 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 @@ -61,6 +61,10 @@ struct mdp3_session_data { struct kthread_worker worker; struct task_struct *thread; + struct kthread_work retire_work; + struct kthread_worker retire_worker; + struct task_struct *retire_thread; + atomic_t dma_done_cnt; int histo_status; struct mutex histo_lock; @@ -84,7 +88,6 @@ struct mdp3_session_data { /* For retire fence */ struct mdss_timeline *vsync_timeline; int retire_cnt; - struct work_struct retire_work; }; void mdp3_bufq_deinit(struct mdp3_buffer_queue *bufq, int client); diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 631c1ecd4f5c..87f85d5620d3 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -3005,7 +3005,7 @@ static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data, ret = mdss_wait_sync_fence(fences[i], wait_ms); - if (ret == -ETIME) { + if (ret == -ETIMEDOUT) { wait_jf = timeout - jiffies; wait_ms = jiffies_to_msecs(wait_jf); if (wait_jf < 0) @@ -3022,14 +3022,14 @@ static int __mdss_fb_wait_for_fence_sub(struct msm_sync_pt_data *sync_pt_data, MDSS_XLOG_TOUT_HANDLER("mdp"); ret = mdss_wait_sync_fence(fences[i], wait_ms); - if (ret == -ETIME) + if (ret == -ETIMEDOUT) break; } mdss_put_sync_fence(fences[i]); } if (ret < 0) { - pr_err("%s: sync_fence_wait failed! ret = %x\n", + pr_err("%s: sync_fence_wait failed! ret = %d\n", sync_pt_data->fence_name, ret); for (; i < fence_cnt; i++) mdss_put_sync_fence(fences[i]); diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 8c5f407c6510..1c70637e6191 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-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 @@ -3232,6 +3232,7 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state) struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; struct mdss_mdp_cmd_ctx *sctx = NULL; struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + struct mdss_panel_data *pdata; bool panel_off = false; bool turn_off_clocks = false; bool send_panel_events = false; @@ -3242,6 +3243,7 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state) return -ENODEV; } + pdata = ctl->panel_data; if (__mdss_mdp_cmd_is_panel_power_off(ctx)) { pr_debug("%s: panel already off\n", __func__); return 0; @@ -3278,7 +3280,8 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state) send_panel_events = true; if (mdss_panel_is_power_on_ulp(panel_power_state)) { turn_off_clocks = true; - } else if (atomic_read(&ctx->koff_cnt)) { + } else if (atomic_read(&ctx->koff_cnt) && + !pdata->panel_info.panel_dead) { /* * Transition from interactive to low power * Wait for kickoffs to finish diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e69ebe648a34..be3e1db832b5 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -456,17 +456,12 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) return inode; } -int proc_fill_super(struct super_block *s, void *data, int silent) +int proc_fill_super(struct super_block *s) { - struct pid_namespace *ns = get_pid_ns(s->s_fs_info); struct inode *root_inode; int ret; - if (!proc_parse_options(data, ns)) - return -EINVAL; - - /* User space would break if executables or devices appear on proc */ - s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV; + s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NODEV; s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index d8105cd8b01c..d8edf39e0c1d 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -213,7 +213,7 @@ extern const struct file_operations proc_reclaim_operations; extern void proc_init_inodecache(void); extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); -extern int proc_fill_super(struct super_block *, void *data, int flags); +extern int proc_fill_super(struct super_block *); extern void proc_entry_rundown(struct proc_dir_entry *); /* @@ -278,7 +278,6 @@ static inline void proc_tty_init(void) {} * root.c */ extern struct proc_dir_entry proc_root; -extern int proc_parse_options(char *options, struct pid_namespace *pid); extern void proc_self_init(void); extern int proc_remount(struct super_block *, int *, char *); diff --git a/fs/proc/root.c b/fs/proc/root.c index c2f5014d642d..1d68fcd9313f 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -23,6 +23,21 @@ #include "internal.h" +static int proc_test_super(struct super_block *sb, void *data) +{ + return sb->s_fs_info == data; +} + +static int proc_set_super(struct super_block *sb, void *data) +{ + int err = set_anon_super(sb, NULL); + if (!err) { + struct pid_namespace *ns = (struct pid_namespace *)data; + sb->s_fs_info = get_pid_ns(ns); + } + return err; +} + enum { Opt_gid, Opt_hidepid, Opt_err, }; @@ -33,7 +48,7 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; -int proc_parse_options(char *options, struct pid_namespace *pid) +static int proc_parse_options(char *options, struct pid_namespace *pid) { char *p; substring_t args[MAX_OPT_ARGS]; @@ -85,16 +100,45 @@ int proc_remount(struct super_block *sb, int *flags, char *data) static struct dentry *proc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { + int err; + struct super_block *sb; struct pid_namespace *ns; + char *options; if (flags & MS_KERNMOUNT) { - ns = data; - data = NULL; + ns = (struct pid_namespace *)data; + options = NULL; } else { ns = task_active_pid_ns(current); + options = data; + + /* Does the mounter have privilege over the pid namespace? */ + if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + } + + sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); + if (IS_ERR(sb)) + return ERR_CAST(sb); + + if (!proc_parse_options(options, ns)) { + deactivate_locked_super(sb); + return ERR_PTR(-EINVAL); + } + + if (!sb->s_root) { + err = proc_fill_super(sb); + if (err) { + deactivate_locked_super(sb); + return ERR_PTR(err); + } + + sb->s_flags |= MS_ACTIVE; + /* User space would break if executables appear on proc */ + sb->s_iflags |= SB_I_NOEXEC; } - return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super); + return dget(sb->s_root); } static void proc_kill_sb(struct super_block *sb) diff --git a/include/dt-bindings/clock/msm-clocks-hwio-8952.h b/include/dt-bindings/clock/msm-clocks-hwio-8952.h index cba5a864b1d2..a8483cb6ae98 100644 --- a/include/dt-bindings/clock/msm-clocks-hwio-8952.h +++ b/include/dt-bindings/clock/msm-clocks-hwio-8952.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2016, 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 @@ -294,7 +294,8 @@ #define dsi0_1phypll_source_val 3 /* byte1_clk & pclk1_clk */ #define dsi1_0phypll_source_val 3 /* byte0_clk & pclk0_clk */ #define dsi1_1phypll_source_val 1 /* byte1_clk & pclk1_clk */ - +#define gpll0_gfx_source_val 5 /* GPLL0 GFX on QM215 */ +#define gpll6_gfx_source_val 6 /* GPLL6 GFX on QM215 */ #define F(f, s, div, m, n) \ { \ diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 62f4fa8b4e50..5e9bb82c5618 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -66,6 +66,7 @@ #define DIAG_IOCTL_REGISTER_CALLBACK 37 #define DIAG_IOCTL_HDLC_TOGGLE 38 #define DIAG_IOCTL_QUERY_PD_LOGGING 39 +#define DIAG_IOCTL_QUERY_MD_PID 41 /* PC Tools IDs */ #define APQ8060_TOOLS_ID 4062 diff --git a/include/linux/hdcp_qseecom.h b/include/linux/hdcp_qseecom.h index 08f30a46726f..9d13f24a33d4 100644 --- a/include/linux/hdcp_qseecom.h +++ b/include/linux/hdcp_qseecom.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -215,6 +215,7 @@ struct hdcp_register_data { int hdcp_library_register(struct hdcp_register_data *data); void hdcp_library_deregister(void *phdcpcontext); bool hdcp1_check_if_supported_load_app(void); +void hdcp1_unload_app(void); int hdcp1_set_keys(uint32_t *aksv_msb, uint32_t *aksv_lsb); int hdcp1_set_enc(bool enable); #endif /* __HDCP_QSEECOM_H */ diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 325f649d77ff..377417200728 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -210,6 +210,7 @@ extern struct task_group root_task_group; .policy = SCHED_NORMAL, \ .cpus_allowed = CPU_MASK_ALL, \ .nr_cpus_allowed= NR_CPUS, \ + .cpus_requested = CPU_MASK_ALL, \ .mm = NULL, \ .active_mm = &init_mm, \ .restart_block = { \ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index d32e7b8c0b87..29dedd4eb1b1 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -497,8 +497,8 @@ struct perf_addr_filters_head { * enum perf_event_active_state - the states of a event */ enum perf_event_active_state { - PERF_EVENT_STATE_DEAD = -5, - PERF_EVENT_STATE_ZOMBIE = -4, + PERF_EVENT_STATE_DORMANT = -5, + PERF_EVENT_STATE_DEAD = -4, PERF_EVENT_STATE_EXIT = -3, PERF_EVENT_STATE_ERROR = -2, PERF_EVENT_STATE_OFF = -1, @@ -721,7 +721,13 @@ struct perf_event { /* Is this event shared with other events */ bool shared; - struct list_head zombie_entry; + + /* + * Entry into the list that holds the events whose CPUs + * are offline. These events will be installed once the + * CPU wakes up and will be removed from the list after that + */ + struct list_head dormant_event_entry; #endif /* CONFIG_PERF_EVENTS */ }; @@ -1401,9 +1407,11 @@ static struct device_attribute format_attr_##_name = __ATTR_RO(_name) #ifdef CONFIG_PERF_EVENTS int perf_event_init_cpu(unsigned int cpu); int perf_event_exit_cpu(unsigned int cpu); +int perf_event_restart_events(unsigned int cpu); #else #define perf_event_init_cpu NULL #define perf_event_exit_cpu NULL +#define perf_event_restart_events NULL #endif #endif /* _LINUX_PERF_EVENT_H */ diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 6c0168b0f44c..b40287e0ce16 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -38,7 +38,7 @@ enum pwm_polarity { * current PWM hardware state. */ struct pwm_args { - unsigned int period; + u64 period; enum pwm_polarity polarity; }; @@ -65,9 +65,9 @@ enum pwm_output_type { * @cycles_per_duty: number of PWM period cycles an entry stays at */ struct pwm_output_pattern { - unsigned int *duty_pattern; + u64 *duty_pattern; unsigned int num_entries; - unsigned int cycles_per_duty; + u64 cycles_per_duty; }; /* @@ -78,8 +78,8 @@ struct pwm_output_pattern { * @enabled: PWM enabled status */ struct pwm_state { - unsigned int period; - unsigned int duty_cycle; + u64 period; + u64 duty_cycle; enum pwm_polarity polarity; enum pwm_output_type output_type; struct pwm_output_pattern *output_pattern; @@ -135,12 +135,30 @@ static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period) pwm->state.period = period; } +static inline void pwm_set_period_extend(struct pwm_device *pwm, u64 period) +{ + if (pwm) + pwm->state.period = period; +} + static inline unsigned int pwm_get_period(const struct pwm_device *pwm) { struct pwm_state state; pwm_get_state(pwm, &state); + if (state.period > UINT_MAX) + pr_warn("PWM period %llu is truncated\n", state.period); + + return (unsigned int)state.period; +} + +static inline u64 pwm_get_period_extend(const struct pwm_device *pwm) +{ + struct pwm_state state; + + pwm_get_state(pwm, &state); + return state.period; } @@ -150,12 +168,30 @@ static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty) pwm->state.duty_cycle = duty; } +static inline void pwm_set_duty_cycle_extend(struct pwm_device *pwm, u64 duty) +{ + if (pwm) + pwm->state.duty_cycle = duty; +} + static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm) { struct pwm_state state; pwm_get_state(pwm, &state); + if (state.duty_cycle > UINT_MAX) + pr_warn("PWM duty cycle %llu is truncated\n", state.duty_cycle); + + return (unsigned int)state.duty_cycle; +} + +static inline u64 pwm_get_duty_cycle_extend(const struct pwm_device *pwm) +{ + struct pwm_state state; + + pwm_get_state(pwm, &state); + return state.duty_cycle; } @@ -287,6 +323,8 @@ pwm_set_relative_duty_cycle(struct pwm_state *state, unsigned int duty_cycle, * @request: optional hook for requesting a PWM * @free: optional hook for freeing a PWM * @config: configure duty cycles and period length for this PWM + * @config_extend: configure duty cycles and period length for this + * PWM with u64 data type * @set_polarity: configure the polarity of this PWM * @capture: capture and report PWM signal * @enable: enable PWM output toggling @@ -309,6 +347,8 @@ struct pwm_ops { void (*free)(struct pwm_chip *chip, struct pwm_device *pwm); int (*config)(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns); + int (*config_extend)(struct pwm_chip *chip, struct pwm_device *pwm, + u64 duty_ns, u64 period_ns); int (*set_polarity)(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity); int (*capture)(struct pwm_chip *chip, struct pwm_device *pwm, @@ -366,8 +406,8 @@ struct pwm_chip { * @duty_cycle: duty cycle of the PWM signal (in nanoseconds) */ struct pwm_capture { - unsigned int period; - unsigned int duty_cycle; + u64 period; + u64 duty_cycle; }; #if IS_ENABLED(CONFIG_PWM) @@ -421,6 +461,31 @@ static inline int pwm_config(struct pwm_device *pwm, int duty_ns, } /** + * pwm_config_extend() - change PWM period and duty length with u64 data type + * @pwm: PWM device + * @duty_ns: "on" time (in nanoseconds) + * @period_ns: duration (in nanoseconds) of one cycle + * + * Returns: 0 on success or a negative error code on failure. + */ +static inline int pwm_config_extend(struct pwm_device *pwm, u64 duty_ns, + u64 period_ns) +{ + struct pwm_state state; + + if (!pwm) + return -EINVAL; + + pwm_get_state(pwm, &state); + if (state.duty_cycle == duty_ns && state.period == period_ns) + return 0; + + state.duty_cycle = duty_ns; + state.period = period_ns; + return pwm_apply_state(pwm, &state); +} + +/** * pwm_set_polarity() - configure the polarity of a PWM signal * @pwm: PWM device * @polarity: new polarity of the PWM signal diff --git a/include/linux/sched.h b/include/linux/sched.h index 009ed0a7d4c7..e11e0232b25e 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1803,6 +1803,7 @@ struct task_struct { unsigned int policy; int nr_cpus_allowed; cpumask_t cpus_allowed; + cpumask_t cpus_requested; #ifdef CONFIG_PREEMPT_RCU int rcu_read_lock_nesting; diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 7ef3db418100..0732a6fd33d1 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* 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 @@ -144,4 +144,5 @@ extern bool icnss_is_fw_ready(void); extern bool icnss_is_fw_down(void); extern bool icnss_is_rejuvenate(void); extern int icnss_trigger_recovery(struct device *dev); +extern void icnss_block_shutdown(bool status); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index c7dcf366ef01..862153eae123 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2009-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 @@ -114,7 +114,7 @@ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sxr1120") #define early_machine_is_msm8953() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8953") -#define early_machine_is_sdmnobelium() \ +#define early_machine_is_sdm712() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm670") #define early_machine_is_msm8937() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,msm8937") @@ -201,7 +201,7 @@ #define early_machine_is_sda429() 0 #define early_machine_is_mdm9650() 0 #define early_machine_is_qm215() 0 -#define early_machine_is_sdmnobelium() 0 +#define early_machine_is_sdm712() 0 #endif #define PLATFORM_SUBTYPE_MDM 1 @@ -279,7 +279,7 @@ enum msm_cpu { MSM_CPU_8940, MSM_CPU_9607, MSM_CPU_SDM439, - MSM_CPU_SDMNOBELIUM, + MSM_CPU_SDM712, MSM_CPU_SDM429, MSM_CPU_SDA439, MSM_CPU_SDA429, diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index db433542860b..e69fe7ab5f96 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -163,7 +163,8 @@ struct cam_iommu_handle { #define CAM_FORMAT_PLAIN8_10_SWAP 43 #define CAM_FORMAT_YV12 44 #define CAM_FORMAT_Y_ONLY 45 -#define CAM_FORMAT_MAX 46 +#define CAM_FORMAT_DPCM_12_10_12 46 +#define CAM_FORMAT_MAX 47 /* camera rotaion */ #define CAM_ROTATE_CW_0_DEGREE 0 diff --git a/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h index 2344b223ec0d..91360e240b49 100644 --- a/include/uapi/media/cam_isp.h +++ b/include/uapi/media/cam_isp.h @@ -89,6 +89,7 @@ #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 /* Query devices */ /** @@ -386,6 +387,44 @@ struct cam_isp_bw_config { struct cam_isp_bw_vote rdi_vote[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 */ diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h index b806befa2bed..7e9ba62c507f 100644 --- a/include/uapi/media/cam_isp_ife.h +++ b/include/uapi/media/cam_isp_ife.h @@ -27,7 +27,8 @@ #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_MAX (CAM_ISP_IFE_OUT_RES_BASE + 23) +#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 @@ -37,6 +38,7 @@ #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_MAX (CAM_ISP_IFE_IN_RES_BASE + 5) +#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_req_mgr.h b/include/uapi/media/cam_req_mgr.h index 0b4f1cc40df3..b903078dccbd 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -383,10 +383,12 @@ struct cam_mem_cache_ops_cmd { * @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 diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h index cd82b760bd92..e6a91030309f 100644 --- a/include/uapi/scsi/ufs/ufs.h +++ b/include/uapi/scsi/ufs/ufs.h @@ -36,8 +36,12 @@ enum attr_idn { QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F, QUERY_ATTR_IDN_CNTX_CONF = 0x10, QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11, + QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME = 0x17, }; +#define QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME \ + QUERY_ATTR_IDN_REF_CLK_GATING_WAIT_TIME + #define QUERY_ATTR_IDN_BOOT_LU_EN_MAX 0x02 /* Descriptor idn for Query requests */ diff --git a/kernel/cpu.c b/kernel/cpu.c index aa035154bb72..df007c474778 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -1463,7 +1463,7 @@ static struct cpuhp_step cpuhp_ap_states[] = { }, [CPUHP_AP_PERF_ONLINE] = { .name = "perf:online", - .startup.single = perf_event_init_cpu, + .startup.single = perf_event_restart_events, .teardown.single = perf_event_exit_cpu, }, [CPUHP_AP_WORKQUEUE_ONLINE] = { diff --git a/kernel/cpuset.c b/kernel/cpuset.c index af9159a3bc9b..2714a17c80a9 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -847,6 +847,20 @@ void rebuild_sched_domains(void) put_online_cpus(); } +static int update_cpus_allowed(struct cpuset *cs, struct task_struct *p, + const struct cpumask *new_mask) +{ + int ret; + + if (cpumask_subset(&p->cpus_requested, cs->cpus_requested)) { + ret = set_cpus_allowed_ptr(p, &p->cpus_requested); + if (!ret) + return ret; + } + + return set_cpus_allowed_ptr(p, new_mask); +} + /** * update_tasks_cpumask - Update the cpumasks of tasks in the cpuset. * @cs: the cpuset in which each task's cpus_allowed mask needs to be changed @@ -862,7 +876,7 @@ static void update_tasks_cpumask(struct cpuset *cs) css_task_iter_start(&cs->css, &it); while ((task = css_task_iter_next(&it))) - set_cpus_allowed_ptr(task, cs->effective_cpus); + update_cpus_allowed(cs, task, cs->effective_cpus); css_task_iter_end(&it); } @@ -1545,7 +1559,7 @@ static void cpuset_attach(struct cgroup_taskset *tset) * can_attach beforehand should guarantee that this doesn't * fail. TODO: have a better way to handle failure here */ - WARN_ON_ONCE(set_cpus_allowed_ptr(task, cpus_attach)); + WARN_ON_ONCE(update_cpus_allowed(cs, task, cpus_attach)); cpuset_change_task_nodemask(task, &cpuset_attach_nodemask_to); cpuset_update_task_spread_flag(cs, task); diff --git a/kernel/events/core.c b/kernel/events/core.c index 6be8ea2fb116..8dd675001654 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2315,6 +2315,23 @@ static void ctx_resched(struct perf_cpu_context *cpuctx, perf_pmu_enable(cpuctx->ctx.pmu); } +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE +static LIST_HEAD(dormant_event_list); +static DEFINE_SPINLOCK(dormant_event_list_lock); + +static void perf_prepare_install_in_context(struct perf_event *event) +{ + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) + goto out; + + event->state = PERF_EVENT_STATE_DORMANT; + list_add_tail(&event->dormant_event_entry, &dormant_event_list); +out: + spin_unlock(&dormant_event_list_lock); +} +#endif + /* * Cross CPU call to install and enable a performance event * @@ -2460,6 +2477,34 @@ again: raw_spin_unlock_irq(&ctx->lock); } +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE +static void perf_deferred_install_in_context(int cpu) +{ + struct perf_event *event, *tmp; + struct perf_event_context *ctx; + + spin_lock(&dormant_event_list_lock); + list_for_each_entry_safe(event, tmp, &dormant_event_list, + dormant_event_entry) { + if (cpu != event->cpu) + continue; + + list_del(&event->dormant_event_entry); + event->state = PERF_EVENT_STATE_INACTIVE; + spin_unlock(&dormant_event_list_lock); + + ctx = event->ctx; + + mutex_lock(&ctx->mutex); + perf_install_in_context(ctx, event, cpu); + mutex_unlock(&ctx->mutex); + + spin_lock(&dormant_event_list_lock); + } + spin_unlock(&dormant_event_list_lock); +} +#endif + /* * Put a event into inactive state and update time fields. * Enabling the leader of a group effectively enables all @@ -4277,14 +4322,6 @@ static void put_event(struct perf_event *event) } /* - * Maintain a zombie list to collect all the zombie events - */ -#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE -static LIST_HEAD(zombie_list); -static DEFINE_SPINLOCK(zombie_list_lock); -#endif - -/* * Kill an event dead; while event:refcount will preserve the event * object, it will not preserve its functionality. Once the last 'user' * gives up the object, we'll destroy the thing. @@ -4294,23 +4331,12 @@ static int __perf_event_release_kernel(struct perf_event *event) struct perf_event_context *ctx = event->ctx; struct perf_event *child, *tmp; - /* - * If the cpu associated to this event is offline, set the event as a - * zombie event. The cleanup of the cpu would be done if the CPU is - * back online. - */ #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE - if (event->cpu != -1 && per_cpu(is_hotplugging, event->cpu)) { - if (event->state == PERF_EVENT_STATE_ZOMBIE) - return 0; - - event->state = PERF_EVENT_STATE_ZOMBIE; - - spin_lock(&zombie_list_lock); - list_add_tail(&event->zombie_entry, &zombie_list); - spin_unlock(&zombie_list_lock); - - return 0; + if (event->cpu != -1) { + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) + list_del(&event->dormant_event_entry); + spin_unlock(&dormant_event_list_lock); } #endif @@ -4627,6 +4653,15 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct perf_event_context *ctx; int ret; +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) { + spin_unlock(&dormant_event_list_lock); + return 0; + } + spin_unlock(&dormant_event_list_lock); +#endif + ctx = perf_event_ctx_lock(event); ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); @@ -9455,13 +9490,13 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, mutex_init(&event->child_mutex); INIT_LIST_HEAD(&event->child_list); + INIT_LIST_HEAD(&event->dormant_event_entry); INIT_LIST_HEAD(&event->group_entry); INIT_LIST_HEAD(&event->event_entry); INIT_LIST_HEAD(&event->sibling_list); INIT_LIST_HEAD(&event->rb_entry); INIT_LIST_HEAD(&event->active_entry); INIT_LIST_HEAD(&event->addr_filters.list); - INIT_LIST_HEAD(&event->zombie_entry); INIT_HLIST_NODE(&event->hlist_entry); @@ -11114,111 +11149,27 @@ int perf_event_init_cpu(unsigned int cpu) } #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE -static void -check_hotplug_start_event(struct perf_event *event) -{ - if (event->pmu->events_across_hotplug && - event->attr.type == PERF_TYPE_SOFTWARE && - event->pmu->start) - event->pmu->start(event, 0); -} - -static void perf_event_zombie_cleanup(unsigned int cpu) +int perf_event_restart_events(unsigned int cpu) { - struct perf_event *event, *tmp; - - spin_lock(&zombie_list_lock); - - list_for_each_entry_safe(event, tmp, &zombie_list, zombie_entry) { - if (event->cpu != cpu) - continue; - - list_del(&event->zombie_entry); - spin_unlock(&zombie_list_lock); - - /* - * The detachment of the event with the - * PMU expects it to be in an active state - */ - event->state = PERF_EVENT_STATE_ACTIVE; - __perf_event_release_kernel(event); - - spin_lock(&zombie_list_lock); - } - - spin_unlock(&zombie_list_lock); -} - -static int perf_event_start_swevents(unsigned int cpu) -{ - struct perf_event_context *ctx; - struct pmu *pmu; - struct perf_event *event; - int idx; - mutex_lock(&pmus_lock); - perf_event_zombie_cleanup(cpu); - - idx = srcu_read_lock(&pmus_srcu); - list_for_each_entry_rcu(pmu, &pmus, entry) { - ctx = &per_cpu_ptr(pmu->pmu_cpu_context, cpu)->ctx; - mutex_lock(&ctx->mutex); - raw_spin_lock(&ctx->lock); - list_for_each_entry(event, &ctx->event_list, event_entry) - check_hotplug_start_event(event); - raw_spin_unlock(&ctx->lock); - mutex_unlock(&ctx->mutex); - } - srcu_read_unlock(&pmus_srcu, idx); per_cpu(is_hotplugging, cpu) = false; + perf_deferred_install_in_context(cpu); mutex_unlock(&pmus_lock); return 0; } -/* - * If keeping events across hotplugging is supported, do not - * remove the event list so event lives beyond CPU hotplug. - * The context is exited via an fd close path when userspace - * is done and the target CPU is online. If software clock - * event is active, then stop hrtimer associated with it. - * Start the timer when the CPU comes back online. - */ -static void -check_hotplug_remove_from_context(struct perf_event *event, - struct perf_cpu_context *cpuctx, - struct perf_event_context *ctx) -{ - if (event->pmu->events_across_hotplug && - event->attr.type == PERF_TYPE_SOFTWARE && - event->pmu->stop) - event->pmu->stop(event, PERF_EF_UPDATE); - else if (!event->pmu->events_across_hotplug) - __perf_remove_from_context(event, cpuctx, - ctx, (void *)DETACH_GROUP); -} - -static void __perf_event_exit_context(void *__info) -{ - struct perf_event_context *ctx = __info; - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx); - struct perf_event *event; - - raw_spin_lock(&ctx->lock); - list_for_each_entry(event, &ctx->event_list, event_entry) - check_hotplug_remove_from_context(event, cpuctx, ctx); - raw_spin_unlock(&ctx->lock); -} - static void perf_event_exit_cpu_context(int cpu) { struct perf_cpu_context *cpuctx; struct perf_event_context *ctx; unsigned long flags; + struct perf_event *event, *event_tmp; struct pmu *pmu; int idx; idx = srcu_read_lock(&pmus_srcu); + per_cpu(is_hotplugging, cpu) = true; list_for_each_entry_rcu(pmu, &pmus, entry) { cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); ctx = &cpuctx->ctx; @@ -11233,7 +11184,12 @@ static void perf_event_exit_cpu_context(int cpu) } mutex_lock(&ctx->mutex); - smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1); + list_for_each_entry_safe(event, event_tmp, &ctx->event_list, + event_entry) { + perf_remove_from_context(event, DETACH_GROUP); + if (event->pmu->events_across_hotplug) + perf_prepare_install_in_context(event); + } mutex_unlock(&ctx->mutex); } srcu_read_unlock(&pmus_srcu, idx); @@ -11246,8 +11202,8 @@ static void perf_event_exit_cpu_context(int cpu) { } int perf_event_exit_cpu(unsigned int cpu) { + mutex_lock(&pmus_lock); - per_cpu(is_hotplugging, cpu) = true; perf_event_exit_cpu_context(cpu); mutex_unlock(&pmus_lock); return 0; @@ -11292,25 +11248,6 @@ static struct notifier_block perf_event_idle_nb = { .notifier_call = event_idle_notif, }; -#ifdef CONFIG_HOTPLUG_CPU -static int perf_cpu_hp_init(void) -{ - int ret; - - ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ONLINE, - "PERF/CORE/CPUHP_AP_PERF_ONLINE", - perf_event_start_swevents, - perf_event_exit_cpu); - if (ret) - pr_err("CPU hotplug notifier for perf core could not be registered: %d\n", - ret); - - return ret; -} -#else -static int perf_cpu_hp_init(void) { return 0; } -#endif - void __init perf_event_init(void) { int ret, cpu; @@ -11337,8 +11274,6 @@ void __init perf_event_init(void) perf_event_init_cpu(smp_processor_id()); idle_notifier_register(&perf_event_idle_nb); register_reboot_notifier(&perf_reboot_notifier); - ret = perf_cpu_hp_init(); - WARN(ret, "core perf_cpu_hp_init() failed with: %d", ret); ret = init_hw_breakpoint(); WARN(ret, "hw_breakpoint initialization failed with: %d", ret); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f03942c9b2dc..e9bed0bd202d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -5019,6 +5019,9 @@ again: retval = -EINVAL; } + if (!retval && !(p->flags & PF_KTHREAD)) + cpumask_and(&p->cpus_requested, in_mask, cpu_possible_mask); + out_free_new_mask: free_cpumask_var(new_mask); out_free_cpus_allowed: @@ -8146,6 +8149,7 @@ void __init sched_init_smp(void) /* Move init over to a non-isolated CPU */ if (set_cpus_allowed_ptr(current, non_isolated_cpus) < 0) BUG(); + cpumask_copy(¤t->cpus_requested, cpu_possible_mask); sched_init_granularity(); free_cpumask_var(non_isolated_cpus); diff --git a/lib/qmi_encdec.c b/lib/qmi_encdec.c index d7221d898238..2808f7b72e3f 100644 --- a/lib/qmi_encdec.c +++ b/lib/qmi_encdec.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -706,8 +706,8 @@ static int qmi_decode_string_elem(struct elem_info *ei_array, void *buf_dst, decoded_bytes += rc; } - if (string_len > temp_ei->elem_len) { - pr_err("%s: String len %d > Max Len %d\n", + if (string_len >= temp_ei->elem_len) { + pr_err("%s: String len %d >= Max Len %d\n", __func__, string_len, temp_ei->elem_len); return -ETOOSMALL; } else if (string_len > tlv_len) { diff --git a/mm/memory.c b/mm/memory.c index ccf1a6b9f7e1..b8f1279e3728 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1971,7 +1971,7 @@ int apply_to_page_range(struct mm_struct *mm, unsigned long addr, unsigned long end = addr + size; int err; - if (WARN_ON(addr >= end)) + if (WARN_ON(addr >= end - 1)) return -EINVAL; pgd = pgd_offset(mm, addr); diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 7c1b14868313..8e471bec64c8 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -25,20 +25,20 @@ country AE: DFS-ETSI country AF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country AI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country AL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -49,8 +49,8 @@ country AM: DFS-ETSI country AN: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -73,8 +73,8 @@ country AS: DFS-FCC country AT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -92,8 +92,8 @@ country AU: DFS-FCC country AW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country AZ: DFS-ETSI @@ -103,8 +103,8 @@ country AZ: DFS-ETSI country BA: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -120,8 +120,8 @@ country BD: country BE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -136,8 +136,8 @@ country BF: DFS-FCC country BG: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -150,8 +150,8 @@ country BH: country BL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country BM: DFS-FCC @@ -192,14 +192,14 @@ country BS: DFS-FCC country BT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country BY: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country BZ: @@ -226,8 +226,8 @@ country CF: DFS-FCC country CH: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -280,8 +280,8 @@ country CX: DFS-FCC country CY: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -291,8 +291,8 @@ country CY: DFS-ETSI # and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf country CZ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -306,8 +306,8 @@ country CZ: DFS-ETSI country DE: DFS-ETSI # entries 279004 and 280006 (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -315,8 +315,8 @@ country DE: DFS-ETSI country DK: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -351,8 +351,8 @@ country EC: DFS-FCC country EE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -365,8 +365,8 @@ country EG: DFS-ETSI country ES: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -374,14 +374,14 @@ country ES: DFS-ETSI country ET: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country FI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -396,8 +396,8 @@ country FM: DFS-FCC country FR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -405,8 +405,8 @@ country FR: DFS-ETSI country GB: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -426,8 +426,8 @@ country GE: DFS-ETSI country GF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -440,26 +440,26 @@ country GH: DFS-FCC country GI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GP: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -467,8 +467,8 @@ country GR: DFS-ETSI country GT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country GU: DFS-FCC @@ -503,8 +503,8 @@ country HN: country HR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -519,8 +519,8 @@ country HT: DFS-FCC country HU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -533,8 +533,8 @@ country ID: country IE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -547,21 +547,23 @@ country IL: DFS-ETSI # 60 gHz band channels 1-4, base on Etsi En 302 567 (57000 - 66000 @ 2160), (40) -country IN: - (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (23) - (5735 - 5835 @ 80), (33) +country IN: DFS-ETSI + (2402 - 2482 @ 40), (30) + (5170 - 5250 @ 80), (30), AUTO-BW + (5250 - 5330 @ 80), (24), DFS, AUTO-BW + (5490 - 5730 @ 160), (24), DFS + (5735 - 5875 @ 80), (30) country IQ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country IS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -569,8 +571,8 @@ country IS: DFS-ETSI country IT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -593,10 +595,10 @@ country JO: (57000 - 66000 @ 2160), (40) country JP: DFS-JP - (2402 - 2482 @ 40), (20) + (2402 - 2482 @ 40), (23) (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR - (5250 - 5330 @ 80), (26), DFS, AUTO-BW, NO-OUTDOOR - (5490 - 5710 @ 160), (26), DFS + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR + (5490 - 5710 @ 160), (23), DFS # 60 gHz band channels 1-4 (57240 - 65880 @ 2160), (40) @@ -608,8 +610,8 @@ country KE: DFS-ETSI country KH: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country KN: DFS-FCC @@ -660,8 +662,8 @@ country LC: DFS-FCC country LI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -676,14 +678,14 @@ country LK: DFS-FCC country LS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country LT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -691,8 +693,8 @@ country LT: DFS-ETSI country LU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -700,8 +702,8 @@ country LU: DFS-ETSI country LV: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -716,29 +718,29 @@ country MA: DFS-ETSI country MC: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country MD: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country ME: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country MF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country MH: DFS-FCC @@ -750,8 +752,8 @@ country MH: DFS-FCC country MK: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -778,21 +780,21 @@ country MP: DFS-FCC country MQ: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) country MR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country MT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -800,8 +802,8 @@ country MT: DFS-ETSI country MU: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -813,8 +815,8 @@ country MV: DFS-ETSI country MW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country MX: DFS-FCC @@ -858,8 +860,8 @@ country NI: DFS-FCC country NL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -867,8 +869,8 @@ country NL: DFS-ETSI country NO: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -890,8 +892,8 @@ country NZ: DFS-FCC country OM: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country PA: @@ -910,8 +912,8 @@ country PE: DFS-FCC country PF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -937,8 +939,8 @@ country PK: country PL: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -946,8 +948,8 @@ country PL: DFS-ETSI country PM: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -967,8 +969,8 @@ country PS: DFS-FCC country PT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -999,14 +1001,14 @@ country QA: DFS-ETSI country RE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country RO: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1016,8 +1018,8 @@ country RO: DFS-ETSI # http://www.ratel.rs/upload/documents/Plan_namene/Plan_namene-sl_glasnik.pdf country RS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1047,8 +1049,8 @@ country SA: DFS-ETSI country SE: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1065,8 +1067,8 @@ country SG: DFS-FCC country SI: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1074,8 +1076,8 @@ country SI: DFS-ETSI country SK: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 @@ -1089,8 +1091,8 @@ country SN: country SR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country SV: DFS-FCC @@ -1108,14 +1110,14 @@ country TC: DFS-FCC country TD: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country TG: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS + (5170 - 5250 @ 40), (23), NO-OUTDOOR + (5250 - 5330 @ 40), (23), DFS, NO-OUTDOOR (5490 - 5710 @ 40), (30), DFS country TH: DFS-FCC @@ -1134,8 +1136,8 @@ country TN: DFS-ETSI country TR: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -1210,8 +1212,8 @@ country UZ: DFS-ETSI country VC: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) @@ -1246,14 +1248,14 @@ country VU: DFS-FCC country WF: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country WS: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 40), (23) - (5250 - 5330 @ 40), (23), DFS + (5170 - 5250 @ 40), (23), NO-OUTDOOR + (5250 - 5330 @ 40), (23), DFS, NO-OUTDOOR (5490 - 5710 @ 40), (30), DFS country XA: DFS-JP @@ -1268,8 +1270,8 @@ country YE: country YT: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS country ZA: DFS-FCC @@ -1283,6 +1285,6 @@ country ZA: DFS-FCC country ZW: DFS-ETSI (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (23), DFS, AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW, NO-OUTDOOR + (5250 - 5330 @ 80), (23), DFS, AUTO-BW, NO-OUTDOOR (5490 - 5710 @ 160), (30), DFS diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 0534378309ff..409662fdc74c 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2618,7 +2618,7 @@ sub process { $sig_nospace =~ s/\s//g; $sig_nospace = lc($sig_nospace); if (defined $signatures{$sig_nospace}) { - WARN("BAD_SIGN_OFF", + WARN("DUPLICATE_SIGN_OFF", "Duplicate signature\n" . $herecurr); } else { $signatures{$sig_nospace} = 1; diff --git a/scripts/gcc-wrapper.py b/scripts/gcc-wrapper.py index 8a0e0af1c39a..76fb91c57264 100755 --- a/scripts/gcc-wrapper.py +++ b/scripts/gcc-wrapper.py @@ -55,7 +55,7 @@ def interpret_warning(line): line = line.rstrip('\n') m = warning_re.match(line) if m and m.group(2) not in allowed_warnings: - print "error, forbidden warning:", m.group(2) + print >> sys.stderr, "error, forbidden warning:", m.group(2) # If there is a warning, remove any object if it exists. if ofile: @@ -80,17 +80,17 @@ def run_gcc(): try: proc = subprocess.Popen(args, stderr=subprocess.PIPE) for line in proc.stderr: - print line, + print >> sys.stderr, line, interpret_warning(line) result = proc.wait() except OSError as e: result = e.errno if result == errno.ENOENT: - print args[0] + ':',e.strerror - print 'Is your PATH set correctly?' + print >> sys.stderr, args[0] + ':',e.strerror + print >> sys.stderr, 'Is your PATH set correctly?' else: - print ' '.join(args), str(e) + print >> sys.stderr, ' '.join(args), str(e) return result |