diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt index b2640dab324d032b712c750a1ca663ee1dd644ef..74e90e64ee9d1d4329df01a024b78a507fd7a7a1 100644 --- a/Documentation/devicetree/bindings/arm/msm/msm.txt +++ b/Documentation/devicetree/bindings/arm/msm/msm.txt @@ -101,6 +101,9 @@ SoCs: - SDA670 compatible = "qcom,sda670" +- SXR1130 + compatible = "qcom,sxr1130" + - MSM8952 compatible = "qcom,msm8952" @@ -321,6 +324,8 @@ compatible = "qcom,sda845-mtp" compatible = "qcom,sda845-qrd" compatible = "qcom,sda845-hdk" compatible = "qcom,sda845-svr" +compatible = "qcom,sxr1130-cdp" +compatible = "qcom,sxr1130-mtp" compatible = "qcom,sdm670-rumi" compatible = "qcom,sdm670-cdp" compatible = "qcom,sdm670-mtp" diff --git a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt index 90bc36823a8312373d49f8e5065166b7270be073..c4ada7cfd15416ccf73218f2dcab4f363b343b0b 100644 --- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt +++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt @@ -86,7 +86,8 @@ Optional Properties: compatible devices: qcom,sdm845-llcc, - qcom,sdm670-llcc + qcom,sdm670-llcc, + qcom,qcs605-llcc Example: diff --git a/Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt new file mode 100644 index 0000000000000000000000000000000000000000..3fcaaad476c66fd34dd86d77354ffa31f8fccfc6 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/elants_i2c.txt @@ -0,0 +1,34 @@ +Elan Ektf3xx series touch controller + + Required properties: + + - compatible : Should be "elan,ekth3500" + - reg : I2C slave address of the device. + - interrupt-parent : Parent of interrupt. + - interrupts : Configuration of touch panel controller interrupt GPIO. + - elan,irq-gpio : Interrupt gpio which is to provide interrupts to + host, same as "interrupts" node.It will also contain + active low or active high information + + Optional properties: + + - vdd-supply : Power supply needed to power up the device, when use + external regulator, do not add this property. + - vccio-supply : Power source required to power up i2c bus. + Ekth3500 series can provide 1.8V from internal + LDO, add this properties base on hardware design. + - reset-gpio : Reset gpio to control the reset of chip. + + Example: + i2c@f9923000{ + elan_ktf@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + vdd-supply = <&pm8110_l19>; + vccio-supply = <&pm8110_l14>; + reset-gpio = <&msmgpio 0 GPIO_ACTIVE_LOW>; + interrupt-parent = <&msmgpio>; + interrupts = <1 0x2>; + elan,irq-gpio = <&tlmm 65 0x2008>;> + }; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt new file mode 100644 index 0000000000000000000000000000000000000000..ba61a2fcfa233a1d487beac3149240ab860baa82 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/git9xx/gt9xx.txt @@ -0,0 +1,99 @@ +Goodix GT9xx series touch controller + +Required properties: + + - compatible : Should be "goodix,gt9xx" + - reg : I2C slave address of the device. + - interrupt-parent : Parent of interrupt. + - interrupts : Configuration of touch panel controller interrupt + GPIO. + - goodix,product-id : Product identification of the controller. + - interrupt-gpios : Interrupt gpio which is to provide interrupts to + host, same as "interrupts" node. + - reset-gpios : Reset gpio to control the reset of chip. + - goodix,display-coords : Display coordinates in pixels. It is a four + tuple consisting of min x, min y, max x and + max y values. + +Optional properties: + + - avdd-supply : Power supply needed to power up the device, this is + for fixed voltage external regulator. + - vdd-supply : Power supply needed to power up the device, when use + external regulator, do not add this property. + - vcc-i2c-supply : Power source required to power up i2c bus. + GT9xx series can provide 1.8V from internal + LDO, add this properties base on hardware + design. + - goodix,panel-coords : Panel coordinates for the chip in pixels. + It is a four tuple consisting of min x, + min y, max x and max y values. + - goodix,i2c-pull-up : To specify pull up is required. + - goodix,force-update : To specify force update is allowed. + - goodix,enable-power-off : Power off touchscreen during suspend. + - goodix,button-map : Button map of key codes. The number of key codes + depend on panel. + - goodix,cfg-data0 : Touch screen controller config data group 0. Ask vendor + to provide that. + Driver supports maximum six config groups. If more than one + groups are defined, driver will select config group depending + on hardware configuration. If only config group 0 is defined, + it will be used for all hardware configurations. + Touch screen controller will use its onchip default config data + if this property is not present. + - goodix,cfg-data1 : Touch screen controller config data group 1. Ask vendor + to provide that. + - goodix,cfg-data2 : Touch screen controller config data group 2. Ask vendor + to provide that. + - goodix,cfg-data3 : Touch screen controller config data group 3. Ask vendor + to provide that. + - goodix,cfg-data4 : Touch screen controller config data group 4. Ask vendor + to provide that. + - goodix,cfg-data5 : Touch screen controller config data group 5. Ask vendor + to provide that. + - goodix,fw-name : Touch screen controller firmware file name. + - goodix,slide-wakeup : To specify slide-wakeup property is enabled or not. + - goodix,dbl-clk-wakeup : To specify dbl-clk-wakeup property is enabled or not. + - goodix,change-x2y : To specify change-x2y property is enabled or not. + - goodix,driver-send-cfg : To specify driver-send-cfg property is enabled or not. + - goodix,have-touch-key : To specify have-touch-key property is enabled or not. + - goodix,with-pen : To specify with-pen property is enabled or not. +Example: +i2c@f9927000 { + goodix@5d { + compatible = "goodix,gt9xx"; + reg = <0x5d>; + interrupt-parent = <&msmgpio>; + interrupts = <17 0x2008>; + reset-gpios = <&msmgpio 16 0x00>; + interrupt-gpios = <&msmgpio 17 0x00>; + avdd-supply = <&tp_power>; + goodix,panel-coords = <0 0 720 1200>; + goodix,display-coords = <0 0 720 1080>; + goodix,button-map= <158 102 139>; + goodix,product-id = "915"; + goodix,cfg-data0 = [ + 41 D0 02 00 05 0A 05 01 01 08 + 12 58 50 41 03 05 00 00 00 00 + 00 00 00 00 00 00 00 8C 2E 0E + 28 24 73 13 00 00 00 83 03 1D + 40 02 00 00 00 03 64 32 00 00 + 00 1A 38 94 C0 02 00 00 00 04 + 9E 1C 00 8D 20 00 7A 26 00 6D + 2C 00 60 34 00 60 10 38 68 00 + F0 50 35 FF FF 27 00 00 00 00 + 00 01 1B 14 0C 14 00 00 01 00 + 00 00 00 00 00 00 00 00 00 00 + 00 00 02 04 06 08 0A 0C 0E 10 + 12 14 16 18 1A 1C FF FF FF FF + FF FF FF FF FF FF FF FF FF FF + FF FF 00 02 04 06 08 0A 0C 0F + 10 12 13 14 16 18 1C 1D 1E 1F + 20 21 22 24 26 28 29 2A FF FF + FF FF FF FF FF FF FF 22 22 22 + 22 22 22 FF 07 01]; + goodix,fw_name = "gtp_fw.bin"; + goodix,have-touch-key; + goodix,driver-send-cfg; + }; +}; diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt deleted file mode 100644 index b54c85971927dcf0c0d48c840374ed4032089024..0000000000000000000000000000000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/himax.txt +++ /dev/null @@ -1,22 +0,0 @@ -Himax touch controller - -Required properties: - - - compatible : Should be "himax,hxcommon" - - reg : i2c slave address of the device. - - interrupt-parent : parent of interrupt. - - himax,irq-gpio : irq gpio. - - himax,reset-gpio : reset gpio. - - vdd-supply : Power supply needed to power up the device. - - avdd-supply : Power source required to power up i2c bus. - - himax,panel-coords : panel coordinates for the chip in pixels. - It is a four tuple consisting of min x, - min y, max x and max y values. - - himax,display-coords : display coordinates in pixels. It is a four - tuple consisting of min x, min y, max x and - max y values - -Optional properties: - - himax,3v3-gpio : gpio acting as 3.3 v supply. - - report_type : Multi-touch protocol type. Default 0. - 0 for protocol A, 1 for protocol B. diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt new file mode 100644 index 0000000000000000000000000000000000000000..9889f55dd4bb044a7ab28a60dd30dd4310fa071a --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/himax_i2c_ts.txt @@ -0,0 +1,57 @@ +Himax touch controller + +Required properties: + + - compatible : should be "himax,hxcommon" + - reg : i2c slave address of the device + - interrupt-parent : parent of interrupt + - interrupts : touch sample interrupt to indicate presense or release + of fingers on the panel. + - himax,irq-gpio : irq gpio + - himax,reset-gpio : reset gpio + +Optional property: + - vdd-supply : Analog power supply needed to power device + - vcc_i2c-supply : Power source required to pull up i2c bus + - himax,i2c-pull-up : specify to indicate pull up is needed + - himax,disable-gpios : specify to disable gpios in suspend (power saving) + - himax,button-map : virtual key code mappings to be used + - himax,x-flip : modify orientation of the x axis + - himax,y-flip : modify orientation of the y axis + - himax,panel-coords : touch panel min x, min y, max x and + max y resolution + - himax,display-coords : display min x, min y, max x and + max y resolution + - himax,reset-delay : reset delay for controller (ms), default 100 + - himax,fw-image-name : name of firmware .img file in /etc/firmware + - himax,power-down : fully power down regulators in suspend + - himax,do-lockdown : perform one time lockdown procedure + +Example: + i2c@f9927000 { /* BLSP1 QUP5 */ + cell-index = <5>; + compatible = "himax,hxcommon"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0xf9927000 0x1000>; + interrupt-names = "qup_err_intr"; + interrupts = <0 99 0>; + gpios = <&msmgpio 19 0>, /* SCL */ + <&msmgpio 18 0>; /* SDA */ + qcom,i2c-bus-freq = <100000>; + qcom,i2c-src-freq = <19200000>; + + himax_ts@20 { + compatible = "himax,hxcommon" + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <255 0x2008>; + vdd-supply = <&pm8994_l15>; + avdd-supply = <&pm8994_l22>; + himax,panel-coords = <0 720 0 1440>; + himax,display-coords = <0 720 0 1440>; + himax,irq-gpio = <&tlmm 255 0x2008>; + himax,rst-gpio = <&tlmm 8 0x00>; + }; + }; diff --git a/Documentation/devicetree/bindings/media/qca402x.txt b/Documentation/devicetree/bindings/media/qca402x.txt new file mode 100644 index 0000000000000000000000000000000000000000..f803b029eb29fc1565d7f95a54fe2fe2f6562483 --- /dev/null +++ b/Documentation/devicetree/bindings/media/qca402x.txt @@ -0,0 +1,14 @@ +* Qualcomm Technologies, Inc. MSM QCA402x + +Required properties for parent node: +- compatible : + - "qcom,qca402" + +Optional properties +- endpoints : Number of endpoints used for communication with the QCA402x + device +Example: +qcom,qca402x { + compatible = "qcom,qca402"; + endpoints = <1>; +}; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt index cd4d222021c497c2d0874a776ff2d08d83241368..59651a3541570c9b076f43ad31db629e8c504494 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-cci.txt @@ -1,355 +1,752 @@ * Qualcomm Technologies, Inc. MSM CCI -[First level nodes] -Required properties: +CCI (Camera Control Interface) is module that is use for camera sensor module +I2C communication. + +======================= +Required Node Structure +======================= +The camera CCI node must be described in two levels of device nodes. The +first level describe the overall CCI node structure. Second level nodes +describe camera sensor submodule nodes which is using CCI for +i2c communication. + +====================================== +First Level Node - CCI device +====================================== + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cci". + - cell-index: cci hardware core index -- compatible : - - "qcom,cci" -- reg : offset and length of the register set for the device - for the cci operating in compatible mode. -- reg-names : should specify relevant names to each reg property defined. -- interrupts : should contain the cci interrupt. -- interrupt-names : should specify relevant names to each interrupts - property defined. -- gpios : should contain phandle to gpio controller node and array of - #gpio-cells specifying specific gpio (controller specific) -- gpio-req-tbl-num : should contain index to gpios specific to this sensor -- gpio-req-tbl-flags : should contain direction of gpios present in - gpio-req-tbl-num property (in the same order) -- gpio-req-tbl-label : should contain name of gpios present in - gpio-req-tbl-num property (in the same order) -- clock-names: name of the clocks required for the device -- clock-rates: clock rate in Hz - -Optional properties: -- regulator-names : name of the voltage regulators required for the device. -- gdscr-supply : should contain gdsr regulator used for cci clocks. -- mmagic-supply : should contain mmagic regulator used for mmagic clocks. + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- reg-names + Usage: required + Value type: + Definition: Should specify relevant names to each + reg property defined. + +- interrupts + Usage: required + Value type: + Definition: Interrupt associated with CCI HW. + +- interrupt-names + Usage: required + Value type: + Definition: Name of the interrupt. + +- gpios + Usage: required + Value type: + Definition: should specify the gpios to be used for the CCI. + +- gpio-req-tbl-num + Usage: required + Value type: + Definition: should specify the gpio table index. + +- gpio-req-tbl-flags + Usage: required + Value type: + Definition: should specify the gpio functions. + +- gpio-req-tbl-label + Usage: required + Value type: + Definition: should specify the gpio labels in + gpio-req-tbl-num property (in the same order) + +- clock-names + Usage: required + Value type: + Definition: List of clock names required for CCI HW. + +- clock-rates + Usage: required + Value type: + Definition: List of clock rates in Hz for CCI HW. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. +- src-clock-name + Usage: required + Value type: + Definition: name for the source clock. + +- regulator-names + Usage: required + Value type: + Definition: name of the voltage regulators required for the device. + +- gdscr-supply + Usage: required + Value type: + Definition: should contain gdsr regulator used for cci clocks. + +- mmagic-supply + Usage: optional + Value type: + Definition: should contain mmagic regulator used for mmagic clocks. + +========================= +CCI clock settings +========================= - I2c speed settings (*) - - i2c_freq_100Khz: qcom,i2c_standard_mode - node should contain clock settings for - 100Khz - - i2c_freq_400Khz: qcom,i2c_fast_mode - node should contain clock settings for - 400Khz - - i2c_freq_custom: qcom,i2c_custom_mode - node can contain clock settings for - frequencies other than 100Khz and 400Khz which is specific to usecase. - Currently it has settings for 375Khz. - - i2c_freq_1Mhz: qcom,i2c_fast_plus_mode - node should contain clock - settings for 1Mhz + Usage: required + Definition: List of i2c rates for CCI HW. + - i2c_freq_100Khz + Definition: qcom,i2c_standard_mode - node should contain clock settings for + 100Khz + - i2c_freq_400Khz + Definition: qcom,i2c_fast_mode - node should contain clock settings for + 400Khz + - i2c_freq_custom + Definition: qcom,i2c_custom_mode - node can contain clock settings for + frequencies other than 100Khz and 400Khz which is specific to usecase. + Currently it has settings for 375Khz. + - i2c_freq_1Mhz + Definition: qcom,i2c_fast_plus_mode - node should contain clock + settings for 1Mhz * if speed settings is not defined the low level driver can use "i2c_freq_custom" like default -[Second level nodes] -* Qualcomm Technologies, Inc. CCI clock settings + - hw-thigh + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tlow + Definition: should contain high period of the SCL clock in terms of CCI clock cycle + - hw-tsu-sto + Definition: should contain setup time for STOP condition + - hw-tsu-sta + Definition: should contain setup time for Repeated START condition + - hw-thd-dat + Definition: should contain hold time for the data + - hw-thd-sta + Definition: should contain hold time for START condition + - hw-tbuf + Definition: should contain free time between a STOP and a START condition + - hw-scl-stretch-en + Definition: should contain enable or disable clock stretching + - hw-trdhld + Definition: should contain internal hold time for SDA + - hw-tsp + Definition: should contain filtering of glitches -Optional properties: -- hw-thigh : should contain high period of the SCL clock in terms of CCI clock cycle -- hw-tlow : should contain high period of the SCL clock in terms of CCI clock cycle -- hw-tsu-sto : should contain setup time for STOP condition -- hw-tsu-sta : should contain setup time for Repeated START condition -- hw-thd-dat : should contain hold time for the data -- hw-thd-sta : should contain hold time for START condition -- hw-tbuf : should contain free time between a STOP and a START condition -- hw-scl-stretch-en : should contain enable or disable clock stretching -- hw-trdhld : should contain internal hold time for SDA -- hw-tsp : should contain filtering of glitches +Example: + + qcom,cci@0xfda0c000 { + cell-index = <0>; + compatible = "qcom,cci"; + reg = <0xfda0c000 0x300>; + reg-names = "cci"; + interrupts = <0 50 0>; + interrupt-names = "cci"; + clock-names = "camnoc_axi_clk", "soc_ahb_clk", + "slow_ahb_src_clk", "cpas_ahb_clk", + "cci_clk", "cci_clk_src"; + clock-rates = <0 0 80000000 0 0 37500000>; + clock-cntl-level = "turbo"; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-tbl-num = <0 1 2 3>; + gpio-tbl-flags = <1 1 1 1>; + gpio-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + i2c_freq_100Khz: qcom,i2c_standard_mode { + hw-thigh = <78>; + hw-tlow = <114>; + hw-tsu-sto = <28>; + hw-tsu-sta = <28>; + hw-thd-dat = <10>; + hw-thd-sta = <77>; + hw-tbuf = <118>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <1>; + status = "ok"; + }; + i2c_freq_400Khz: qcom,i2c_fast_mode { + hw-thigh = <20>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <0>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_custom: qcom,i2c_custom_mode { + hw-thigh = <15>; + hw-tlow = <28>; + hw-tsu-sto = <21>; + hw-tsu-sta = <21>; + hw-thd-dat = <13>; + hw-thd-sta = <18>; + hw-tbuf = <25>; + hw-scl-stretch-en = <1>; + hw-trdhld = <6>; + hw-tsp = <3>; + status = "ok"; + }; + i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { + hw-thigh = <16>; + hw-tlow = <22>; + hw-tsu-sto = <17>; + hw-tsu-sta = <18>; + hw-thd-dat = <16>; + hw-thd-sta = <15>; + hw-tbuf = <19>; + hw-scl-stretch-en = <1>; + hw-trdhld = <3>; + hw-tsp = <3>; + cci-clk-src = <37500000>; + status = "ok"; + }; + }; -* Qualcomm Technologies, Inc. MSM Camera Sensor Resource Manager +======================================= +Second Level Node - CAM SENSOR MODULES +======================================= -MSM camera sensor resource manager node contains properties of shared camera +======================================= +CAM SENSOR RESOURCE MANAGER +======================================= +Camera Sensor Resource manager node contains properties of shared camera sensor resource. -Required properties: -- compatible : should be manufacturer name followed by sensor name - - "qcom,cam-res-mgr" -Optional properties: -- shared-gpios : should contain the gpios which are used by two or more - cameras, and these cameras may be opened together. -- pinctrl-names: List of names to assign the shared pin state defined in pinctrl device node -- pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin - controller. These pin configurations are installed in the pinctrl device node. - -* Qualcomm Technologies, Inc. MSM Sensor - -MSM sensor node contains properties of camera sensor - -Required properties: -- compatible : should be manufacturer name followed by sensor name - - "qcom,camera" -- reg : should contain i2c slave address of the device -- csiphy-sd-index : should contain csiphy instance that will used to - receive sensor data - - 0, 1, 2 -- cam_vdig-supply : should contain regulator from which digital voltage is - supplied -- cam_vana-supply : should contain regulator from which analog voltage is - supplied -- cam_vio-supply : should contain regulator from which IO voltage is supplied -- regulator-names : should contain names of all regulators needed by this - sensor - - "cam_vdig", "cam_vana", "cam_vio", "cam_vaf" -- rgltr-cntrl-support : It is booloean property. This property is required - if the code and regulator control parameters e.g. rgltr-min-voltage -- rgltr-min-voltage : should contain minimum voltage level for - regulators mentioned in regulator-names property (in the same order) -- rgltr-max-voltage : should contain maximum voltage level for - regulators mentioned in regulator-names property (in the same order) -- rgltr-load-current : should contain optimum voltage level for regulators - mentioned in regulator-names property (in the same order) -- sensor-position-roll : should contain sensor rotational angle with respect - to axis of reference - - 0, 90, 180, 360 -- sensor-position-pitch : should contain sensor rotational angle with respect - to axis of reference - - 0, 90, 180, 360 -- sensor-position-yaw : should contain sensor rotational angle with respect - to axis of reference - - 0, 90, 180, 360 -Optional properties: -- slave-id : should contain i2c slave address, device id address, expected - id read value and device id mask -- sensor-name : should contain unique sensor name to differentiate from - other sensor - - "s5k3l1yx" -- sensor-mode : should contain sensor mode supported - - 0 -> back camera 2D - - 1 -> front camera 2D - - 2 -> back camera 3D - - 3 -> back camera int 3D -- sensor-type : should contain format of data that sensor streams - - 0 -> bayer format - - 1 -> yuv format -- qcom,secure : should be enabled to operate the camera in secure mode - - 0, 1 -- gpio-no-mux : should contain field to indicate whether gpio mux table is - available - - 1 if gpio mux is not available, 0 otherwise -- cam_vaf-supply : should contain regulator from which AF voltage is supplied -- gpios : should contain phandle to gpio controller node and array of - #gpio-cells specifying specific gpio (controller specific) -- gpio-reset : should contain index to gpio used by sensors reset_n -- gpio-standby : should contain index to gpio used by sensors standby_n -- gpio-vio : should contain index to gpio used by sensors io vreg enable -- gpio-vana : should contain index to gpio used by sensors analog vreg enable -- gpio-vdig : should contain index to gpio used by sensors digital vreg enable -- gpio-vaf : should contain index to gpio used by sensors af vreg enable -- gpio-af-pwdm : should contain index to gpio used by sensors af pwdm_n -- gpio-req-tbl-num : should contain index to gpios specific to this sensor -- gpio-req-tbl-flags : should contain direction of gpios present in - gpio-req-tbl-num property (in the same order) -- gpio-req-tbl-label : should contain name of gpios present in - gpio-req-tbl-num property (in the same order) -- gpio-set-tbl-num : should contain index of gpios that need to be - configured by msm -- gpio-set-tbl-flags : should contain value to be configured for the gpios - present in gpio-set-tbl-num property (in the same order) -- gpio-set-tbl-delay : should contain amount of delay after configuring - gpios as specified in gpio_set_tbl_flags property (in the same order) -- csi-phy-sel : should contain CSIPHY core instance from which CSID should - receive data -- actuator-cam-name : should contain actuator cam name associated with - this sensor - - If actuator does not exist, this property should not be initialized - - If actuator exist, this field should indicate the index of actuator to - be used -- qcom,actuator-vcm-pwd : should contain the gpio pin of vcm power to be enabled - for actuator -- qcom,actuator-vcm-enable : should contain value to be set for actuator vcm - gpio -- sensor-position : should contain the mount angle of the camera sensor - - 0 -> back camera - - 1 -> front camera -- cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 -- actuator-src : if auto focus is supported by this sensor, this - property should contain phandle of respective actuator node -- led-flash-src : if LED flash is supported by this sensor, this - property should contain phandle of respective LED flash node -- qcom,vdd-cx-supply : should contain regulator from which cx voltage is - supplied -- qcom,vdd-cx-name : should contain names of cx regulator -- eeprom-src : if eeprom memory is supported by this sensor, this - property should contain phandle of respective eeprom nodes -- ois-src : if optical image stabilization is supported by this sensor, - this property should contain phandle of respective ois node -- ir-led-src : if ir led is supported by this sensor, this property - should contain phandle of respective ir-led node -- qcom,ir-cut-src : if ir cut is supported by this sensor, this property - should contain phandle of respective ir-cut node -- qcom,special-support-sensors: if only some special sensors are supported - on this board, add sensor name in this property. -- use-shared-clk : It is booloean property. This property is required - if the clk is shared clk between different sensor and ois, if this - device need to be opened together. -- clock-rates: clock rate in Hz. -- clock-cntl-level: says what all different cloc level node has. -- clock-cntl-support: Says whether clock control support is present or not -- clock-control: The valid fields are "NO_SET_RATE", "INIT_RATE" and - "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting - the rate assuming some other driver has already set it to appropriate rate. - "INIT_RATE" clock rate is not queried assuming some other driver has set - the clock rate and ispif will set the the clock to this rate. - "SET_RATE" clock is enabled and the rate is set to the value specified - in the property clock-rates. - -* Qualcomm Technologies, Inc. MSM ACTUATOR - -Required properties: -- cell-index : should contain unique identifier to differentiate - between multiple actuators -- reg : should contain i2c slave address of the actuator and length of - data field which is 0x0 -- compatible : - - "qcom,actuator" -- cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 -Optional properties: -- regulator-names : should contain names of all regulators needed by this - actuator - - "cam_vaf" -- rgltr-cntrl-support : It is booloean property. This property is required - if the code and regulator control parameters e.g. rgltr-min-voltage -- rgltr-min-voltage : should contain minimum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-max-voltage : should contain maximum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-load-current : should contain the maximum current in microamps - required from the regulators mentioned in the regulator-names property - (in the same order). -- cam_vaf-supply : should contain regulator from which AF voltage is supplied - -* Qualcomm Technologies, Inc. MSM OIS - -Required properties: -- cell-index : should contain unique identifier to differentiate - between multiple ois drivers -- reg : should contain i2c slave address of the ois and length of - data field which is 0x0 -- compatible : - - "qcom,ois" -- cci-master : should contain i2c master id to be used for this camera - sensor - - 0 -> MASTER 0 - - 1 -> MASTER 1 -- clock-rates: clock rate in Hz. - -Optional properties: -- regulator-names : should contain names of all regulators needed by this - ois - - "cam_vaf" -- rgltr-cntrl-support : It is booloean property. This property is required - if the code and regulator control parameters e.g. rgltr-min-voltage -- rgltr-min-voltage : should contain minimum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-max-voltage : should contain maximum voltage level in mcrovolts - for regulators mentioned in regulator-names property (in the same order) -- rgltr-load-current : should contain the maximum current in microamps - required from the regulators mentioned in the regulator-names property - (in the same order). -- cam_vaf-supply : should contain regulator from which ois voltage is supplied -- use-shared-clk : It is booloean property. This property is required - if the clk is shared clk between different sensor and ois, if this - device need to be opened together. +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-res-mgr". -Example: +- shared-gpios + Usage: optional + Value type: + Definition: should contain the gpios which are used by two or more + cameras, and these cameras may be opened together. -led_flash0: qcom,camera-flash@0 { - cell-index = <0>; - compatible = "qcom,camera-flash"; - flash-source = <&pmi8994_flash0 &pmi8994_flash1>; - torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - switch-source = <&pmi8998_switch>; - status = "ok"; -} - -qcom,cci@0xfda0c000 { - cell-index = <0>; - compatible = "qcom,cci"; - reg = <0xfda0c000 0x300>; - reg-names = "cci"; - interrupts = <0 50 0>; - interrupt-names = "cci"; - clock-names = "camnoc_axi_clk", "soc_ahb_clk", - "slow_ahb_src_clk", "cpas_ahb_clk", - "cci_clk", "cci_clk_src"; - clock-rates = <0 0 80000000 0 0 37500000>; - clock-cntl-level = "turbo"; - gpios = <&tlmm 17 0>, - <&tlmm 18 0>, - <&tlmm 19 0>, - <&tlmm 20 0>; - gpio-tbl-num = <0 1 2 3>; - gpio-tbl-flags = <1 1 1 1>; - gpio-tbl-label = "CCI_I2C_DATA0", - "CCI_I2C_CLK0", - "CCI_I2C_DATA1", - "CCI_I2C_CLK1"; - i2c_freq_100Khz: qcom,i2c_standard_mode { - hw-thigh = <78>; - hw-tlow = <114>; - hw-tsu-sto = <28>; - hw-tsu-sta = <28>; - hw-thd-dat = <10>; - hw-thd-sta = <77>; - hw-tbuf = <118>; - hw-scl-stretch-en = <0>; - hw-trdhld = <6>; - hw-tsp = <1>; - status = "ok"; - }; - i2c_freq_400Khz: qcom,i2c_fast_mode { - hw-thigh = <20>; - hw-tlow = <28>; - hw-tsu-sto = <21>; - hw-tsu-sta = <21>; - hw-thd-dat = <13>; - hw-thd-sta = <18>; - hw-tbuf = <25>; - hw-scl-stretch-en = <0>; - hw-trdhld = <6>; - hw-tsp = <3>; - status = "ok"; - }; - i2c_freq_custom: qcom,i2c_custom_mode { - hw-thigh = <15>; - hw-tlow = <28>; - hw-tsu-sto = <21>; - hw-tsu-sta = <21>; - hw-thd-dat = <13>; - hw-thd-sta = <18>; - hw-tbuf = <25>; - hw-scl-stretch-en = <1>; - hw-trdhld = <6>; - hw-tsp = <3>; - status = "ok"; - }; - i2c_freq_1Mhz: qcom,i2c_fast_plus_mode { - hw-thigh = <16>; - hw-tlow = <22>; - hw-tsu-sto = <17>; - hw-tsu-sta = <18>; - hw-thd-dat = <16>; - hw-thd-sta = <15>; - hw-tbuf = <19>; - hw-scl-stretch-en = <1>; - hw-trdhld = <3>; - hw-tsp = <3>; - cci-clk-src = <37500000>; +- pinctrl-names + Usage: optional + Value type: + Definition: List of names to assign the shared pin state defined in pinctrl device node + +- pinctrl-<0..n> + Usage: optional + Value type: + Definition: Lists phandles each pointing to the pin configuration node within a pin + controller. These pin configurations are installed in the pinctrl device node. + + +============================= +CAMERA IMAGE SENSOR MODULE +============================= +Image sensor node contains properties of camera image sensor + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,cam-sensor". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- csiphy-sd-index + Usage: required + Value type: + Definition: should contain csiphy instance that will used to + receive sensor data (0, 1, 2, 3). + +- cam_vdig-supply + Usage: required + Value type: + Definition: should contain regulator from which digital voltage is + supplied + +- cam_vana-supply + Usage: required + Value type: + Definition: should contain regulator from which analog voltage is + supplied + +- cam_vio-supply + Usage: required + Value type: + Definition: should contain regulator from which IO voltage is supplied + +- cam_bob-supply + Usage: optional + Value type: + Definition: should contain regulator from which BoB voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + sensor + +- rgltr-cntrl-support + Usage: required + Value type: + Definition: This property is required if the sw control regulator parameters + e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: required + Value type: + Definition: should contain minimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: required + Value type: + Definition: should contain maximum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- rgltr-load-current + Usage: required + Value type: + Definition: should contain optimum voltage level for regulators mentioned + in regulator-names property (in the same order) + +- sensor-position-roll + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-pitch + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- sensor-position-yaw + Usage: required + Value type: + Definition: should contain sensor rotational angle with respect to axis of + reference. i.e. 0, 90, 180, 360 + +- qcom,secure + Usage: optional + Value type: + Definition: should be enabled to operate the camera in secure mode + +- gpio-no-mux + Usage: optional + Value type: + Definition: should contain field to indicate whether gpio mux table is + available. i.e. 1 if gpio mux is not available, 0 otherwise + +- cam_vaf-supply + Usage: optional + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- pwm-switch + Usage: optional + Value type: + Definition: This property is required for regulator to switch into PWM mode. + +- gpios + Usage: required + Value type: + Definition: should contain phandle to gpio controller node and array of + #gpio-cells specifying specific gpio (controller specific) + +- gpio-reset + Usage: required + Value type: + Definition: should contain index to gpio used by sensors reset_n + +- gpio-standby + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors standby_n + +- gpio-vio + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors io vreg enable + +- gpio-vana + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors analog vreg enable + +- gpio-vdig + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors digital vreg enable + +- gpio-vaf + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af vreg enable + +- gpio-af-pwdm + Usage: optional + Value type: + Definition: should contain index to gpio used by sensors af pwdm_n + +- gpio-req-tbl-num + Usage: optional + Value type: + Definition: should contain index to gpios specific to this sensor + +- gpio-req-tbl-flags + Usage: optional + Value type: + Definition: should contain direction of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-req-tbl-label + Usage: optional + Value type: + Definition: should contain name of gpios present in + gpio-req-tbl-num property (in the same order) + +- gpio-set-tbl-num + Usage: optional + Value type: + Definition: should contain index of gpios that need to be + configured by msm + +- gpio-set-tbl-flags + Usage: optional + Value type: + Definition: should contain value to be configured for the gpios + present in gpio-set-tbl-num property (in the same order) + +- gpio-set-tbl-delay + Usage: optional + Value type: + Definition: should contain amount of delay after configuring + gpios as specified in gpio_set_tbl_flags property (in the same order) + +- actuator-src + Usage: optional + Value type: + Definition: if auto focus is supported by this sensor, this + property should contain phandle of respective actuator node + +- led-flash-src + Usage: optional + Value type: + Definition: if LED flash is supported by this sensor, this + property should contain phandle of respective LED flash node + +- qcom,vdd-cx-supply + Usage: optional + Value type: + Definition: should contain regulator from which cx voltage is supplied + +- qcom,vdd-cx-name + Usage: optional + Value type: + Definition: should contain names of cx regulator + +- eeprom-src + Usage: optional + Value type: + Definition: if eeprom memory is supported by this sensor, this + property should contain phandle of respective eeprom nodes + +- ois-src + Usage: optional + Value type: + Definition: if optical image stabilization is supported by this sensor, + this property should contain phandle of respective ois node + +- ir-led-src + Usage: optional + Value type: + Definition: if ir led is supported by this sensor, this property + should contain phandle of respective ir-led node + +- qcom,ir-cut-src + Usage: optional + Value type: + Definition: if ir cut is supported by this sensor, this property + should contain phandle of respective ir-cut node + +- qcom,special-support-sensors + Usage: required + Value type: + Definition: if only some special sensors are supported + on this board, add sensor name in this property. + +- use-shared-clk + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the clk is shared clk between different sensor and ois, if this + device need to be opened together. + +- clock-rates + Usage: required + Value type: + Definition: clock rate in Hz. + +- clock-cntl-level + Usage: required + Value type: + Definition: All different clock level node can support. + +- clock-cntl-support + Usage: optional + Value type: + Definition: Says whether clock control support is present or not + +- clocks + Usage: required + Value type: + Definition: all clock phandle and source clocks. + +- clock-control + Usage: optional + Value type: + Definition: The valid fields are "NO_SET_RATE", "INIT_RATE" and + "SET_RATE". "NO_SET_RATE" the corresponding clock is enabled without setting + the rate assuming some other driver has already set it to appropriate rate. + "INIT_RATE" clock rate is not queried assuming some other driver has set + the clock rate and ispif will set the the clock to this rate. + "SET_RATE" clock is enabled and the rate is set to the value specified + in the property clock-rates. + +============================= +ACTUATOR MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,actuator". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +============================= +OIS MODULE +============================= + +- compatible + Usage: required + Value type: + Definition: Should be "qcom,ois". + +- cell-index: cci hardware core index + Usage: required + Value type: + Definition: Should specify the Hardware index id. + +- reg + Usage: required + Value type: + Definition: offset and length of the register set + for the device for the cci operating in + compatible mode. + +- cci-device + Usage: required + Value type: + Definition: should contain i2c device id to be used for this camera + sensor + +- cci-master + Usage: required + Value type: + Definition: should contain i2c master id to be used for this camera + sensor + - 0 -> MASTER 0 + - 1 -> MASTER 1 + +- cam_vaf-supply + Usage: required + Value type: + Definition: should contain regulator from which AF voltage is supplied + +- regulator-names + Usage: required + Value type: + Definition: should contain names of all regulators needed by this + actuator. i.e. "cam_vaf" + +- rgltr-cntrl-support + Usage: optional + Value type: + Definition: It is booloean property. This property is required + if the code and regulator control parameters e.g. rgltr-min-voltage + +- rgltr-min-voltage + Usage: optional + Value type: + Definition: should contain minimum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-max-voltage + Usage: optional + Value type: + Definition: should contain maximum voltage level in mcrovolts + for regulators mentioned in regulator-names property (in the same order) + +- rgltr-load-current + Usage: optional + Value type: + Definition: should contain the maximum current in microamps + required from the regulators mentioned in the regulator-names property + (in the same order). + +- use-shared-clk + Usage: optional + Value type: + Definition: This property is required if the clk is shared clk between different + sensor and ois, if this device need to be opened together. + +Example: +&soc { + led_flash0: qcom,camera-flash@0 { + cell-index = <0>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8994_flash0 &pmi8994_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch>; status = "ok"; }; +}; +&cam_cci0 { actuator0: qcom,actuator@0 { cell-index = <0>; reg = <0x0>; compatible = "qcom,actuator"; + cci-device = <0>; cci-master = <0>; cam_vaf-supply = <&pmi8998_bob>; regulator-names = "cam_vaf"; - rgltr-cntrl-support; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <100000>; + }; + + ois0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-device = <0>; + cci-master = <0>; + cam_vaf-supply = <&pmi8998_bob>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; rgltr-min-voltage = <2800000>; rgltr-max-voltage = <2800000>; rgltr-load-current = <100000>; @@ -375,15 +772,20 @@ qcom,cci@0xfda0c000 { secure = <1>; led-flash-src = <&led_flash0>; actuator-src = <&actuator0>; + ois-src = <&ois0>; eeprom-src = <&eeprom0>; - cam_vdig-supply = <&pm845_s3>; - cam_vio-supply = <&pm845_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - regulator-names = "cam_vdig", "cam_vio", "cam_vana"; + cam_vdig-supply = <&pm8009_l2>; + cam_vio-supply = <&pm8009l_l1>; + cam_vana-supply = <&pm8009l_l5>; + cam_bob-supply = <&pm8150l_bob>; + cam_clk-supply = <&tital_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_bob"; rgltr-cntrl-support; - rgltr-min-voltage = <0 3312000 1352000>; - rgltr-max-voltage = <0 3312000 1352000>; - rgltr-load-current = <0 80000 105000>; + pwm-switch; + rgltr-min-voltage = <0 2800000 1200000 0 3008000>; + rgltr-max-voltage = <0 2800000 1200000 0 4000000>; + rgltr-load-current = <0 80000 1200000 0 2000000>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk0_active @@ -402,12 +804,14 @@ qcom,cci@0xfda0c000 { "CAM_VANA"; sensor-position = <0>; sensor-mode = <0>; + cci-device = <0>; cci-master = <0>; status = "ok"; use-shared-clk; clocks = <&clock_mmss clk_mclk0_clk_src>, <&clock_mmss clk_camss_mclk0_clk>; clock-names = "cam_src_clk", "cam_clk"; - clock-cntl-level; + clock-cntl-leveli = "turbo"; + clock-rates = <24000000>; }; }; diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt index c47cb34a2ae63da06632621e1347e7b624e42d2b..b96853054decdcc5f93ffdd8c36e5740d026e9af 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-fd.txt @@ -108,6 +108,11 @@ about the device register map, interrupt map, clocks, regulators. Value type: Definition: Source clock name. +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + - clock-cntl-level Usage: required Value type: diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt index ffc0e96a459de868e7c3072284a11b99945d852c..14958819068c2edfb12c3923714013a9dd21ac23 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt @@ -110,6 +110,11 @@ and name of firmware image. Value type: Definition: Source clock name. +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + - clocks Usage: required Value type: 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 f9a5e0fc1bf1e3571bec857378997c164d32ec4d..29ea987e306d9ef7acb3ddf2c0b2a49d42be9fee 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-ife-csid.txt @@ -73,7 +73,10 @@ First Level Node - CAM IFE CSID device Value type: Definition: Source clock name. - +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. Example: diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt index 99f2c7a0be350ab45804b0cd032749e061123f8d..f156cc67b2aa19c2ed51ffa05bf9e2f2b4a7497d 100644 --- a/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt +++ b/Documentation/devicetree/bindings/media/video/msm-cam-vfe.txt @@ -91,6 +91,11 @@ Optional properties: Value type: Definition: List of clocks rates for optional clocks. +- clock-control-debugfs + Usage: optional + Value type: + Definition: Enable/Disable clk rate control. + Example: qcom,vfe0@acaf000 { cell-index = <0>; diff --git a/Documentation/devicetree/bindings/net/dsa/b53.txt b/Documentation/devicetree/bindings/net/dsa/b53.txt index d6c6e41648d4f17814ea43775e8591a40a4c0786..6192f02af2a949e66d93d0cbb5313a971e1ea649 100644 --- a/Documentation/devicetree/bindings/net/dsa/b53.txt +++ b/Documentation/devicetree/bindings/net/dsa/b53.txt @@ -10,6 +10,7 @@ Required properties: "brcm,bcm53128" "brcm,bcm5365" "brcm,bcm5395" + "brcm,bcm5389" "brcm,bcm5397" "brcm,bcm5398" diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index 0b6daab49367f8b50917ba11e5e67552a93d3726..2c267431e8b311dab55cf3f9c15667de1c18499d 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -241,6 +241,12 @@ Charger specific properties: connector THERM, only valid values are (0/30/100/400). If not specified 100K is used as default pull-up. +- qcom,moisture-protection-enable + Usage: optional + Value type: bool + Definition: Boolean flag which when present enables mositure protection + feature. + ============================================= Second Level Nodes - SMB5 Charger Peripherals ============================================= diff --git a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt index a034acc98aa6e536eb8127e3fa25d8c65e9cdc43..e546dc22a368707febe6e370860fe1baa9a5ff1a 100644 --- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt +++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt @@ -16,6 +16,7 @@ Optional properties: - qcom,adsp-remoteheap-vmid: FastRPC remote heap VMID list - qcom,fastrpc-adsp-audio-pdr: Flag to enable ADSP Audio PDR - qcom,fastrpc-adsp-sensors-pdr: Flag to enable Sensors PDR +- qcom,secure-domains: FastRPC secure domain configuration Optional subnodes: - qcom,msm_fastrpc_compute_cb : Child nodes representing the compute context diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 20cb25b1db9b79bb0c0b5ead129ff1a4350165cd..6c9d82538c4fd844fc81df0fa1677020bb8318c2 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -3290,3 +3290,97 @@ Example: qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", "SpkrLeft", "SpkrRight"; } + +* QCS605 IPcamera ASoC Machine driver + +Required properties: +- compatible : "qcom,qcs605-asoc-snd-tavil" +- qcom,model : The user-visible name of this sound card. +- qcom,audio-routing : A list of the connections between audio components. +- qcom,msm-gpios : Lists down all the gpio sets that are supported. +- qcom,pinctrl-names : Lists all the possible combinations of the gpio sets +mentioned in qcom,msm-gpios. +- pinctrl-names : The combinations of gpio sets from above that are supported in +the flavor. +- pinctrl-# : Pinctrl states as mentioned in pinctrl-names. + +Optional properties: +- qcom,wsa-disable : Boolean. Disables WSA speaker dailinks from sound node. +- qcom,msm-spk-ext-pa : GPIO which enables external speaker pa. +- qcom,msm-mclk-freq : This property is used to inform machine driver about +mclk frequency needs to be configured for internal and external PA. +- asoc-platform: This is phandle list containing the references to platform device + nodes that are used as part of the sound card dai-links. +- asoc-platform-names: This property contains list of platform names. The order of + the platform names should match to that of the phandle order + given in "asoc-platform". +- asoc-cpu: This is phandle list containing the references to cpu dai device nodes + that are used as part of the sound card dai-links. +- asoc-cpu-names: This property contains list of cpu dai names. The order of the + cpu dai names should match to that of the phandle order given. +- asoc-codec: This is phandle list containing the references to codec dai device + nodes that are used as part of the sound card dai-links. +- asoc-codec-names: This property contains list of codec dai names. The order of the + codec dai names should match to that of the phandle order given + in "asoc-codec". +- qcom,wsa-max-devs : Maximum number of WSA881x devices present in the target +- qcom,wsa-devs : List of phandles for all possible WSA881x devices supported for the target +- qcom,wsa-aux-dev-prefix : Name prefix with Left/Right configuration for WSA881x device +- qcom,cdc-dmic-gpios : phandle for Digital mic clk and data gpios. +- qcom,cdc-sdw-gpios : phandle for soundwire clk and data gpios. +- qcom,pri-mi2s-gpios : phandle for primary MI2S clk, word select and data gpios. +- qcom,sec-mi2s-gpios : phandle for secondary MI2S clk, word select and data gpios. +- qcom,tert-mi2s-gpios : phandle for tertiary MI2S clk, word select and data gpios. +- qcom,quat-mi2s-gpios : phandle for quaternary MI2S clk, word select and data gpios. +- qcom,quin-mi2s-gpios : phandle for quinary MI2S clk, word select and data gpios. + +Example: + sound { + compatible = "qcom,qcs605-asoc-snd-tavil"; + qcom,model = "qcs605-tavil-snd-card"; + qcom,audio-routing = + "RX_BIAS", "INT_MCLK0", + "SPK_RX_BIAS", "INT_MCLK0", + "DMIC1", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic1", + "DMIC2", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic2", + "DMIC3", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic3", + "DMIC4", "DIGITAL_REGULATOR", + "DIGITAL_REGULATOR", "Digital Mic4", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,msm-mclk-freq = <9600000>; + qcom,msm-gpios = + "slim", + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "slim_act", + "us_eu_gpio_act", + "slim_us_eu_gpio_act"; + pinctrl-names = + "all_off", + "slim_act", + "us_eu_gpio_act", + "slim_us_eu_gpio_act"; + pinctrl-0 = <&cdc_slim_lines_sus &cross_conn_det_sus>; + pinctrl-1 = <&cdc_slim_lines_act &cross_conn_det_sus>; + pinctrl-2 = <&cdc_slim_lines_sus &cross_conn_det_act>; + pinctrl-3 = <&cdc_slim_lines_act &cross_conn_det_act>; + qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>; + + asoc-codec = <&stub_codec>, <&msm_digital_codec>, + <&msm_sdw_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-dig-codec", + "msm_sdw_codec"; + + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211_en>, <&wsa881x_212_en>, + <&wsa881x_213_en>, <&wsa881x_214_en>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + } diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index a22edb520505ea5b3233b08f75277eb8ab62994a..ed51a777f9718b1d5759fb828b22546aad6377ce 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -123,13 +123,13 @@ halo Halo Microelectronics Co., Ltd. hannstar HannStar Display Corporation haoyu Haoyu Microelectronic Co. Ltd. hardkernel Hardkernel Co., Ltd -himax Himax Technologies, Inc. hisilicon Hisilicon Limited. hit Hitachi Ltd. hitex Hitex Development Tools holt Holt Integrated Circuits, Inc. honeywell Honeywell hp Hewlett Packard +himax Himax Coroporation i2se I2SE GmbH ibm International Business Machines (IBM) idt Integrated Device Technologies, Inc. diff --git a/Documentation/networking/netdev-FAQ.txt b/Documentation/networking/netdev-FAQ.txt index a20b2fae942b29e21fba5935f47777b391ecd65f..56af008e9258ac8e63cfef2fe25d9ce107f2944d 100644 --- a/Documentation/networking/netdev-FAQ.txt +++ b/Documentation/networking/netdev-FAQ.txt @@ -168,6 +168,15 @@ A: No. See above answer. In short, if you think it really belongs in dash marker line as described in Documentation/SubmittingPatches to temporarily embed that information into the patch that you send. +Q: Are all networking bug fixes backported to all stable releases? + +A: Due to capacity, Dave could only take care of the backports for the last + 2 stable releases. For earlier stable releases, each stable branch maintainer + is supposed to take care of them. If you find any patch is missing from an + earlier stable branch, please notify stable@vger.kernel.org with either a + commit ID or a formal patch backported, and CC Dave and other relevant + networking developers. + Q: Someone said that the comment style and coding convention is different for the networking content. Is this true? diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt index 5962949944fd7307530f26c54c65d783745a8a27..d2fbeeb295824cf697c6f295cc01f616a2e0d51c 100644 --- a/Documentation/printk-formats.txt +++ b/Documentation/printk-formats.txt @@ -279,11 +279,10 @@ struct clk: %pC pll1 %pCn pll1 - %pCr 1560000000 For printing struct clk structures. '%pC' and '%pCn' print the name (Common Clock Framework) or address (legacy clock framework) of the - structure; '%pCr' prints the current clock rate. + structure. Passed by reference. diff --git a/Makefile b/Makefile index 6fac39b6714b715321492915066f40d909b921e2..98ce41fb53d65588a9293986320f834eeaedd465 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 106 +SUBLEVEL = 112 EXTRAVERSION = NAME = Roaring Lionus diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 54e93a0066180ff28c3f87ee528acb10fff89359..04b90d375b1f00c8ed1f8d90fcd3d337bbb06c06 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1412,6 +1412,16 @@ config HAVE_ARM_TWD help This options enables support for the ARM timer and watchdog unit +config ARCH_MSM8953_SOC_SETTINGS + bool "Enable MSM8953 SOC settings" + depends on ARCH_MSM8953 + help + Enable MSM8953 SOC related settings, these generic MSM8953 + related settings are required for some of CPUSS sub-system + functionality. + + If you are not sure what to do, select 'N' here. + config MCPM bool "Multi-Cluster Power Management" depends on CPU_V7 && SMP diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index e9a5d0b8c7b05917f27345c39dab9179f9642052..908b269a016b9ca8a875f3be0c6d72ea4954d976 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -96,7 +96,7 @@ clocks = <&clks IMX6Q_CLK_ECSPI5>, <&clks IMX6Q_CLK_ECSPI5>; clock-names = "ipg", "per"; - dmas = <&sdma 11 7 1>, <&sdma 12 7 2>; + dmas = <&sdma 11 8 1>, <&sdma 12 8 2>; dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts index 04f11ce9ec7b1bf4bf3d26b919b66e279b1f7f30..fa858c371a7acf1302871917f204f86bef29aeab 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,cdp"; qcom,board-id = <1 0x0>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi index 0f9c8bc422f679e8a52a9a4d0e207eee3a5eb082..fc56a506bdde4706b3c5842ba7d21894327c638f 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp-256.dtsi @@ -11,6 +11,7 @@ */ #include "sdxpoorwills-cdp.dtsi" +#include "sdxpoorwills-memory-256.dtsi" &soc { vreg_sd_mmc: vreg_sd_mmc { @@ -21,3 +22,11 @@ &sdhc_1 { cd-gpios = <&tlmm 21 0x1>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts index 99e3faafd38974550f3259de878a5e0c7d1d624e..eb282823e5634680c9502798135395e21178d523 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts @@ -22,3 +22,7 @@ "qcom,sdxpoorwills", "qcom,cdp"; qcom,board-id = <1 0x102>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi index 8c506b921b3b238ba75114773ef02503cdd51193..c836f94b7927771fe84076f9b7143d57a26f2a43 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dtsi @@ -141,3 +141,11 @@ extcon = <&smb1381_charger>; vbus_dwc3-supply = <&smb138x_vbus>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi index 16f933f687ce77a5fab3a504283a739c7f608917..d447724fb66abb1c66d72bf18329d63f3b59d46b 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-cdp.dtsi @@ -36,11 +36,3 @@ /delete-property/ qcom,devfreq,freq-table; /delete-property/ cd-gpios; }; - -&soc { - bluetooth: bt_qca6174 { - compatible = "qca,qca6174"; - qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ - qca,bt-vdd-pa-supply = <&vreg_wlan>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi index 252fb04d294075c3c306632e96c8657121ae70f7..b60225ac8d56f2d2cc2b8fd230fa6163d5f8adca 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-dualwifi-mtp.dtsi @@ -36,11 +36,3 @@ /delete-property/ qcom,devfreq,freq-table; /delete-property/ cd-gpios; }; - -&soc { - bluetooth: bt_qca6174 { - compatible = "qca,qca6174"; - qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ - qca,bt-vdd-pa-supply = <&vreg_wlan>; - }; -}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..0c2181431c5ad37cfcd96702f53e9f417ed2b6c4 --- /dev/null +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-memory-256.dtsi @@ -0,0 +1,19 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&peripheral2_mem { + reg = <0x8fe00000 0x200000>; +}; + +&mss_mem { + reg = <0x87000000 0x8300000>; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts index 2377d79cd5b8ac59a38fad855f8b0db0567f8e29..a774c8bcea34448c0b907f8fa98c35138270ce5e 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,mtp"; qcom,board-id = <8 0x0>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi index 741203123468777eb8e45eda6a707d2ce6a2b49a..297af522e60f64cc9ee2012598047a4e88977f00 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp-256.dtsi @@ -11,6 +11,7 @@ */ #include "sdxpoorwills-mtp.dtsi" +#include "sdxpoorwills-memory-256.dtsi" &soc { vreg_sd_mmc: vreg_sd_mmc { @@ -21,3 +22,11 @@ &sdhc_1 { cd-gpios = <&tlmm 21 0x1>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts index 3ae5b2c82df8926e3d321f7bf3ed434cdf25ac0f..a383f3e237ba3510580c16cce4f0379a9ba6206d 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts @@ -24,3 +24,7 @@ &qcom_seecom { status = "okay"; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi index ef1150ac27343800cbfdd8bcf45774f245ec7ae1..a6d2463ead269c036f29d8b3ff7b31d71935ae77 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dtsi @@ -141,3 +141,11 @@ extcon = <&smb1381_charger>; vbus_dwc3-supply = <&smb138x_vbus>; }; + +&soc { + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&pmxpoorwills_gpios 4 0>; /* BT_EN */ + qca,bt-vdd-pa-supply = <&vreg_wlan>; + }; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts index cbbf585bea9433a72745293e59864266ac2e4b2c..d23275e7ad9879994ee667a682a2003152f32617 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,cdp"; qcom,board-id = <1 0x1>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts index 2a2e496fbc219515684fcb31f6e8adfe9fe77891..521d948f6428ca12d5c2cb2981b21c86623f25c0 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dts @@ -21,3 +21,6 @@ qcom,board-id = <1 0x106>; }; +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts index 6b6aab50eba4990bb09f1651b6a310d1cea6bce9..236ce73e46f29e07062fc923025a2cfad9d34db3 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,mtp"; qcom,board-id = <8 0x1>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts index 8c223489fe3a9ec565382b8c66a9883065ee9c13..11c4e62749bacdd163cc72b33ceb6e4571f5039c 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,mtp"; qcom,board-id = <8 0x105>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi index e939bd2edab04b1b1815e4b61356fe9ab2b48901..19072090568bd369c9dd3314693b49fcd32fe0fe 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie.dtsi @@ -143,6 +143,26 @@ qcom,cpl-timeout = <0x2>; + qcom,smmu-sid-base = <0x00A0>; + + iommu-map = <0x0 &apps_smmu 0x00A0 0x1>, + <0x100 &apps_smmu 0x00A1 0x1>, + <0x200 &apps_smmu 0x00A2 0x1>, + <0x300 &apps_smmu 0x00A3 0x1>, + <0x400 &apps_smmu 0x00A4 0x1>, + <0x500 &apps_smmu 0x00A5 0x1>, + <0x600 &apps_smmu 0x00A6 0x1>, + <0x700 &apps_smmu 0x00A7 0x1>, + <0x800 &apps_smmu 0x00A8 0x1>, + <0x900 &apps_smmu 0x00A9 0x1>, + <0xa00 &apps_smmu 0x00AA 0x1>, + <0xb00 &apps_smmu 0x00AB 0x1>, + <0xc00 &apps_smmu 0x00AC 0x1>, + <0xd00 &apps_smmu 0x00AD 0x1>, + <0xe00 &apps_smmu 0x00AE 0x1>, + <0xf00 &apps_smmu 0x00AF 0x1>; + + qcom,boot-option = <0x1>; linux,pci-domain = <0>; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts index 775be9636262e1cc52beb0f0ccdd43e1e27b54b7..f0363c08935de2c074e9fc87acc28d342e055fd5 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-ttp.dts @@ -20,3 +20,7 @@ "qcom,sdxpoorwills", "qcom,ttp"; qcom,board-id = <30 0x100>; }; + +&blsp1_uart2b_hs { + status = "okay"; +}; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 2014885f81cf384ec596d52271d2e2d68810aff0..61363fe4c8e173bef52927be2715897a6f182644 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -36,7 +36,7 @@ peripheral2_mem: peripheral2_region@8fe00000 { compatible = "removed-dma-pool"; no-map; - reg = <0x8fe00000 0x200000>; + reg = <0x8fe00000 0xe00000>; label = "peripheral2_mem"; }; @@ -65,7 +65,7 @@ mss_mem: mss_region@87400000 { compatible = "removed-dma-pool"; no-map; - reg = <0x87400000 0x8300000>; + reg = <0x87000000 0x8700000>; label = "mss_mem"; }; @@ -951,24 +951,24 @@ , /* SVS2 */ - , - , - , - , + , + , + , + , , /* SVS */ - , - , - , - , + , + , + , + , , /* NOMINAL */ - , - , - , - , + , + , + , + , , /* TURBO */ @@ -1288,6 +1288,9 @@ <45 512 98572 655360>, <1 512 98572 1600000>, /* Upto 800 Mbps */ <45 512 207108 1146880>, <1 512 207108 3124992>; + + qcom,wlan-smmu-iova-address = <0x10000000 0x10000000>; + qcom,wlan-smmu-iova-ipa = <0x20000000 0x10000>; }; cnss_sdio: qcom,cnss_sdio { @@ -1343,9 +1346,9 @@ qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = <98 512 0 0>, <1 781 0 0>, /* No vote */ - <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ - <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ - <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ + <98 512 2500 0>, <1 781 0 40000>, /* 10Mbps vote */ + <98 512 25000 0>, <1 781 0 40000>, /* 100Mbps vote */ + <98 512 250000 0>, <1 781 0 40000>; /* 1000Mbps vote */ qcom,bus-vector-names = "0", "10", "100", "1000"; clocks = <&clock_gcc GCC_ETH_AXI_CLK>, <&clock_gcc GCC_ETH_PTP_CLK>, diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index d907a0dc0c25a1e8faba6f7dd7aab5b09e1af06b..3f8ba5f5879ff70aac6fb871d9feca8a89e10783 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -63,6 +63,7 @@ CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y CONFIG_PM_WAKELOCKS=y @@ -230,6 +231,7 @@ CONFIG_BLK_DEV_DM=y CONFIG_DM_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y @@ -257,6 +259,7 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y +CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y CONFIG_DIAG_USES_SMD=y @@ -422,6 +425,9 @@ CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_EVENT_TIMER=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_BAM_DMUX=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_CNSS_CRYPTO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y @@ -470,4 +476,9 @@ CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index a87599f26d8dd163ef65e9af82a8f1f252111741..009ead21b860191ddd69371ef2229312cdb4f3fe 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -460,6 +460,9 @@ CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_BAM_DMUX=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y CONFIG_CNSS_CRYPTO=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_IIO=y diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 3094af9b708a6a072a79f961ebed89c80a55b25d..0e56f7ff9a9467e4f713c2235053124e303004cc 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -448,6 +448,7 @@ CONFIG_PWM=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y CONFIG_STM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 2e545d8d18cf93f98b1c168eb28f5bb0b0a2740a..8351322eb859312e6d4547895aa9073bda73646e 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -440,6 +440,7 @@ CONFIG_PWM=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDER_IPC_32BIT=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y @@ -462,9 +463,7 @@ CONFIG_DEBUG_INFO=y CONFIG_FRAME_WARN=2048 CONFIG_PAGE_OWNER=y CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y -CONFIG_DEBUG_PAGEALLOC=y CONFIG_SLUB_DEBUG_PANIC_ON=y -CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y CONFIG_LOCKUP_DETECTOR=y diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 3747ca39cc1fafb2aface3b87dd0685509f98822..e9a52377cf96f88c3db3beffdee62ac412b4d5c5 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -104,6 +104,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -115,6 +116,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -585,6 +587,7 @@ CONFIG_IIO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_SHOW_RESUME_IRQ=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -638,6 +641,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index a33bdbdd8f8c93407dad24f5d10314f26251e079..4a85408147e842aee43350fcd65bbb9e269a2461 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -108,6 +108,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -119,6 +120,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -705,6 +707,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index fca07a10e3baf34175c2ceb4b62eddf4fd72d85b..344ab3d60f51c0066798c7e25b588bd90e0d4eab 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -102,6 +102,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -113,6 +114,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -303,6 +305,7 @@ CONFIG_USB_USBNET=y # CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_QCA402X=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -310,10 +313,14 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_GT9XX_v28=y +CONFIG_TOUCHSCREEN_GT9XX_UPDATE=y +CONFIG_TOUCHSCREEN_GT9XX_TOOL=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y CONFIG_HMX_DB=y +CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y @@ -504,6 +511,7 @@ CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y # CONFIG_PWRSEQ_EMMC is not set # CONFIG_PWRSEQ_SIMPLE is not set +CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 @@ -647,6 +655,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 690faf2296f0462fc20eedd72808531aa37cf182..ff0a8a21a8cceb0f404b0a2dd2697244b731b9d2 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -106,6 +106,7 @@ CONFIG_IP_MULTIPLE_TABLES=y CONFIG_IP_ROUTE_VERBOSE=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPVTI=y CONFIG_INET_AH=y CONFIG_INET_ESP=y CONFIG_INET_IPCOMP=y @@ -117,6 +118,7 @@ CONFIG_INET6_AH=y CONFIG_INET6_ESP=y CONFIG_INET6_IPCOMP=y CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y CONFIG_IPV6_MULTIPLE_TABLES=y CONFIG_IPV6_SUBTREES=y CONFIG_NETFILTER=y @@ -308,6 +310,7 @@ CONFIG_USB_USBNET=y # CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y +CONFIG_QCA402X=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set @@ -315,10 +318,14 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_GT9XX_v28=y +CONFIG_TOUCHSCREEN_GT9XX_UPDATE=y +CONFIG_TOUCHSCREEN_GT9XX_TOOL=y CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y CONFIG_TOUCHSCREEN_HIMAX_I2C=y CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y CONFIG_HMX_DB=y +CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y @@ -513,6 +520,7 @@ CONFIG_MMC_PERF_PROFILING=y # CONFIG_PWRSEQ_EMMC is not set # CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_EMBEDDED_SDIO=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 @@ -653,7 +661,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_OBJECTS_WORK=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y @@ -711,6 +718,7 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig index 2fda0e2d1967636aa87415b4681fb4c8cac9f930..949b279c504aa897f8bceb8ad688f8d8a8533852 100644 --- a/arch/arm/configs/sdm670_defconfig +++ b/arch/arm/configs/sdm670_defconfig @@ -63,6 +63,8 @@ CONFIG_NR_CPUS=8 CONFIG_ARM_PSCI=y CONFIG_PREEMPT=y CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_ARM_MODULE_PLTS=y CONFIG_CLEANCACHE=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y @@ -236,6 +238,7 @@ CONFIG_RFKILL=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_AQT_REGMAP=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y @@ -297,6 +300,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_LEGACY_PTYS is not set CONFIG_SERIAL_MSM_GENI=y CONFIG_SERIAL_MSM_GENI_CONSOLE=y +CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y CONFIG_MSM_ADSPRPC=y @@ -312,6 +316,9 @@ CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y CONFIG_PINCTRL_SDM670=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_SUPPLY=y CONFIG_QPNP_FG_GEN3=y CONFIG_SMB1355_SLAVE_CHARGER=y @@ -363,6 +370,7 @@ CONFIG_LOGO=y # CONFIG_LOGO_LINUX_VGA16 is not set CONFIG_SOUND=y CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y @@ -427,6 +435,8 @@ CONFIG_EDAC_MM_EDAC=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_QCOM_GPI_DMA_DEBUG=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index d5930a7c48e1f1b1788187592a82466b0bf48908..e1fed15a3a366faa1b98ea5ef73064043fe490cc 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -1,4 +1,5 @@ CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y @@ -41,6 +42,9 @@ CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index f5abbb436d2cd8a0cd752cbd04a3ef8b3ffbfd8e..54072ccd3a9e44da7018bbee6a951dbdb0f35878 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -1,4 +1,5 @@ CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y @@ -43,6 +44,9 @@ CONFIG_VFP=y CONFIG_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h index b62eaeb147aa9a0b8caa73bf96a73a1d02e5f708..174346bcdc34d3de63df88a72b7aa61f52c1ff83 100644 --- a/arch/arm/include/asm/cputype.h +++ b/arch/arm/include/asm/cputype.h @@ -76,6 +76,8 @@ #define ARM_CPU_PART_CORTEX_A12 0x4100c0d0 #define ARM_CPU_PART_CORTEX_A17 0x4100c0e0 #define ARM_CPU_PART_CORTEX_A15 0x4100c0f0 +#define ARM_CPU_PART_CORTEX_A73 0x4100d090 +#define ARM_CPU_PART_KRYO2XX_GOLD 0x51008000 #define ARM_CPU_PART_MASK 0xff00fff0 /* DEC implemented cores */ diff --git a/arch/arm/include/asm/kgdb.h b/arch/arm/include/asm/kgdb.h index 0a9d5dd932941a1f0635574904ecd47259b87295..6949c7d4481c46057161415e8f2c7a8a3d0aac04 100644 --- a/arch/arm/include/asm/kgdb.h +++ b/arch/arm/include/asm/kgdb.h @@ -76,7 +76,7 @@ extern int kgdb_fault_expected; #define KGDB_MAX_NO_CPUS 1 #define BUFMAX 400 -#define NUMREGBYTES (DBG_MAX_REG_NUM << 2) +#define NUMREGBYTES (GDB_MAX_REGS << 2) #define NUMCRITREGBYTES (32 << 2) #define _R0 0 diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index 3cc14dd8587c097746dc7c8138be18f64b5ace94..0c835ee0f04b0e6a61cfb4468eca4d8ac1f049ce 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h @@ -24,6 +24,18 @@ void __check_vmalloc_seq(struct mm_struct *mm); +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +void arm_init_bp_hardening(void); +void arm_apply_bp_hardening(void); +#else +static inline void arm_init_bp_hardening(void) +{ +} +static inline void arm_apply_bp_hardening(void) +{ +} +#endif + #ifdef CONFIG_CPU_HAS_ASID void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk); @@ -63,8 +75,10 @@ static inline void check_and_switch_context(struct mm_struct *mm, * finish_arch_post_lock_switch() call. */ mm->context.switch_pending = 1; - else + else { + arm_apply_bp_hardening(); cpu_switch_mm(mm->pgd, mm); + } } #ifndef MODULE diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c index 4f14b5ce6535f7a19215660ebb4b3e62bd6ea5ed..c2b440b05692a12901f1ec289d205b2b0168fb71 100644 --- a/arch/arm/kernel/module.c +++ b/arch/arm/kernel/module.c @@ -40,8 +40,15 @@ #ifdef CONFIG_MMU void *module_alloc(unsigned long size) { - void *p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, - GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, + gfp_t gfp_mask = GFP_KERNEL; + void *p; + + /* Silence the initial allocation */ + if (IS_ENABLED(CONFIG_ARM_MODULE_PLTS)) + gfp_mask |= __GFP_NOWARN; + + p = __vmalloc_node_range(size, 1, MODULES_VADDR, MODULES_END, + gfp_mask, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, __builtin_return_address(0)); if (!IS_ENABLED(CONFIG_ARM_MODULE_PLTS) || p) return p; diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 38ad8b956c6becb5ef8e0e6d6d0170bfe8397c8a..b876193c9b2641f645ad1b69068c70c97e7722ab 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -150,17 +150,6 @@ static void show_extra_register_data(struct pt_regs *regs, int nbytes) show_data(regs->ARM_sp - nbytes, nbytes * 2, "SP"); show_data(regs->ARM_ip - nbytes, nbytes * 2, "IP"); show_data(regs->ARM_fp - nbytes, nbytes * 2, "FP"); - show_data(regs->ARM_r0 - nbytes, nbytes * 2, "R0"); - show_data(regs->ARM_r1 - nbytes, nbytes * 2, "R1"); - show_data(regs->ARM_r2 - nbytes, nbytes * 2, "R2"); - show_data(regs->ARM_r3 - nbytes, nbytes * 2, "R3"); - show_data(regs->ARM_r4 - nbytes, nbytes * 2, "R4"); - show_data(regs->ARM_r5 - nbytes, nbytes * 2, "R5"); - show_data(regs->ARM_r6 - nbytes, nbytes * 2, "R6"); - show_data(regs->ARM_r7 - nbytes, nbytes * 2, "R7"); - show_data(regs->ARM_r8 - nbytes, nbytes * 2, "R8"); - show_data(regs->ARM_r9 - nbytes, nbytes * 2, "R9"); - show_data(regs->ARM_r10 - nbytes, nbytes * 2, "R10"); set_fs(fs); } @@ -256,7 +245,8 @@ void __show_regs(struct pt_regs *regs) } #endif - show_extra_register_data(regs, 128); + if (!user_mode(regs)) + show_extra_register_data(regs, 128); } void show_regs(struct pt_regs * regs) diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 09dd8ff379cb83e3311c45cd990627aee5928f45..4f451ce921648d8bcefd7183dab8f777ef86bb26 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c @@ -243,6 +243,40 @@ static const char *proc_arch[] = { "?(17)", }; +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +struct arm_btbinv { + void (*apply_bp_hardening)(void); +}; +static DEFINE_PER_CPU_READ_MOSTLY(struct arm_btbinv, arm_btbinv); + +static void arm_a73_apply_bp_hardening(void) +{ + asm("mov r2, #0"); + asm("mcr p15, 0, r2, c7, c5, 6"); +} + +void arm_apply_bp_hardening(void) +{ + if (this_cpu_ptr(&arm_btbinv)->apply_bp_hardening) + this_cpu_ptr(&arm_btbinv)->apply_bp_hardening(); +} + +void arm_init_bp_hardening(void) +{ + switch (read_cpuid_part()) { + case ARM_CPU_PART_CORTEX_A73: + case ARM_CPU_PART_KRYO2XX_GOLD: + per_cpu(arm_btbinv.apply_bp_hardening, raw_smp_processor_id()) + = arm_a73_apply_bp_hardening; + break; + default: + per_cpu(arm_btbinv.apply_bp_hardening, raw_smp_processor_id()) + = NULL; + break; + } +} +#endif + #ifdef CONFIG_CPU_V7M static int __get_cpu_architecture(void) { @@ -685,6 +719,7 @@ static void __init setup_processor(void) * types. The linker builds this table for us from the * entries in arch/arm/mm/proc-*.S */ + arm_init_bp_hardening(); list = lookup_processor_type(read_cpuid_id()); if (!list) { pr_err("CPU configuration botched (ID %08x), unable to continue.\n", diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 3b2f4ce1790c7db6a7aa7fb597ab2d78343bb3a7..0169acb6d72a0e4099e370e7bb7f10b70e1b6434 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -47,6 +47,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include @@ -359,6 +360,7 @@ asmlinkage void secondary_start_kernel(void) * The identity mapping is uncached (strongly ordered), so * switch away from it before attempting any exclusive accesses. */ + arm_init_bp_hardening(); cpu_switch_mm(mm->pgd, mm); local_flush_bp_all(); enter_lazy_tlb(mm, current); diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index d96863ed55bc3effc834d85042eb790c0f14258f..7ca91802b274e6e64a6bd4748cc77d3c148a9b4c 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -64,6 +64,7 @@ config ARCH_MSM8953 select HAVE_CLK select HAVE_CLK_PREPARE select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS config ARCH_MSM8953_BOOT_ORDERING bool "Enable support for MSM8953 device boot ordering" @@ -160,6 +161,7 @@ config ARCH_SDM450 select HAVE_CLK select HAVE_CLK_PREPARE select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS config ARCH_SDM632 bool "Enable Support for Qualcomm Technologies Inc. SDM632" @@ -176,6 +178,7 @@ config ARCH_SDM632 select SND_HWDEP select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS config ARCH_SDM670 bool "Enable Support for SDM670" diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c1799dd1d0d99a413df2dc9ce7ddb69189723dad..1a5acee44c4f73a7cd4247c0a7c864efd0aacc6a 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -1068,3 +1068,20 @@ config DEBUG_ALIGN_RODATA additional section-aligned split of rodata from kernel text so it can be made explicitly non-executable. This padding may waste memory space to gain the additional protection. + +config HARDEN_BRANCH_PREDICTOR + bool "Harden the branch predictor against aliasing attacks" if EXPERT + default y + help + Speculation attacks against some high-performance processors rely on + being able to manipulate the branch predictor for a victim context by + executing aliasing branches in the attacker context. Such attacks + can be partially mitigated against by clearing internal branch + predictor state and limiting the prediction logic in some situations. + + This config option will take CPU-specific actions to harden the + branch predictor against aliasing attacks and may rely on specific + instruction sequences or control bits being set by the system + firmware. + + If unsure, say Y. diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c index c8c8b9ed02e09b57a79bee1ab5db9c337be0d338..f1874392c8751697c318a1471f7ead82290f3f14 100644 --- a/arch/arm/mm/context.c +++ b/arch/arm/mm/context.c @@ -276,5 +276,6 @@ void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk) raw_spin_unlock_irqrestore(&cpu_asid_lock, flags); switch_mm_fastpath: + arm_apply_bp_hardening(); cpu_switch_mm(mm->pgd, mm); } diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index e346cf3fb947479ea85ebe94b750666cf047650b..a8f8d4610baa34e931e020448add898c0330e50c 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -2483,7 +2483,10 @@ static int __arm_iommu_attach_device(struct device *dev, { int err; - err = iommu_attach_device(mapping->domain, dev); + if (!dev->iommu_group) + return -EINVAL; + + err = iommu_attach_group(mapping->domain, dev->iommu_group); if (err) return err; diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 203728dfac97c53cfe38e898dc744d9dec410c22..7fa65aa1aabfaa73493b53dd918a9154e527d5c5 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c @@ -265,6 +265,7 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, unsigned long addr; struct vm_struct *area; phys_addr_t paddr = __pfn_to_phys(pfn); + pgprot_t prot; #ifndef CONFIG_ARM_LPAE /* @@ -310,6 +311,12 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, addr = (unsigned long)area->addr; area->phys_addr = paddr; + prot = __pgprot(type->prot_pte); +#ifdef CONFIG_ARCH_MSM8953_SOC_SETTINGS + if (paddr >= MSM8953_TLMM_START_ADDR && + paddr <= MSM8953_TLMM_END_ADDR) + prot = pgprot_stronglyordered(type->prot_pte); +#endif #if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE) if (DOMAIN_IO == 0 && (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) || @@ -322,8 +329,7 @@ static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, err = remap_area_sections(addr, pfn, size, type); } else #endif - err = ioremap_page_range(addr, addr + size, paddr, - __pgprot(type->prot_pte)); + err = ioremap_page_range(addr, addr + size, paddr, prot); if (err) { vunmap((void *)addr); diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index f72ce300916022c2d84f032c6b1d53a5a7f6de2c..ac71d3916ed875b0e420e6ade8fc51e0af031c3a 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -554,6 +554,16 @@ config ARM64_64K_PAGES endchoice +config ARCH_MSM8953_SOC_SETTINGS + bool "Enable MSM8953 SOC settings" + depends on ARCH_MSM8953 + help + Enable MSM8953 SOC related settings, these generic MSM8953 + related settings are required for some of CPUSS sub-system + functionality. + + If you are not sure what to do, select 'N' here. + choice prompt "Virtual address space size" default ARM64_VA_BITS_39 if ARM64_4K_PAGES diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index a92f51149a0b2ac7b5f4fda4003d2c367f2bc1ec..4c013ad501899b2da656be28435ea8209719c666 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -152,6 +152,7 @@ config ARCH_MSM8953 depends on ARCH_QCOM select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS help This enables support for the MSM8953 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. @@ -179,6 +180,7 @@ config ARCH_SDM450 depends on ARCH_QCOM select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS help This enables support for the sdm450 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. @@ -188,6 +190,7 @@ config ARCH_SDM632 depends on ARCH_QCOM select CPU_FREQ_QCOM select COMMON_CLK_MSM + select ARCH_MSM8953_SOC_SETTINGS help This enables support for the sdm632 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index e4d62009dd2e445612237090c480186293dc9aa1..15f53ee7b1471ac9555c16b6c7c2f88e9bee2796 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -150,6 +150,7 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) qcs605-mtp-overlay.dtbo \ qcs605-360camera-overlay.dtbo \ qcs605-external-codec-mtp-overlay.dtbo \ + qcs605-lc-ipcamera-overlay.dtbo \ qcs605-lc-mtp-overlay.dtbo \ qcs605-lc-cdp-overlay.dtbo \ sdm710-cdp-overlay.dtbo \ @@ -173,7 +174,18 @@ ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) sdm710-tasha-codec-cdp-overlay.dtbo \ sdm710-pm660a-tasha-codec-cdp-overlay.dtbo \ sdm710-aqt1000-cdp-overlay.dtbo \ - sdm710-pm660a-aqt1000-cdp-overlay.dtbo + sdm710-pm660a-aqt1000-cdp-overlay.dtbo \ + sxr1130-cdp-overlay.dtbo \ + sxr1130-external-codec-cdp-overlay.dtbo \ + sxr1130-mtp-overlay.dtbo \ + sxr1130-external-codec-mtp-overlay.dtbo \ + sxr1130-external-codec-pm660a-mtp-overlay.dtbo \ + sxr1130-pm660a-mtp-overlay.dtbo \ + sxr1130-usbc-external-codec-cdp-overlay.dtbo \ + sxr1130-usbc-external-codec-mtp-overlay.dtbo \ + sxr1130-usbc-external-codec-pm660a-mtp-overlay.dtbo \ + sxr1130-usbc-mtp-overlay.dtbo \ + sxr1130-usbc-pm660a-mtp-overlay.dtbo sdm670-cdp-overlay.dtbo-base := sdm670.dtb sdm670-mtp-overlay.dtbo-base := sdm670.dtb @@ -211,6 +223,7 @@ qcs605-cdp-overlay.dtbo-base := qcs605.dtb qcs605-mtp-overlay.dtbo-base := qcs605.dtb qcs605-external-codec-mtp-overlay.dtbo-base := qcs605.dtb qcs605-lc-mtp-overlay.dtbo-base := qcs605-lc.dtb +qcs605-lc-ipcamera-overlay.dtbo-base := qcs605-lc.dtb qcs605-360camera-overlay.dtbo-base := qcs605.dtb qcs605-lc-cdp-overlay.dtbo-base := qcs605-lc-cdp-base.dtb sdm710-cdp-overlay.dtbo-base := sdm710.dtb @@ -235,6 +248,17 @@ sdm710-tasha-codec-cdp-overlay.dtbo-base := sdm710.dtb sdm710-pm660a-tasha-codec-cdp-overlay.dtbo-base := sdm710.dtb sdm710-aqt1000-cdp-overlay.dtbo-base := sdm710.dtb sdm710-pm660a-aqt1000-cdp-overlay.dtbo-base := sdm710.dtb +sxr1130-cdp-overlay.dtbo-base := sxr1130.dtb +sxr1130-external-codec-cdp-overlay.dtbo-base := sxr1130.dtb +sxr1130-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-external-codec-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-external-codec-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-external-codec-cdp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-external-codec-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-external-codec-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-mtp-overlay.dtbo-base := sxr1130.dtb +sxr1130-usbc-pm660a-mtp-overlay.dtbo-base := sxr1130.dtb else dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ @@ -271,6 +295,7 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ qcs605-mtp.dtb \ qcs605-cdp.dtb \ qcs605-external-codec-mtp.dtb \ + qcs605-lc-ipcamera.dtb \ qcs605-lc-mtp.dtb \ qcs605-lc-cdp.dtb \ sdm710-mtp.dtb \ @@ -292,7 +317,18 @@ dtb-$(CONFIG_ARCH_SDM670) += sdm670-rumi.dtb \ sdm710-usbc-pm660a-cdp.dtb \ sdm710-usbc-pm660a-mtp.dtb \ sdm710-tasha-codec-cdp.dtb \ - sdm710-pm660a-tasha-codec-cdp.dtb + sdm710-pm660a-tasha-codec-cdp.dtb \ + sxr1130-cdp.dtb \ + sxr1130-external-codec-cdp.dtb \ + sxr1130-mtp.dtb \ + sxr1130-external-codec-mtp.dtb \ + sxr1130-external-codec-pm660a-mtp.dtb \ + sxr1130-pm660a-mtp.dtb \ + sxr1130-usbc-external-codec-cdp.dtb \ + sxr1130-usbc-external-codec-mtp.dtb \ + sxr1130-usbc-external-codec-pm660a-mtp.dtb \ + sxr1130-usbc-mtp.dtb \ + sxr1130-usbc-pm660a-mtp.dtb endif ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) @@ -301,7 +337,10 @@ dtbo-$(CONFIG_ARCH_MSM8917) += msm8917-mtp-overlay.dtbo \ msm8917-cdp-overlay.dtbo \ msm8917-cdp-ext-codec-overlay.dtbo \ msm8917-cdp-ml-touch-overlay.dtbo \ - msm8917-rcm-overlay.dtbo + msm8917-rcm-overlay.dtbo \ + apq8017-mtp-overlay.dtbo \ + apq8017-cdp-overlay.dtbo \ + apq8017-cdp-wcd-rome-overlay.dtbo dtbo-$(CONFIG_ARCH_MSM8953) += msm8953-mtp-overlay.dtbo \ msm8953-cdp-overlay.dtbo \ @@ -496,11 +535,13 @@ dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb \ msm8917-pmi8940-cdp.dtb \ msm8917-pmi8940-rcm.dtb -dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \ - apq8009w-bg-wtp-v2.dtb \ - apq8009w-bg-alpha.dtb \ +dtb-$(CONFIG_ARCH_MSM8909) += sdw3100-msm8909w-wtp.dtb \ + sdw3100-apq8009w-wtp.dtb \ + sdw3100-apq8009w-alpha.dtb \ apq8009-mtp-wcd9326-refboard.dtb \ apq8009-robot-som-refboard.dtb \ + apq8009-robot-rome-refboard.dtb \ + apq8009-robot-pronto-refboard.dtb \ apq8009-dragon.dtb \ apq8009-lat-v1.0.dtb \ sdw3100-msm8909w-1gb-wtp.dtb diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts new file mode 100644 index 0000000000000000000000000000000000000000..0ac8a311649c29f36edda88c1013216485231dda --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-pronto-refboard.dts @@ -0,0 +1,380 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8909-mtp.dtsi" +#include "8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" +#include "apq8009-memory.dtsi" +#include +#include "msm8909-pm8916-camera.dtsi" +#include "msm8909-pm8916-camera-sensor-robot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Robot-pronto RefBoard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0xE>; +}; + +&audio_codec_mtp { + status = "disabled"; +}; + +&pm8916_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + status = "okay"; + }; + }; +}; + +&msm_gpio { + hsuart_active: default { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_vbus_detect: usb_vbus_detect { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_id_detect: usb_id_detect { + mux { + pins = "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio110"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&soc { + ext_codec: sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-gpios = + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-0 = <&cross_conn_det_sus>; + pinctrl-1 = <&cross_conn_det_act>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>; + + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + i2c@78b9000 { + synaptics@20 { + status = "disabled"; + }; + }; + + blsp1_uart2_hs: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &msm_gpio 21 0>; + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart2_hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "ok"; + }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + **/ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&msm_gpio>; + interrupts = <97 0>; + interrupt-names = "vbus_det_irq"; + pinctrl-names = "usb_vbus_detect", "usb_id_detect"; + pinctrl-0 = <&usb_vbus_detect>; + pinctrl-1 = <&usb_id_detect>; + qcom,gpio-mode-sel = <&msm_gpio 97 0>; + qcom,id-det-gpio = <&msm_gpio 110 0>; + qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "okay"; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + }; + }; + + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active + &pri_mi2s_dout_active &pri_mi2s_din_active>; + pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep + &pri_mi2s_dout_sleep &pri_mi2s_din_sleep>; + }; + + cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; + + wcd_rst_gpio: wcd_gpio_ctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&wcnss { + status = "disabled"; +}; + +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + +&i2c_4 { + status= "okay"; + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <58 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,charging-disabled; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4200>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + status= "okay"; + smb1360_vbus: qcom,smb1360-vbus { + regulator-name = "qcom,smb1360-vbus"; + }; + }; +}; + +&usb_otg { + interrupts = <0 134 0>, <0 140 0>, <0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + qcom,hsusb-otg-mode = <3>; + vbus_otg-supply = <&smb1360_vbus>; + extcon = <&smb1360_otg_supply>; +}; + +&mdss_fb0 { + status = "disabled"; + /delete-node/ qcom,cont-splash-memory; +}; + +&mdss_mdp { + status = "disabled"; +}; + +&mdss_dsi0_pll { + status = "disabled"; +}; + +&mdss_dsi0 { + status = "disabled"; +}; + +&i2c_1 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&i2c_5 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + +&blsp1_uart2_hs { + status = "disabled"; +}; + +/delete-node/ &cont_splash_mem; diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts new file mode 100644 index 0000000000000000000000000000000000000000..66070b7bb42644d275fd1fc16e246b49c18efd1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-rome-refboard.dts @@ -0,0 +1,380 @@ +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8909-mtp.dtsi" +#include "8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" +#include "apq8009-memory.dtsi" +#include +#include "msm8909-pm8916-camera.dtsi" +#include "msm8909-pm8916-camera-sensor-robot.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Robot-rome RefBoard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id= <8 0x10>; +}; + +&audio_codec_mtp { + status = "disabled"; +}; + +&pm8916_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + status = "okay"; + }; + }; +}; + +&msm_gpio { + hsuart_active: default { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <16>; + bias-disable; + }; + }; + + hsuart_sleep: sleep { + mux { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + function = "blsp_uart2"; + }; + + config { + pins = "gpio20", "gpio21", "gpio111", "gpio112"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_vbus_detect: usb_vbus_detect { + mux { + pins = "gpio97"; + function = "gpio"; + }; + + config { + pins = "gpio97"; + drive-strength = <2>; + bias-disable; + }; + }; + + usb_id_detect: usb_id_detect { + mux { + pins = "gpio110"; + function = "gpio"; + }; + + config { + pins = "gpio110"; + drive-strength = <2>; + bias-pull-up; + }; + }; +}; + +&soc { + ext_codec: sound-9335 { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-gpios = + "us_eu_gpio"; + qcom,pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-names = + "all_off", + "us_eu_gpio_act"; + pinctrl-0 = <&cross_conn_det_sus>; + pinctrl-1 = <&cross_conn_det_act>; + qcom,pri-mi2s-gpios = <&cdc_pri_mi2s_gpios>; + qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>; + + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; + }; + + i2c@78b9000 { + synaptics@20 { + status = "disabled"; + }; + }; + + blsp1_uart2_hs: uart@78b0000 { + compatible = "qcom,msm-hsuart-v14"; + reg = <0x78b0000 0x200>, + <0x7884000 0x1f000>; + reg-names = "core_mem", "bam_mem"; + interrupt-names = "core_irq", "bam_irq", "wakeup_irq"; + #address-cells = <0>; + interrupt-parent = <&blsp1_uart2_hs>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 108 0 + 1 &intc 0 238 0 + 2 &msm_gpio 21 0>; + qcom,inject-rx-on-wakeup; + qcom,rx-char-to-inject = <0xfd>; + qcom,master-id = <86>; + clock-names = "core_clk", "iface_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_uart2_apps_clk>, + <&clock_gcc clk_gcc_blsp1_ahb_clk>; + pinctrl-names = "sleep", "default"; + pinctrl-0 = <&hsuart_sleep>; + pinctrl-1 = <&hsuart_active>; + qcom,bam-tx-ep-pipe-index = <2>; + qcom,bam-rx-ep-pipe-index = <3>; + qcom,msm-bus,name = "blsp1_uart2_hs"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <86 512 0 0>, + <86 512 500 800>; + status = "ok"; + }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; + + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + **/ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; + + usb_detect: qcom,gpio-usbdetect { + compatible = "qcom,gpio-usbdetect"; + interrupt-parent = <&msm_gpio>; + interrupts = <97 0>; + interrupt-names = "vbus_det_irq"; + pinctrl-names = "usb_vbus_detect", "usb_id_detect"; + pinctrl-0 = <&usb_vbus_detect>; + pinctrl-1 = <&usb_id_detect>; + qcom,gpio-mode-sel = <&msm_gpio 97 0>; + qcom,id-det-gpio = <&msm_gpio 110 0>; + qcom,dpdm_switch_gpio = <&pm8916_gpios 3 0>; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "okay"; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + }; + }; + + cdc_pri_mi2s_gpios: msm_cdc_pinctrl_pri { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&pri_mi2s_active &pri_mi2s_ws_active + &pri_mi2s_dout_active &pri_mi2s_din_active>; + pinctrl-1 = <&pri_mi2s_sleep &pri_mi2s_ws_sleep + &pri_mi2s_dout_sleep &pri_mi2s_din_sleep>; + }; + + cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; + + wcd_rst_gpio: wcd_gpio_ctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&wcnss { + status = "disabled"; +}; + +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + +&i2c_4 { + status= "okay"; + smb1360_otg_supply: smb1360-chg-fg@14 { + compatible = "qcom,smb1360-chg-fg"; + reg = <0x14>; + interrupt-parent = <&msm_gpio>; + interrupts = <58 8>; + pinctrl-names = "default"; + pinctrl-0 = <&smb_int_default>; + qcom,charging-disabled; + qcom,empty-soc-disabled; + qcom,chg-inhibit-disabled; + qcom,float-voltage-mv = <4200>; + qcom,iterm-ma = <200>; + qcom,recharge-thresh-mv = <100>; + qcom,thermal-mitigation = <1500 700 600 0>; + status= "okay"; + smb1360_vbus: qcom,smb1360-vbus { + regulator-name = "qcom,smb1360-vbus"; + }; + }; +}; + +&usb_otg { + interrupts = <0 134 0>, <0 140 0>, <0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + qcom,hsusb-otg-mode = <3>; + vbus_otg-supply = <&smb1360_vbus>; + extcon = <&smb1360_otg_supply>; +}; + +&mdss_fb0 { + status = "disabled"; + /delete-node/ qcom,cont-splash-memory; +}; + +&mdss_mdp { + status = "disabled"; +}; + +&mdss_dsi0_pll { + status = "disabled"; +}; + +&mdss_dsi0 { + status = "disabled"; +}; + +&i2c_1 { + status = "disabled"; +}; + +&i2c_2 { + status = "disabled"; +}; + +&i2c_5 { + status = "disabled"; +}; + +&spi_0 { + status = "disabled"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + +&blsp1_uart2_hs { + status = "disabled"; +}; + +/delete-node/ &cont_splash_mem; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi b/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi index d83ae5c0e971fb6eee2dccbe11b8c26917e4a180..fef9f4528f17e1c7d5945f446c468a4416ea1866 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-memory.dtsi @@ -22,3 +22,14 @@ &peripheral_mem { reg = <0x0 0x8a300000 0x0 0x0600000>; }; + +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xa0000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts index 6c8bef4ffafa2268b8f593b97b04eca5f834100c..21e47bf556e806965016e820ed1159da46d9debf 100644 --- a/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/apq8017-cdp-overlay.dts @@ -19,6 +19,7 @@ / { model = "Qualcomm Technologies, Inc. APQ8017-CDP"; qcom,board-id = <1 0>; + qcom,msm-id = <307 0x0>; }; &mdss_fb0 { diff --git a/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts b/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts index 055c457733ee37ce17d3b51442ef29fbf902e90d..4f07399dfa157e6077c9744345bdc4a14f4ddd36 100644 --- a/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts +++ b/arch/arm64/boot/dts/qcom/apq8017-cdp-wcd-rome-overlay.dts @@ -21,6 +21,7 @@ model = "Qualcomm Technologies, Inc. APQ8017-CDP \ with WCD codec/Rome card"; qcom,board-id = <1 2>; + qcom,msm-id = <307 0x0>; }; &blsp1_uart1 { diff --git a/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts index 23bbb0f91189633548daaced60385c3ea0dc2656..0b958ee7cdfaab736fa1fb628f2f4037886f7ba7 100644 --- a/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/apq8017-mtp-overlay.dts @@ -19,6 +19,7 @@ / { model = "Qualcomm Technologies, Inc. APQ8017-MTP"; qcom,board-id = <8 0>; + qcom,msm-id = <307 0x0>; }; &blsp1_uart1 { diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts index 6c9c26698071e227da637b76565dbe05a4adae43..63a364addf9a15622bc63b113b240d3d5d604cca 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts @@ -25,3 +25,17 @@ &blsp2_uart0 { status = "okay"; }; + +&i2c_3 { + status = "okay"; + elan_ktf@10 { + compatible = "elan,ekth3500"; + reg = <0x10>; + vdd-supply = <&pm8953_l10>; + vccio-supply = <&pm8953_l6>; + interrupt-parent = <&tlmm>; + reset-gpio = <&tlmm 64 GPIO_ACTIVE_LOW>; + elan,irq-gpio = <&tlmm 65 0x2008>; + interrupts = <65 0x2>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts index ecc4fea1cb28f01095ee980b5cdc5411621c50e0..8b5dd2b00cfb4e5bd00beea45f3f654f784bdb08 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts @@ -25,3 +25,81 @@ &blsp2_uart0 { status = "okay"; }; + +&i2c_3 { + status = "okay"; + /delete-node/ himax_ts@48; + gt9xx-i2c@14 { + compatible = "goodix,gt9xx"; + status = "okay"; + reg = <0x14>; + vdd_ana-supply = <&pm8953_l10>; + vcc_i2c-supply = <&pm8953_l6>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + pinctrl-names = "gdix_ts_int_default", "gdix_ts_int_output_low", + "gdix_ts_int_output_high", "gdix_ts_int_input", + "gdix_ts_rst_default", "gdix_ts_rst_output_low", + "gdix_ts_rst_output_high", "gdix_ts_rst_input"; + pinctrl-0 = <&ts_int_default>; + pinctrl-1 = <&ts_int_output_low>; + pinctrl-2 = <&ts_int_output_high>; + pinctrl-3 = <&ts_int_input>; + pinctrl-4 = <&ts_rst_default>; + pinctrl-5 = <&ts_rst_output_low>; + pinctrl-6 = <&ts_rst_output_high>; + pinctrl-7 = <&ts_rst_input>; + + reset-gpios = <&tlmm 64 0x00>; + irq-gpios = <&tlmm 65 0x2008>; + irq-flags = <2>; + + touchscreen-max-id = <11>; + touchscreen-size-x = <1200>; + touchscreen-size-y = <1920>; + touchscreen-max-w = <1024>; + touchscreen-max-p = <1024>; + + goodix,type-a-report = <0>; + goodix,driver-send-cfg = <1>; + goodix,wakeup-with-reset = <0>; + goodix,resume-in-workqueue = <0>; + goodix,int-sync = <1>; + goodix,swap-x2y = <0>; + goodix,esd-protect = <1>; + goodix,pen-suppress-finger = <0>; + goodix,auto-update = <1>; + goodix,auto-update-cfg = <0>; + goodix,power-off-sleep = <0>; + + goodix,cfg-group0 = [ + 5A B0 04 80 07 0A 35 10 22 08 32 0D 50 3C 0A 04 + 01 01 00 B4 11 11 44 15 19 1B 14 95 35 FF 3A 3C + 39 13 00 00 00 98 03 1C 00 00 00 00 03 00 00 00 + 00 80 0A 37 46 40 E5 52 23 28 00 04 81 38 00 7F + 3B 00 7D 3E 00 7C 41 00 7A 44 0C 7A 00 50 33 50 + 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 + 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E + 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 + 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 + 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 + 07 06 05 04 03 02 01 00 08 01 + ]; + + goodix,cfg-group2 = [ + 5B B0 04 80 07 0A 35 10 22 08 32 0D 50 32 0A 04 + 01 01 00 B4 11 11 44 2B 31 36 28 95 35 FF 3E 40 + 39 13 00 00 00 DA 03 1C 00 00 00 00 03 00 00 00 + 00 80 0A 32 42 40 E5 52 23 28 00 04 7D 33 00 7D + 36 00 7E 39 00 7F 3C 00 80 40 0C 80 00 50 33 50 + 0B 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 55 00 01 00 00 02 00 00 00 + 1D 1C 1B 1A 19 18 17 16 15 14 13 12 11 10 0F 0E + 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 2A 29 + 28 27 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 + 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 + 07 06 05 04 03 02 01 00 81 01 + ]; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi index 5cf8ac06ff439cdab9abfd6967363d913abe149a..c682f58f0e1de1b43c81caa53e8ff8f157e03385 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi @@ -42,6 +42,7 @@ &i2c_3 { status = "okay"; + /delete-node/ focaltech@38; /delete-node/ himax_ts@48; focaltech_ts@38 { compatible = "focaltech,fts"; @@ -64,6 +65,7 @@ }; &wled { + qcom,cons-sync-write-delay-us = <1000>; qcom,led-strings-list = [00 01 02]; }; @@ -78,3 +80,19 @@ &camera2{ qcom,mount-angle = <90>; }; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8394d_kingdisplay_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + vdd-supply = <&pm8953_l17>; + vddio-supply = <&pm8953_l6>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 61 0>; + qcom,platform-bklight-en-gpio = <&tlmm 100 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index 90b1d4fad300e44be204602c7a048dab673de3a8..186d6ef93bd8c4fc5010fa710e3a909ad1d99fd5 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -123,6 +123,11 @@ qcom,rmnet-ipa { status = "disabled"; }; + + qcom,qca402x { + compatible = "qcom,qca402"; + endpoints = <1>; + }; }; &firmware { diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi index 5be35e72c7a937a8e86f6aae78fe57605c3b81a5..c9d716063a8205fbef6f19b60a752165a049de56 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi @@ -18,7 +18,7 @@ model = "Qualcomm Technologies, Inc. APQ 8953 Lite"; compatible = "qcom,apq8053"; qcom,msm-id = <304 0x0>; - interrupt-parent = <&intc>; + interrupt-parent = <&wakegic>; soc: soc { }; }; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..e065f002395fa3ac1fa67fd6c9f9915ad1acbd80 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi @@ -0,0 +1,157 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_hx83112a_truly_video: qcom,mdss_dsi_hx83112a_truly_video { + qcom,mdss-dsi-panel-name = + "hx83112a video mode dsi truly panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2160>; + qcom,mdss-dsi-h-front-porch = <42>; + qcom,mdss-dsi-h-back-porch = <42>; + qcom,mdss-dsi-h-pulse-width = <10>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <15>; + qcom,mdss-dsi-v-front-porch = <10>; + qcom,mdss-dsi-v-pulse-width = <3>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 83 11 2A + 39 01 00 00 00 00 09 B1 08 29 29 00 00 4F 54 + 33 + 39 01 00 00 00 00 11 B2 00 02 00 80 70 00 08 + 26 FC 01 00 03 15 A3 87 09 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 03 D2 2C 2C + 39 01 00 00 00 00 1C B4 01 CE 01 CE 01 CE 0A + CE 0A CE 0A CE 00 FF 00 FF 00 00 22 23 00 + 28 0A 13 14 00 8A + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0A B4 00 92 12 22 88 12 12 + 00 53 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 04 B6 82 82 E3 + 39 01 00 00 00 00 02 CC 08 + 39 01 00 00 00 00 2B D3 40 00 00 00 00 01 01 + 0A 0A 07 07 00 08 09 09 09 09 32 10 09 00 + 09 32 21 0A 00 0A 32 10 08 00 00 00 00 00 + 00 00 00 00 0B 08 82 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 09 D3 00 00 19 00 00 0A 00 + 81 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 31 D5 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 01 00 07 06 05 04 03 02 21 20 18 + 18 19 19 18 18 03 03 18 18 18 18 18 18 + 39 01 00 00 00 00 31 D6 18 18 18 18 18 18 18 + 18 31 31 30 30 2F 2F 31 31 30 30 2F 2F C0 + 18 40 40 02 03 04 05 06 07 00 01 20 21 18 + 18 18 18 19 19 20 20 18 18 18 18 18 18 + 39 01 00 00 00 00 19 D8 00 00 00 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 00 00 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 0D D8 AF FF FA AA BA AA AA + FF FA AA BA AA + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 19 D8 AA AA AA AA AA AA AA + AA AA AA AA AA AA AA AA AA AA AA AA AA AA + AA AA AA + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 18 E7 0E 0E 1E 6A 1D 6A 00 + 32 02 02 00 00 02 02 02 05 14 14 32 B9 23 + B9 08 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 0A E7 02 00 98 01 9A 0D A8 + 0E 01 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 1E E7 00 00 08 00 01 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 00 04 00 00 00 00 02 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 C1 01 + 39 01 00 00 00 00 02 BD 01 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 02 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 03 + 39 01 00 00 00 00 3A C1 FF F7 F0 E9 E2 DB D4 + C6 BF B8 B1 AB A5 9F 99 94 8E 8A 85 7C 74 + 6C 65 5F 58 52 4B 47 42 3C 37 31 2C 27 22 + 1C 18 12 0D 08 05 04 02 01 00 27 B9 BE 54 + C6 B8 9C 37 43 3D E5 00 + 39 01 00 00 00 00 02 BD 00 + 39 01 00 00 00 00 02 E9 C3 + 39 01 00 00 00 00 03 CB 92 01 + 39 01 00 00 00 00 02 E9 3F + 39 01 00 00 00 00 07 C7 70 00 04 E0 33 00 + 39 01 00 00 00 00 03 51 0F FF + 39 01 00 00 00 00 02 53 24 + 39 01 00 00 00 00 02 55 00 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 96 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..69f168b8e0540c4d8053744ca8e76db807f4beb7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8394d-wxga-video.dtsi @@ -0,0 +1,86 @@ +/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_hx8394d_kingdisplay_vid: qcom,mdss_dsi_hx8394d_kingdisplay_vid { + qcom,mdss-dsi-panel-name = "hx8394d wxga video mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <800>; + qcom,mdss-dsi-panel-height = <1280>; + qcom,mdss-dsi-h-front-porch = <24>; + qcom,mdss-dsi-h-back-porch = <132>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <9>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 04 B9 FF 83 94 + 39 01 00 00 32 00 05 D9 00 8B 02 07 + 39 01 00 00 00 00 03 BA 73 83 + 39 01 00 00 00 00 10 B1 6C 10 10 24 E4 11 F1 80 E4 D7 23 80 C0 D2 58 + 39 01 00 00 00 00 0C B2 00 64 10 07 70 1C 08 08 1C 4D 00 + 39 01 00 00 00 00 0D B4 00 FF 03 5A 03 5A 03 5A 01 6A 01 6A + 39 01 00 00 00 00 1F D3 00 06 00 40 1A 08 00 32 10 07 00 07 54 15 0F 05 04 02 12 10 05 07 33 33 0B 0B 37 10 07 07 + 39 01 00 00 00 00 2D D5 19 19 18 18 1A 1A 1B 1B 04 05 06 07 00 01 02 03 20 21 18 18 18 18 18 18 18 18 18 18 18 18 22 23 18 18 18 18 18 18 18 18 18 18 18 18 + 39 01 00 00 00 00 2D D6 18 18 19 19 1A 1A 1B 1B 03 02 01 00 07 06 05 04 23 22 18 18 18 18 18 18 18 18 18 18 18 18 21 20 18 18 18 18 18 18 18 18 19 18 18 18 + 39 01 00 00 00 00 2B E0 00 00 02 3C 3E 3F 12 3D 06 09 0A 19 0F 11 14 12 13 07 12 15 16 00 00 01 3C 3E 3F 12 3D 07 09 0B 12 0D 11 13 11 13 08 13 14 19 + 15 01 00 00 00 00 02 CC 09 + 15 01 00 00 00 00 02 D2 55 + 39 01 00 00 00 00 03 C0 30 14 + 39 01 00 00 00 00 04 BF 41 0E 01 + 39 01 00 00 00 00 05 C7 00 C0 40 C0 + 15 01 00 00 00 00 02 DF 8E + 05 01 00 00 C8 00 01 11 + 05 01 00 00 C8 00 01 29 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 32 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-dsi-panel-timings = + [8B 1f 14 00 45 4A 19 23 23 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x04>; + qcom,mdss-dsi-t-clk-pre = <0x1D>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 2>, <1 20>; + qcom,mdss-dsi-init-delay-us = <50000>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-pan-physical-width-dimension = <107>; + qcom,mdss-pan-physical-height-dimension = <172>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi index 89c51783459d9be7704f6f0c9e5cbba4582de862..7a711543a6abd58bd3b5b5cc13021c834242f3c9 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx8399c-hd-plus-video.dtsi @@ -25,7 +25,7 @@ qcom,mdss-dsi-h-pulse-width = <16>; qcom,mdss-dsi-h-sync-skew = <0>; qcom,mdss-dsi-v-back-porch = <40>; - qcom,mdss-dsi-v-front-porch = <60>; + qcom,mdss-dsi-v-front-porch = <36>; qcom,mdss-dsi-v-pulse-width = <4>; qcom,mdss-dsi-h-left-border = <0>; qcom,mdss-dsi-h-right-border = <0>; diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index 1e3e49796713529061f4f0c5f7b4acc8796c41b2..8c06c93783fa86fcb590ac2c3e6ca8c6bada8417 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -163,7 +163,7 @@ }; }; - reserved-memory { + reserved_mem: reserved-memory { #address-cells = <2>; #size-cells = <2>; ranges; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi index f8410974ed81b7d7d2797f5a398c2afc4ae28950..3389d298b276088858ff94812bbe328f2bee9073 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-memory.dtsi @@ -22,3 +22,14 @@ &peripheral_mem { reg = <0x0 0x8d200000 0x0 0x0600000>; }; + +&reserved_mem { + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xa0000000>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + linux,cma-default; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi index 36a67af768bf7d6478a12e893b1dde8c4a0a83ce..7c3e932e52d8dc54520440629fe076d3c40bc23d 100644 --- a/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8916-regulator.dtsi @@ -214,7 +214,7 @@ regulator-min-microvolt = <1>; regulator-max-microvolt = <7>; qcom,use-voltage-corner; - qcom,init-voltage = <1>; + qcom,init-voltage-corner = <1>; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..23545f9d194dd2e541e289e98a76e20f3301a0f3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-camera-sensor-cdp.dtsi @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&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_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_vana", "cam_vio", + "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_mclk0_default + &cam_sensor_rear_default>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_sleep>; + gpios = <&tlmm 26 0>, + <&tlmm 36 0>, + <&tlmm 35 0>; + qcom,gpio-reset = <1>; + qcom,gpio-standby = <2>; + qcom,gpio-req-tbl-num = <0 1 2>; + qcom,gpio-req-tbl-flags = <1 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0"; + 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_default + &cam_sensor_rear_vdig>; + pinctrl-1 = <&cam_sensor_mclk0_sleep &cam_sensor_rear_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/msm8917-cdp-ml-touch-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts index 377eda4ec77b81aac53bca8c22d41627a7f121c8..73ea29b2e200d12f028f36bf3d2421b14dcbf630 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp-ml-touch-overlay.dts @@ -14,7 +14,6 @@ /dts-v1/; /plugin/; -#include #include "msm8917-cdp.dtsi" #include "msm8917-cdp-mirror-lake-touch.dtsi" #include "msm8917-audio-cdp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi index 6a2fecde320db867919b06f5d89f43864989b1b1..7690931e65a3ab3022a8bd19e5b9915ae80bbcba 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi @@ -11,6 +11,9 @@ * GNU General Public License for more details. */ +#include +#include "msm8917-camera-sensor-cdp.dtsi" + &soc { gpio_keys { compatible = "gpio-keys"; @@ -156,6 +159,39 @@ }; }; +&pm8937_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio5"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm8937_l8>; diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts index 920bcaed74e7aca9fe9f16db1d3435bed6e4389d..0540e0925af3167c0827284d166f7c3ec7bc3b93 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-mtp-overlay.dts @@ -15,7 +15,6 @@ /plugin/; #include -#include #include #include "msm8917-mtp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi index 7f35e1ebcf41254b8364c879e877f25b4362b90f..9a3b6daed1884d8282a3f61874616ca4d59e964e 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include #include "msm8917-camera-sensor-mtp.dtsi" &blsp1_uart2 { @@ -19,6 +20,39 @@ pinctrl-0 = <&uart_console_active>; }; +&pm8937_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio5"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm8937_l8>; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi index 858936d86e856055b3ddd86cc04759c033447ca9..0e613b6c2736804da60e149ba7803951002f5098 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi @@ -1345,39 +1345,65 @@ }; }; - pmx_rd_nfc_int { - /*qcom,pins = <&gp 17>;*/ - pins = "gpio17"; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "pmx_nfc_int"; - - nfc_int_active: active { - drive-strength = <6>; - bias-pull-up; + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; }; - nfc_int_suspend: suspend { - drive-strength = <6>; - bias-pull-up; + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 17 NFC Read Interrupt */ + pins = "gpio17"; + function = "gpio"; + }; + + config { + pins = "gpio17"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; }; - }; - pmx_nfc_reset { - /*qcom,pins = <&gp 16>;*/ - pins = "gpio16"; - qcom,pin-func = <0>; - qcom,num-grp-pins = <1>; - label = "pmx_nfc_disable"; + nfc_disable_active: nfc_disable_active { + /* active state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + pins = "gpio16", "gpio130"; + function = "gpio"; + }; - nfc_disable_active: active { - drive-strength = <6>; - bias-pull-up; + config { + pins = "gpio16", "gpio130"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; }; - nfc_disable_suspend: suspend { - drive-strength = <6>; - bias-disable; + nfc_disable_suspend: nfc_disable_suspend { + /* sleep state */ + mux { + /* 16: NFC ENABLE 130: FW DNLD */ + pins = "gpio16", "gpio130"; + function = "gpio"; + }; + + config { + pins = "gpio16", "gpio130"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts index 65177572697989c1cf56868c6da648c36057c64e..c0dc21787dd44d70841615c94a79a921b2115431 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts @@ -14,7 +14,6 @@ /dts-v1/; /plugin/; -#include #include "msm8917-qrd.dtsi" / { @@ -111,13 +110,4 @@ qcom,key-codes = <139 172 158>; qcom,y-offset = <0>; }; - - led_flash0: qcom,camera-flash { - cell-index = <0>; - compatible = "qcom,camera-flash"; - qcom,flash-type = <1>; - qcom,flash-source = <&pmi8937_flash0>; - qcom,torch-source = <&pmi8937_torch0>; - qcom,switch-source = <&pmi8937_switch>; - }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi index d5fd1ff99cd7009b6079d86892c09dbc8bb14855..6a4c10e4aaba29a65f1fc8781d9be8e9ab73e506 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi @@ -10,8 +10,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include #include "msm8917-camera-sensor-qrd.dtsi" #include "msm8937-mdss-panels.dtsi" +#include "msm8917-pmi8937.dtsi" &blsp1_uart2 { status = "ok"; @@ -19,6 +21,39 @@ pinctrl-0 = <&uart_console_active>; }; +&pm8937_gpios { + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio5"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 (NFC) */ + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + &sdhc_1 { /* device core power supply */ vdd-supply = <&pm8937_l8>; diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi index 7bc181c3a2658bafeb01421531dbc5b37399ead5..be6ab790373eaf2e3977e46bc11bcc009e60cc6a 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi @@ -26,6 +26,7 @@ #include "dsi-panel-hx8399c-fhd-plus-video.dtsi" #include "dsi-panel-hx83100a-800p-video.dtsi" #include "dsi-panel-boent51021-1200p-video.dtsi" +#include "dsi-panel-hx8394d-wxga-video.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -184,3 +185,11 @@ 25 20 08 0a 06 03 04 a0 25 1d 08 0a 06 03 04 a0]; }; + +&dsi_hx8394d_kingdisplay_vid { + qcom,mdss-dsi-panel-timings-phy-v2 = [1c 19 02 03 01 03 04 a0 + 1c 19 02 03 01 03 04 a0 + 1c 19 02 03 01 03 04 a0 + 1c 19 02 03 01 03 04 a0 + 1c 07 02 03 01 03 04 a0]; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi index 3552055f01c9eb5a46bc2a6dc4dd24832226aeed..c58d82ec24a980289821e545f9f2af12226da547 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi @@ -1400,6 +1400,163 @@ }; }; + spi6 { + spi6_default: spi6_default { + /* active state */ + mux { + /* MOSI, MISO, CLK */ + pins = "gpio20", "gpio21", "gpio23"; + function = "blsp_spi6"; + }; + + config { + pins = "gpio20", "gpio21", "gpio23"; + drive-strength = <12>; /* 12 MA */ + bias-disable = <0>; /* No PULL */ + }; + }; + + spi6_sleep: spi6_sleep { + /* suspended state */ + mux { + /* MOSI, MISO, CLK */ + pins = "gpio20", "gpio21", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio20", "gpio21", "gpio23"; + drive-strength = <2>; /* 2 MA */ + bias-pull-down; /* PULL Down */ + }; + }; + + spi6_cs0_active: cs0_active { + /* CS */ + mux { + pins = "gpio22"; + function = "blsp_spi6"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + + spi6_cs0_sleep: cs0_sleep { + /* CS */ + mux { + pins = "gpio22"; + function = "gpio"; + }; + + config { + pins = "gpio22"; + drive-strength = <2>; + bias-disable = <0>; + }; + }; + }; + + /* add pingrp for touchscreen */ + ts_int_default: ts_int_default { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + drive-strength = <16>; + /*bias-pull-up;*/ + input-enable; + bias-disable; + }; + }; + + ts_int_output_high: ts_int_output_high { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + output-high; + }; + }; + + ts_int_output_low: ts_int_output_low { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + output-low; + }; + }; + + ts_int_input: ts_int_input { + mux { + pins = "gpio65"; + function = "gpio"; + }; + config { + pins = "gpio65"; + input-enable; + bias-disable; + }; + }; + + ts_rst_default: ts_rst_default { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + drive-strength = <16>; + /*bias-pull-up;*/ + input-enable; + bias-disable; + }; + }; + + ts_rst_output_high: ts_rst_output_high { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + output-high; + }; + }; + + ts_rst_output_low: ts_rst_output_low { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + output-low; + }; + }; + + ts_rst_input: ts_rst_input { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + input-enable; + bias-disable; + }; + }; + /* add pingrp for touchscreen */ pmx_ts_int_active { ts_int_active: ts_int_active { diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi index 5a4f024226ccfddd1dc78f003dfc2c3a777b528b..31e882fd8ae268db8c04d9b707f997984e65bf6f 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi @@ -388,9 +388,6 @@ "APCS_ALIAS0_APM_CTLER_STATUS", "APCS0_CPR_CORE_ADJ_MODE_REG"; - qcom,cpr-temp-point-map = <250 650 850>; - qcom,cpr-initial-temp-band = <0>; - /* Turbo (corner 6) ceiling voltage */ qcom,cpr-aging-ref-voltage = <990000>; @@ -795,59 +792,6 @@ qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; - qcom,corner-allow-temp-adjustment = - /* Speed bin 0; CPR rev 0..7 */ - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - - /* Speed bin 2; CPR rev 0..7 */ - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - - /* Speed bin 6; CPR rev 0..7 */ - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - <1 1 1 1 0 0 0>, - - /* Speed bin 7; CPR rev 0..7 */ - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <0 0 0 0 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>, - <1 1 1 1 0 0 0 0 0>; - - qcom,cpr-corner1-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (-20000)>; - - qcom,cpr-corner2-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (-15000)>; - - qcom,cpr-corner3-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (0)>; - - qcom,cpr-corner4-temp-core-voltage-adjustment = - <(0) (-5000) (-15000) (0)>; - qcom,cpr-aging-max-voltage-adjustment = <15000>; qcom,cpr-aging-ref-corner = <6>; /* Turbo */ qcom,cpr-aging-ro-scaling-factor = <2800>; diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 74d2eb54b4f938a68926e6d654a1127dcd02cca8..efe01f710ccd1fdefcce6d117c721b8973d33ffe 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -171,6 +171,7 @@ i2c3 = &i2c_3; i2c5 = &i2c_5; spi3 = &spi_3; + spi6 = &spi_6; }; soc: soc { @@ -692,6 +693,33 @@ qcom,master-id = <86>; status = "disabled"; }; + + spi_6: spi@7af6000 { /* BLSP2 QUP2 */ + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "spi_physical", "spi_bam_physical"; + reg = <0x7af6000 0x600>, + <0x7ac4000 0x1f000>; + interrupt-names = "spi_irq", "spi_bam_irq"; + interrupts = <0 300 0>, <0 239 0>; + spi-max-frequency = <19200000>; + pinctrl-names = "spi_default", "spi_sleep"; + pinctrl-0 = <&spi6_default &spi6_cs0_active>; + pinctrl-1 = <&spi6_sleep &spi6_cs0_sleep>; + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, + <&clock_gcc clk_gcc_blsp2_qup2_spi_apps_clk>; + clock-names = "iface_clk", "core_clk"; + qcom,infinite-mode = <0>; + qcom,use-bam; + qcom,use-pinctrl; + qcom,ver-reg-exists; + qcom,bam-consumer-pipe-index = <6>; + qcom,bam-producer-pipe-index = <7>; + qcom,master-id = <84>; + status = "disabled"; + }; + i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */ compatible = "qcom,i2c-msm-v2"; #address-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi index c72225d3369ad0f4cd2f959bb261494474ce6e17..829e73364538de2023b6831e81a262daeb2d986e 100644 --- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi @@ -12,6 +12,8 @@ */ #include +#include +#include &spmi_bus { @@ -491,34 +493,28 @@ }; }; - pmi_haptic: qcom,haptic@c000 { - compatible = "qcom,qpnp-haptic"; + pmi_haptic: qcom,haptics@c000 { + compatible = "qcom,qpnp-haptics"; reg = <0xc000 0x100>; interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>; - interrupt-names = "sc-irq", "play-irq"; + interrupt-names = "hap-sc-irq", "hap-play-irq"; qcom,pmic-revid = <&pmi8937_revid>; vcc_pon-supply = <&pon_perph_reg>; qcom,play-mode = "direct"; qcom,wave-play-rate-us = <5263>; - qcom,actuator-type = "lra"; + qcom,actuator-type = <0>; qcom,wave-shape = "square"; qcom,vmax-mv = <2000>; qcom,ilim-ma = <800>; qcom,sc-deb-cycles = <8>; qcom,int-pwm-freq-khz = <505>; qcom,en-brake; - qcom,brake-pattern = [03 03 00 00]; - qcom,use-play-irq; - qcom,use-sc-irq; - qcom,wave-samples = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,brake-pattern = <0x3 0x3 0x0 0x0>; + qcom,wave-samples = <0x3e 0x3e 0x3e 0x3e 0x3e + 0x3e 0x3e 0x3e>; qcom,wave-rep-cnt = <1>; qcom,wave-samp-rep-cnt = <1>; - qcom,lra-auto-res-mode="qwd"; - qcom,lra-high-z="opt1"; - qcom,lra-res-cal-period = <4>; - qcom,correct-lra-drive-freq; - qcom,misc-trim-error-rc19p2-clk-reg-present; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts index 44fae6ab54d8433b47e05fb19eddac40de8af17f..76088af9373263cd25c2835785dccd378ad3d8de 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp-overlay.dts @@ -1,5 +1,5 @@ /* - * 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 @@ -32,3 +32,47 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts index abc3f2da8a2507cc158c9ac9b89331d7eb0863dc..47ea8f390a78d1e51c6700752d17dae3ec6474c4 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts +++ b/arch/arm64/boot/dts/qcom/qcs605-external-codec-mtp.dts @@ -1,5 +1,5 @@ /* - * 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 @@ -26,3 +26,47 @@ <0x0001001b 0x0102001a 0x0 0x0>, <0x0001001b 0x0201011a 0x0 0x0>; }; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..ab82fe6e3071ce9f588bacb9af493318cba89f81 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-audio.dtsi @@ -0,0 +1,360 @@ +/* + * 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 "sdm670-wcd.dtsi" +#include "sdm670-wsa881x.dtsi" +#include "sdm670-lpi.dtsi" +#include + +&tavil_snd { + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,msm-mclk-freq = <9600000>; + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", "msm-ext-disp-audio-codec-rx"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + <&wsa881x_0213>, <&wsa881x_0214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&tasha_snd { + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>, <1>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,msm-mclk-freq = <9600000>; + asoc-codec = <&stub_codec>; + asoc-codec-names = "msm-stub-codec.1"; + qcom,wsa-max-devs = <2>; + qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, + <&wsa881x_213>, <&wsa881x_214>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + "SpkrLeft", "SpkrRight"; +}; + +&soc { + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl_usbc_audio_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; + + cdc_pdm_gpios: cdc_pdm_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_pdm_clk_active &cdc_pdm_sync_active + &cdc_pdm_rx0_active &cdc_pdm_rx1_2_active + &cdc_pdm_2_gpios_active>; + pinctrl-1 = <&cdc_pdm_clk_sleep &cdc_pdm_sync_sleep + &cdc_pdm_rx0_sleep &cdc_pdm_rx1_2_sleep + &cdc_pdm_2_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_comp_gpios: cdc_comp_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_rx0_comp_active &cdc_rx1_comp_active>; + pinctrl-1 = <&cdc_rx0_comp_sleep &cdc_rx1_comp_sleep>; + qcom,lpi-gpios; + }; + + cdc_dmic_gpios: cdc_dmic_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_dmic12_gpios_active + &cdc_dmic34_gpios_active>; + pinctrl-1 = <&cdc_dmic12_gpios_sleep + &cdc_dmic34_gpios_sleep>; + qcom,lpi-gpios; + }; + + cdc_sdw_gpios: sdw_clk_data_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sdw_clk_active &sdw_data_active>; + pinctrl-1 = <&sdw_clk_sleep &sdw_data_sleep>; + }; + + wsa_spkr_en1: wsa_spkr_en1_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_sd_n_active>; + pinctrl-1 = <&spkr_1_sd_n_sleep>; + }; + + wsa_spkr_en2: wsa_spkr_en2_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_sd_n_active>; + pinctrl-1 = <&spkr_2_sd_n_sleep>; + }; + + msm_sdw_codec: msm-sdw-codec@62ec1000 { + status = "okay"; + compatible = "qcom,msm-sdw-codec"; + reg = <0x62ec1000 0x0>; + interrupts = <0 88 0>; + interrupt-names = "swr_master_irq"; + qcom,cdc-sdw-gpios = <&cdc_sdw_gpios>; + + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_211_en: wsa881x_en@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_212_en: wsa881x_en@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + + wsa881x_213_en: wsa881x_en@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_en1>; + }; + + wsa881x_214_en: wsa881x_en@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x0 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_en2>; + }; + }; + }; + + wcd9xxx_intc: wcd9xxx-irq { + status = "disabled"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 80 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio_native: audio_ext_clk_native { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + #clock-cells = <1>; + qcom,lpass-mclk-id = <0x116>; + qcom,codec-mclk-clk-freq = <11289600>; + qcom,audio-ref-clk-gpio = <&lpi_tlmm 19 0>; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&lpi_mclk0_sleep>; + pinctrl-1 = <&lpi_mclk0_active>; + }; + + clock_audio: audio_ext_clk { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&tasha_mclk_default>; + pinctrl-1 = <&tasha_mclk_default>; + qcom,audio-ref-clk-gpio = <&pm660_gpios 3 0>; + clock-names = "osr_clk"; + clocks = <&pm660_div_clk>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + status = "disabled"; + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&lpi_cdc_reset_active>; + pinctrl-1 = <&lpi_cdc_reset_sleep>; + qcom,lpi-gpios; + }; + + wdsp_mgr: qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi_xprt_wdsp 2>; + qcom,img-filename = "cpe_9340"; + }; + + wdsp_glink: qcom,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + }; + + tert_mi2s_gpios: tert_mi2s_pinctrl { + status = "disabled"; + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&ter_i2s_data0_active &ter_i2s_data1_active + &ter_i2s_sck_active>; + pinctrl-1 = <&ter_i2s_data0_sleep &ter_i2s_data1_sleep + &ter_i2s_sck_sleep>; + }; +}; + +&slim_aud { + wcd9335: tasha_codec { + status = "disabled"; + compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 a0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk", "wcd_native_clk"; + clocks = <&clock_audio AUDIO_PMI_CLK>, + <&clock_audio_native AUDIO_LPASS_MCLK>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 a0 01 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + }; + + wcd934x_cdc: tavil_codec { + status = "disabled"; + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; + + cdc-vdd-mic-bias-supply = <&pm660l_bob>; + qcom,cdc-vdd-mic-bias-voltage = <3312000 3312000>; + qcom,cdc-vdd-mic-bias-current = <30400>; + + qcom,cdc-static-supplies = "cdc-vdd-mic-bias"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <0>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + }; +}; + + diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-overlay.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..c7912d6aa1be2420f0d175244fc9ba9af2d27e89 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-overlay.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "qcs605-lc-ipcamera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 IPC"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,msm-id = <347 0x0>; + qcom,board-id = <8 6>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts new file mode 100644 index 0000000000000000000000000000000000000000..90dcd7b98b25af8e64be9c70bc854c807e5d13c2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "qcs605-lc.dtsi" +#include "qcs605-lc-ipcamera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. QC605 LC Groot + PM8005 IPC"; + compatible = "qcom,qcs605-mtp", "qcom,qcs605", "qcom,mtp"; + qcom,board-id = <8 6>; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..d6d9a1797f98b43a0a7d330a95119f301b257dfb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera.dtsi @@ -0,0 +1,196 @@ +/* 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 "qcs605-lc-pmic-overlay.dtsi" +#include "qcs605-lc-camera-sensor-mtp.dtsi" +#include "qcs605-lc-ipcamera-audio.dtsi" + +&qupv3_se9_2uart { + status = "disabled"; +}; + +&qupv3_se12_2uart { + status = "ok"; +}; + +&sdhc_1 { + vdd-supply = <&pm660_l19>; + qcom,vdd-voltage-level = <2960000 2960000>; + qcom,vdd-current-level = <0 570000>; + + vdd-io-supply = <&pm660_l8>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <0 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + status = "ok"; +}; + +&tlmm { + sdc2_cd_on: cd_on { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + sdc2_cd_off: cd_off { + mux { + pins = "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio116"; + drive-strength = <2>; + bias-disable; + }; + }; +}; + +&sdhc_2 { + /* VDD external regulator is enabled/disabled by pm660_l18 regulator */ + vdd-io-supply = <&pm660_l18>; + qcom,vdd-io-voltage-level = <1800000 2960000>; + qcom,vdd-io-current-level = <0 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_cd_off>; + + cd-gpios = <&tlmm 116 0x1>; + + status = "ok"; +}; + +&usb0 { + dwc3@a600000 { + dr_mode = "host"; + }; +}; + +&icnss { + status = "disabled"; +}; + +&msm_sdw_codec { + status = "disabled"; +}; + +&cdc_pdm_gpios { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&cdc_dmic_gpios { + status = "disabled"; +}; + +&cdc_sdw_gpios { + status = "disabled"; +}; + +&wsa_spkr_en1 { + status = "disabled"; +}; + +&wsa_spkr_en2 { + status = "disabled"; +}; + +&qupv3_se8_spi { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&wdsp_mgr { + status = "okay"; +}; + +&wdsp_glink { + status = "okay"; +}; + +&slim_aud { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd934x_cdc { + status = "okay"; +}; + +&clock_audio_lnbb { + status = "okay"; +}; + +&tavil_snd { + status = "okay"; + compatible = "qcom,qcs605-asoc-snd-tavil"; + qcom,model = "qcs605-tavil-snd-card"; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT"; + qcom,wsa-max-devs = <1>; + qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0213>; + qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrLeft"; +}; + +&soc { + wcd_rst_gpio1: msm_cdc_pinctrl@11 { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 11 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; +}; + +&wcd934x_cdc { + /delete-property/ cdc-vdd-mic-bias-supply; + /delete-property/ qcom,cdc-static-supplies; + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio1>; +}; + +&wcd9335 { + /delete-property/ cdc-vdd-mic-bias-supply; +}; diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 61a812c9aaa4e1fffe19bfbe6b7cc9bd206aa500..7801775c7e3b75b0a5acdbcda23a0eff6d167492 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -76,6 +76,10 @@ }; }; +&llcc { + compatible = "qcom,qcs605-llcc"; +}; + &ipa_hw { status = "disabled"; }; @@ -104,6 +108,14 @@ }; }; }; + + gpu-virt-max-step { + trips { + gpu-trip0 { + temperature = <100000>; + }; + }; + }; }; &msm_gpu { diff --git a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi index fcffd447881a7ed8068f69d3a66724057063c311..ea385bd3f02cdd832ca44b220816b3b4bb7a86b5 100644 --- a/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi +++ b/arch/arm64/boot/dts/qcom/sda670-hdk.dtsi @@ -97,9 +97,9 @@ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ 0x21 0x214 /* PWR_CTRL2 */ - 0x00 0x220 /* IMP_CTRL1 */ + 0x0f 0x220 /* IMP_CTRL1 */ 0x58 0x224 /* IMP_CTRL2 */ - 0x77 0x240 /* TUNE1 */ + 0xc5 0x240 /* TUNE1 */ 0x29 0x244 /* TUNE2 */ 0xca 0x248 /* TUNE3 */ 0x04 0x24c /* TUNE4 */ @@ -117,9 +117,9 @@ 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ 0x21 0x214 /* PWR_CTRL2 */ - 0x25 0x220 /* IMP_CTRL1 */ + 0x00 0x220 /* IMP_CTRL1 */ 0x58 0x224 /* IMP_CTRL2 */ - 0x65 0x240 /* TUNE1 */ + 0x67 0x240 /* TUNE1 */ 0x29 0x244 /* TUNE2 */ 0xca 0x248 /* TUNE3 */ 0x04 0x24c /* TUNE4 */ diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 77da1f32139415976ea9172aa56f7c59cbbfde49..9bb8a6cff0ee81722ac99b9305be20cfb496b057 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -69,8 +69,8 @@ target-dev = <&cpubw>; cpu-to-dev-map = < 960000 2929 >, - < 1305600 5126 >, - < 1497600 5859 >, + < 1305600 5053 >, + < 1497600 5712 >, < 1708800 6445 >, < 1804800 7104 >, < 1958400 7104 >; @@ -91,9 +91,21 @@ target-dev = <&mincpubw>; cpu-to-dev-map = < 1305600 2929 >, - < 1804800 5859 >; + < 1804800 5712 >; }; }; + + qcom,ion { + /delete-node/ qcom,ion-heap@8; + }; +}; + +&secure_mem { + status = "disabled"; +}; + +&kgsl_msm_iommu { + /delete-node/ gfx3d_secure; }; &funnel_apss { diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index be05b6ebf7f9875b12a83c6dab2c7933be368f70..9067bc9093f0236a6d6ed54de1370fabf3877831 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -78,9 +78,9 @@ < 2929 /* 384 MHz */ >, /* SVS */ < 3221 /* 422.4 MHz */ >, < 4248 /* 556.8 MHz */ >, - < 5126 /* 662.4 MHz */ >, /* SVS+ */ - < 5859 /* 748.8 MHz */ >, /* NOM */ - < 6152 /* 806.4 MHz */ >, /* NOM+ */ + < 5053 /* 662.4 MHz */ >, /* SVS+ */ + < 5712 /* 748.8 MHz */ >, /* NOM */ + < 6079 /* 796.8 MHz */ >, /* NOM+ */ < 6445 /* 844.8 MHz */ >, < 7104 /* 931.2 MHz */ >; /* TURBO */ }; @@ -98,9 +98,9 @@ < 2929 /* 384 MHz */ >, /* SVS */ < 3221 /* 422.4 MHz */ >, < 4248 /* 556.8 MHz */ >, - < 5126 /* 662.4 MHz */ >, /* SVS+ */ - < 5859 /* 748.8 MHz */ >, /* NOM */ - < 6152 /* 806.4 MHz */ >, /* NOM+ */ + < 5053 /* 662.4 MHz */ >, /* SVS+ */ + < 5712 /* 748.8 MHz */ >, /* NOM */ + < 6079 /* 796.8 MHz */ >, /* NOM+ */ < 6445 /* 844.8 MHz */ >, < 7104 /* 931.2 MHz */ >; /* TURBO */ }; @@ -124,16 +124,16 @@ cpubw-cpufreq { target-dev = <&cpubw>; cpu-to-dev-map-0 = - < 1305600 5126 >, - < 1497600 5859 >, + < 1305600 5053 >, + < 1497600 5712 >, < 1708800 6445 >, < 1804800 7104 >, < 1958400 7104 >; cpu-to-dev-map-4 = < 768000 2929 >, - < 998400 5126 >, - < 1171200 5859 >, - < 1305600 6152 >, + < 998400 5053 >, + < 1171200 5712 >, + < 1305600 6079 >, < 1459200 7104 >; }; @@ -158,10 +158,10 @@ target-dev = <&mincpubw>; cpu-to-dev-map-0 = < 1305600 2929 >, - < 1804800 5859 >; + < 1804800 5712 >; cpu-to-dev-map-4 = < 1171200 2929 >, - < 1459200 5859 >; + < 1459200 5712 >; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi index c40fff684e60877d56bab7bd903a8e0cdf1a3146..1cfa3aeccdaad5871a98f92b63ef6b786b154cb5 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera-sensor-360camera.dtsi @@ -1,5 +1,5 @@ /* - * 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 @@ -189,7 +189,7 @@ rgltr-cntrl-support; rgltr-min-voltage = <1352000 1800000 2850000 0 2800000>; rgltr-max-voltage = <1352000 1800000 2850000 0 2800000>; - rgltr-load-current = <105000 0 80000 0>; + rgltr-load-current = <105000 0 80000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk1_active @@ -226,7 +226,7 @@ rgltr-cntrl-support; rgltr-min-voltage = <1800000 2850000 1352000 0 2800000>; rgltr-max-voltage = <1800000 2850000 1352000 0 2800000>; - rgltr-load-current = <0 80000 105000 0>; + rgltr-load-current = <0 80000 105000 0 0>; gpio-no-mux = <0>; pinctrl-names = "cam_default", "cam_suspend"; pinctrl-0 = <&cam_sensor_mclk2_active diff --git a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi index 348ba6f138fa60ce72f66ce38722c023ec76091d..76b7b058d9af831259adcfad4a12d0a39abf9835 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-camera.dtsi @@ -46,6 +46,7 @@ "csiphy0_clk", "csi0phytimer_clk_src", "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; clock-cntl-level = "turbo"; clock-rates = <0 0 0 0 384000000 0 269333333 0>; @@ -81,6 +82,7 @@ "csiphy1_clk", "csi1phytimer_clk_src", "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; clock-cntl-level = "turbo"; clock-rates = <0 0 0 0 384000000 0 269333333 0>; @@ -117,6 +119,7 @@ "csiphy2_clk", "csi2phytimer_clk_src", "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; clock-cntl-level = "turbo"; clock-rates = <0 0 0 0 384000000 0 269333333 0>; @@ -338,17 +341,17 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0xda00000>; + iova-region-len = <0xd2500000>; iova-region-id = <0x3>; status = "ok"; }; iova-mem-qdss-region { - /* qdss region is approximately 64K */ + /* qdss region is approximately 1MB */ iova-region-name = "qdss"; iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; + iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; status = "ok"; @@ -911,6 +914,9 @@ cam_ipe0: qcom,ipe0 { cell-index = <0>; compatible = "qcom,cam-ipe"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; regulator-names = "ipe0-vdd"; ipe0-vdd-supply = <&ipe_0_gdsc>; clock-names = "ipe_0_ahb_clk", @@ -938,6 +944,9 @@ cam_ipe1: qcom,ipe1 { cell-index = <1>; compatible = "qcom,cam-ipe"; + reg = <0xac91000 0x3000>; + reg-names = "ipe1_top"; + reg-cam-base = <0x91000>; regulator-names = "ipe1-vdd"; ipe1-vdd-supply = <&ipe_1_gdsc>; clock-names = "ipe_1_ahb_clk", @@ -965,6 +974,9 @@ cam_bps: qcom,bps { cell-index = <0>; compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; regulator-names = "bps-vdd"; bps-vdd-supply = <&bps_gdsc>; clock-names = "bps_ahb_clk", diff --git a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi index 3fd122901f914337695d5a46c31c43593c16217b..0968a522e4880c028613c8eeb04122168f6e5292 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi @@ -49,5 +49,12 @@ reg = <9>; qcom,ion-heap-type = "SYSTEM_SECURE"; }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&sdsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi index 04614292bad8a9d3216805faf21686005a40af78..0453cee1119137b8c8f3c5f066930ca1d775f639 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-pinctrl.dtsi @@ -1490,6 +1490,34 @@ }; }; + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio11"; + function = "gpio"; + }; + config { + pins = "gpio11"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio11"; + function = "gpio"; + }; + config { + pins = "gpio11"; + drive-strength = <8>; + bias-pull-down; + output-high; + }; + }; + }; + /* WSA speaker reset pins */ spkr_1_sd_n { spkr_1_sd_n_sleep: spkr_1_sd_n_sleep { diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi index a74337339eb229505b46d0f35adcd9421aa17d59..5d62c5a87d0aaf41e0b908183329b59f9f9e83d1 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde-display.dtsi @@ -27,6 +27,7 @@ #include "dsi-panel-rm67195-amoled-fhd-cmd.dtsi" #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" #include "dsi-panel-hx8399-truly-singlemipi-fhd-video.dtsi" +#include "dsi-panel-hx83112a-truly-singlemipi-fhd-video.dtsi" #include &soc { @@ -489,7 +490,30 @@ ibb-supply = <&lcdb_ncp_vreg>; }; - ext_dsi_bridge_display: qcom,dsi-display@17 { + dsi_hx83112a_truly_video_display: qcom,dsi-display@17 { + compatible = "qcom,dsi-display"; + label = "dsi_hx83112a_truly_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-te-gpio = <&tlmm 10 0>; + qcom,platform-reset-gpio = <&tlmm 75 0>; + + qcom,dsi-panel = <&dsi_hx83112a_truly_video>; + vddio-supply = <&pm660_l11>; + lab-supply = <&lcdb_ldo_vreg>; + ibb-supply = <&lcdb_ncp_vreg>; + }; + + ext_dsi_bridge_display: qcom,dsi-display@18 { compatible = "qcom,dsi-display"; label = "ext_dsi_bridge_display"; qcom,display-type = "primary"; @@ -561,7 +585,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -583,7 +607,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -607,7 +631,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 - 05 03 03 04 00]; + 05 03 02 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -634,7 +658,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 - 04 03 03 04 00]; + 04 03 02 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -649,7 +673,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <1 0 1>, <2 0 1>; qcom,default-topology-index = <0>; @@ -663,7 +687,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -682,7 +706,7 @@ qcom,panel-roi-alignment = <720 40 720 40 720 40>; qcom,partial-update-enabled = "single_roi"; qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; }; timing@1{ qcom,display-topology = <1 0 1>, @@ -691,7 +715,7 @@ qcom,panel-roi-alignment = <540 40 540 40 540 40>; qcom,partial-update-enabled = "single_roi"; qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; }; timing@2{ qcom,display-topology = <1 0 1>, @@ -700,7 +724,7 @@ qcom,panel-roi-alignment = <360 40 360 40 360 40>; qcom,partial-update-enabled = "single_roi"; qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; }; }; }; @@ -711,20 +735,20 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 - 09 06 03 04 00]; + 09 06 02 04 00]; qcom,display-topology = <2 0 2>; qcom,default-topology-index = <0>; }; timing@1{ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; }; timing@2{ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 - 06 04 03 04 00]; + 06 04 02 04 00]; qcom,display-topology = <2 0 2>; qcom,default-topology-index = <0>; }; @@ -737,13 +761,13 @@ qcom,mdss-dsi-display-timings { timing@0 { /* 1080p */ qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 - 07 04 03 04 00]; + 07 04 02 04 00]; qcom,display-topology = <1 1 1>; qcom,default-topology-index = <0>; }; timing@1 { /* qhd */ qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 - 05 03 03 04 00]; + 05 03 02 04 00]; qcom,display-topology = <1 1 1>, <2 2 1>, /* dsc merge */ <2 1 1>; /* 3d mux */ @@ -758,13 +782,13 @@ qcom,mdss-dsi-display-timings { timing@0 { /* qhd */ qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 2 2>; qcom,default-topology-index = <0>; }; timing@1 { /* 4k */ qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 - 06 04 03 04 00]; + 06 04 02 04 00]; qcom,display-topology = <2 2 2>; qcom,default-topology-index = <0>; }; @@ -777,7 +801,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -792,7 +816,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 - 07 05 03 04 00]; + 07 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -808,7 +832,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c - 05 07 05 03 04 00]; + 05 07 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; @@ -826,7 +850,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 05 06 0b 0c - 05 07 05 03 04 00]; + 05 07 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; @@ -841,7 +865,7 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1c 08 07 23 22 - 07 07 05 03 04 00]; + 07 07 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; @@ -862,7 +886,7 @@ qcom,mdss-dsi-display-timings { timing@0{ qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08 - 08 05 03 04 00]; + 08 05 02 04 00]; qcom,display-topology = <2 0 2>, <1 0 2>; qcom,default-topology-index = <0>; @@ -888,7 +912,32 @@ qcom,mdss-dsi-display-timings { timing@0 { qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08 - 08 05 03 04 00]; + 08 05 02 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_hx83112a_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; + + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 22 08 + 08 05 02 04 00]; qcom,display-topology = <1 0 1>; qcom,default-topology-index = <0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi index 4ca400157b60a8feb054fb4d20bbd714122e3b39..fb717f3f392f823575a9c21b61c78da67c38d842 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi @@ -249,33 +249,13 @@ /* data and reg bus scale settings */ qcom,sde-data-bus { - qcom,msm-bus,name = "mdss_sde_mnoc"; + qcom,msm-bus,name = "mdss_sde"; qcom,msm-bus,num-cases = <3>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = - <22 773 0 0>, <23 773 0 0>, - <22 773 0 6400000>, <23 773 0 6400000>, - <22 773 0 6400000>, <23 773 0 6400000>; - }; - - qcom,sde-llcc-bus { - qcom,msm-bus,name = "mdss_sde_llcc"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <132 770 0 0>, - <132 770 0 6400000>, - <132 770 0 6400000>; - }; - - qcom,sde-ebi-bus { - qcom,msm-bus,name = "mdss_sde_ebi"; - qcom,msm-bus,num-cases = <3>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <129 512 0 0>, - <129 512 0 6400000>, - <129 512 0 6400000>; + <22 512 0 0>, <23 512 0 0>, + <22 512 0 6400000>, <23 512 0 6400000>, + <22 512 0 6400000>, <23 512 0 6400000>; }; qcom,sde-reg-bus { diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 575e4481f556467b7f8174032c889a13050ea487..bb07c045906b7c1e922f363049b1b7225fd33031 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -560,7 +560,15 @@ alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; alignment = <0 0x400000>; - size = <0 0xc00000>; + size = <0 0x800000>; + }; + + sdsp_mem: sdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x400000>; }; qseecom_ta_mem: qseecom_ta_region { diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 2e2de74999afaec51b6b0799034c9f0e89d317da..86b17046ed31268949c2f6c31a185d168a493cc7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -45,6 +45,7 @@ "csiphy0_clk", "csi0phytimer_clk_src", "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; clock-cntl-level = "svs", "turbo"; clock-rates = <0 0 0 0 320000000 0 269333333 0>, @@ -80,6 +81,7 @@ "csiphy1_clk", "csi1phytimer_clk_src", "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; clock-cntl-level = "svs", "turbo"; clock-rates = <0 0 0 0 320000000 0 269333333 0>, @@ -116,6 +118,7 @@ "csiphy2_clk", "csi2phytimer_clk_src", "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; clock-cntl-level = "svs", "turbo"; clock-rates = <0 0 0 0 320000000 0 269333333 0>, @@ -311,17 +314,17 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0xda00000>; + iova-region-len = <0xd2500000>; iova-region-id = <0x3>; status = "ok"; }; iova-mem-qdss-region { - /* qdss region is approximately 64K */ + /* qdss region is approximately 1MB */ iova-region-name = "qdss"; iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; + iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; status = "ok"; @@ -621,6 +624,7 @@ <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "turbo"; src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -659,6 +663,7 @@ <0 0 0 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "svs_l1", "turbo"; src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; clock-names-option = "ife_dsp_clk"; clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; clock-rates-option = <600000000>; @@ -707,6 +712,7 @@ <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "turbo"; src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -745,6 +751,7 @@ <0 0 0 0 0 0 600000000 0 0>; clock-cntl-level = "svs", "svs_l1", "turbo"; src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; clock-names-option = "ife_dsp_clk"; clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; clock-rates-option = <600000000>; @@ -790,6 +797,7 @@ <0 0 0 0 0 0 538000000 0 0 0 600000000 0>; clock-cntl-level = "svs", "turbo"; src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -825,6 +833,7 @@ <0 0 0 0 0 0 600000000 0>; clock-cntl-level = "svs", "svs_l1", "turbo"; src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; status = "ok"; }; @@ -881,6 +890,9 @@ cam_ipe0: qcom,ipe0 { cell-index = <0>; compatible = "qcom,cam-ipe"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; regulator-names = "ipe0-vdd"; ipe0-vdd-supply = <&ipe_0_gdsc>; clock-names = "ipe_0_ahb_clk", @@ -889,6 +901,7 @@ "ipe_0_clk", "ipe_0_clk_src"; src-clock-name = "ipe_0_clk_src"; + clock-control-debugfs = "true"; clocks = <&clock_camcc CAM_CC_IPE_0_AHB_CLK>, <&clock_camcc CAM_CC_IPE_0_AREG_CLK>, <&clock_camcc CAM_CC_IPE_0_AXI_CLK>, @@ -908,6 +921,9 @@ cam_ipe1: qcom,ipe1 { cell-index = <1>; compatible = "qcom,cam-ipe"; + reg = <0xac91000 0x3000>; + reg-names = "ipe1_top"; + reg-cam-base = <0x91000>; regulator-names = "ipe1-vdd"; ipe1-vdd-supply = <&ipe_1_gdsc>; clock-names = "ipe_1_ahb_clk", @@ -916,6 +932,7 @@ "ipe_1_clk", "ipe_1_clk_src"; src-clock-name = "ipe_1_clk_src"; + clock-control-debugfs = "true"; clocks = <&clock_camcc CAM_CC_IPE_1_AHB_CLK>, <&clock_camcc CAM_CC_IPE_1_AREG_CLK>, <&clock_camcc CAM_CC_IPE_1_AXI_CLK>, @@ -935,6 +952,9 @@ cam_bps: qcom,bps { cell-index = <0>; compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; regulator-names = "bps-vdd"; bps-vdd-supply = <&bps_gdsc>; clock-names = "bps_ahb_clk", @@ -943,6 +963,7 @@ "bps_clk", "bps_clk_src"; src-clock-name = "bps_clk_src"; + clock-control-debugfs = "true"; clocks = <&clock_camcc CAM_CC_BPS_AHB_CLK>, <&clock_camcc CAM_CC_BPS_AREG_CLK>, <&clock_camcc CAM_CC_BPS_AXI_CLK>, @@ -1065,6 +1086,7 @@ <&clock_camcc CAM_CC_FD_CORE_CLK>, <&clock_camcc CAM_CC_FD_CORE_UAR_CLK>; src-clock-name = "fd_core_clk_src"; + clock-control-debugfs = "true"; clock-cntl-level = "svs", "svs_l1", "turbo"; clock-rates = <0 0 0 0 0 400000000 0 0>, diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index 97cb9814b65d32c59a64ce27782171e9f7023148..c9669d958c2cae2ca806ecedea28491e27b7916c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -248,17 +248,17 @@ iova-mem-region-io { /* IO region is approximately 3 GB */ iova-region-name = "io"; - iova-region-start = <0xd911000>; - iova-region-len = <0xd26ef000>; + iova-region-start = <0xda00000>; + iova-region-len = <0xd2500000>; iova-region-id = <0x3>; status = "ok"; }; iova-mem-qdss-region { - /* qdss region is approximately 64K */ + /* qdss region is approximately 1MB */ iova-region-name = "qdss"; iova-region-start = <0xd900000>; - iova-region-len = <0x10000>; + iova-region-len = <0x100000>; iova-region-id = <0x5>; qdss-phy-addr = <0x16790000>; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-alpha.dts similarity index 98% rename from arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts rename to arch/arm64/boot/dts/qcom/sdw3100-apq8009w-alpha.dts index 20878c02864f895461b1b55b7e88428bf8c059bd..be8416f75a928e9b871c6d916a41022a8b1a2f2c 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-alpha.dts @@ -20,7 +20,7 @@ #include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG Alpha"; + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG Alpha SDW3100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts similarity index 98% rename from arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts rename to arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts index e7af39f46abf5a4f3db6c56cb68f1d00c11b1769..2b3fd84b498c651e5ff7502b391c7bbe15c1461f 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-apq8009w-wtp.dts @@ -20,7 +20,7 @@ #include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BLACKGHOST WTP"; + model = "Qualcomm Technologies, Inc. APQ8009W-PM660 BG WTP SDW3100"; compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; qcom,msm-id = <265 0>, <301 0>; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts similarity index 99% rename from arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts rename to arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts index 255c146e7fbbdaf66463a6a79051592759e3a286..89f0bb84b2cd5b089158567f603a1155fb6ce806 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts @@ -21,7 +21,7 @@ #include "msm8909-audio-bg_codec.dtsi" / { - model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BLACKGHOST WTP"; + model = "Qualcomm Technologies, Inc. MSM8909W-PM660 BG WTP SDW3100"; compatible = "qcom,msm8909-mtp", "qcom,msm8909", "qcom,mtp"; qcom,msm-id = <245 0>, <258 0>, diff --git a/arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..5fc70df2637451136c529e3e9636e6ba4d90b3be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-cdp-overlay.dts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1130-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..7bcd1b62b5d360d0401b8f4f83780df6752adcaa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-cdp.dts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..d2153c5af43c127651964603fa3927cb5598d108 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..b1d701e80c9a68e2d7bbd63c38469d50475ea59f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-cdp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,board-id = <1 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..3288a64fbe68187261b893ce36b1b1c7f571e164 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..6dbb766b2c9184d3ffb804d9dc7787287e0f9274 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-mtp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..432035f0ce15feccb2a839013577c63c4b55d730 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp-overlay.dts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..4e134c5e4de83703ab158e6636a85e735c116aa9 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-external-codec-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 1>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..f8a2a9abe48737441ea371f32c6301769838ad43 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-mtp-overlay.dts @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..7f9f1552166607f55ae253360e67db48689decf0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-mtp.dts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; + +&cam_cci { + /delete-node/ qcom,cam-sensor@1; + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_vio_ldo>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1352000 1800000 2850000 0>; + rgltr-max-voltage = <1352000 1800000 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>; + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET1"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..288f0ed604f4ee743d6fff9102d43bda9e4d4e22 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp-overlay.dts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..ea5f197dc24716b9a01faaf4f29117730535d58d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 0>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..9d7a70648c7a04cccbd80fc87b3e85b192171e3e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp-overlay.dts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts new file mode 100644 index 0000000000000000000000000000000000000000..04a045f0c21b14fde995ded58115b4cba03c84aa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-cdp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-cdp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec CDP"; + compatible = "qcom,sxr1130-cdp", "qcom,sxr1130", "qcom,cdp"; + qcom,board-id = <1 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..7d92bfc9739a83fee87fe4643ebdc5ccc6f466b6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..c551ef9e16a33a5a2297559b75bf492600ce7d4d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-mtp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660L, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a3f8044b15643065e47c5c6516da2953d975b204 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp-overlay.dts @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..a3c56fcda16325482061e25a64dbccf61bc2b889 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-external-codec-pm660a-mtp.dts @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-external-codec.dtsi" +#include "sdm670-ext-cdc-usbc-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660+PM660A, USB-C Audio, Ext. Audio Codec MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..a90d5506ca80f374307c3ee76505157982f96864 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp-overlay.dts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..c3bf64b48070cac82d1741d925ce0617a61a2df8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-mtp.dts @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660L, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0101011a 0x0 0x0>, + <0x0001001b 0x0102001a 0x0 0x0>, + <0x0001001b 0x0201011a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts new file mode 100644 index 0000000000000000000000000000000000000000..4b07f5ad136283cf7f9bf64ac643b0be4a80da74 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp-overlay.dts @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,msm-id = <371 0x0>; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts new file mode 100644 index 0000000000000000000000000000000000000000..e311b61a870ec72aa3a236c2c3a8feb0da9b7e73 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130-usbc-pm660a-mtp.dts @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sxr1130.dtsi" +#include "sdm670-mtp.dtsi" +#include "pm660a.dtsi" +#include "sdm670-int-cdc-usbc-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 PM660 + PM660A, USB-C Audio, MTP"; + compatible = "qcom,sxr1130-mtp", "qcom,sxr1130", "qcom,mtp"; + qcom,board-id = <8 2>; + qcom,pmic-id = <0x0001001b 0x0001011a 0x0 0x0>, + <0x0001001b 0x0002001a 0x0 0x0>, + <0x0001001b 0x0202001a 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130.dts b/arch/arm64/boot/dts/qcom/sxr1130.dts new file mode 100644 index 0000000000000000000000000000000000000000..abbf33424444c20c9a27484e8ca9f77179eba430 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130.dts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sxr1130.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130 SoC"; + compatible = "qcom,sxr1130"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sxr1130.dtsi b/arch/arm64/boot/dts/qcom/sxr1130.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..75707b197902e9cc76bb1063346a41a78d58839a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sxr1130.dtsi @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "qcs605.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SXR1130"; + qcom,msm-id = <371 0x0>; +}; diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index bf35544ee133958e44c60e5ed73035748b455e6e..6420837fc126603c6b16d3c6329270b8c58ce237 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -543,6 +543,7 @@ CONFIG_MSM_L2_SPM=y CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y @@ -587,6 +588,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y @@ -631,6 +634,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index ba390c4d34e6b15557158677820c74ebcf8335dd..40408634fb6a147a608c6c9c00c719df7a2120f5 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -560,6 +560,7 @@ CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_MSM_RPM_SMD=y @@ -606,6 +607,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y @@ -697,6 +700,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index eeb1d74c339847b300f4e191be3a649d5cd9d3f4..f3c1e7b5923d722e644e27465258ebe44992ac27 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -471,6 +471,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -556,6 +557,7 @@ CONFIG_MSM_L2_SPM=y CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_RPM_SMD=y CONFIG_QCOM_BUS_SCALING=y @@ -600,6 +602,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y @@ -644,6 +648,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index d0783cd63972bd7d01a2f37108fe344e756c44bc..8401173cd3f73895576265b477d69e25e75df3a7 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -481,6 +481,7 @@ CONFIG_USB_DWC3=y CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y CONFIG_USB_MSM_SSPHY_QMP=y @@ -572,6 +573,7 @@ CONFIG_QCOM_SCM=y CONFIG_MSM_BOOT_STATS=y CONFIG_MSM_CORE_HANG_DETECT=y CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QPNP_PBS=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_MSM_DEBUG_LAR_UNLOCK=y CONFIG_MSM_RPM_SMD=y @@ -619,6 +621,8 @@ CONFIG_ARM_GIC_V3_ACL=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM=y +CONFIG_NVMEM_SPMI_SDAM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y @@ -656,7 +660,6 @@ CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_OBJECTS_WORK=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y -CONFIG_SLUB_DEBUG_ON=y CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y @@ -711,6 +714,7 @@ CONFIG_SECURITY=y CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 6740bd7bf8bb6843c6b36018f673684b00013da0..ac21b6388323c0c5091156ecef93c24a423f1b77 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -513,6 +513,7 @@ CONFIG_IOMMU_TESTS=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM670_LLCC=y +CONFIG_QCOM_QCS605_LLCC=y CONFIG_QCOM_LLCC_PERFMON=m CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 53fb1cd53d0003017cc43df663f06a55535e35c1..9a6da1f8fb2c96141da432143a3c527b9f58869b 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -527,6 +527,7 @@ CONFIG_QCOM_CPUSS_DUMP=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_QCOM_LLCC=y CONFIG_QCOM_SDM670_LLCC=y +CONFIG_QCOM_QCS605_LLCC=y CONFIG_QCOM_LLCC_PERFMON=m CONFIG_MSM_SERVICE_LOCATOR=y CONFIG_MSM_SERVICE_NOTIFIER=y diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index e35e571cb7a858e0ef98e52a2a479130a3424200..0c541826b47da0d1446a5ead49f25421bcfe5c88 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -520,6 +520,7 @@ CONFIG_MSM_BOOT_STATS=y CONFIG_QCOM_EUD=y CONFIG_QCOM_WATCHDOG_V2=y CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_MINIDUMP=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y CONFIG_QCOM_SECURE_BUFFER=y diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 7457ce082b5ff06ad6cde7a7935f9d815e2bd256..d32a0160c89f74ad75abcd23162bfc84a621e259 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -117,7 +117,7 @@ static inline void atomic_and(int i, atomic_t *v) /* LSE atomics */ " mvn %w[i], %w[i]\n" " stclr %w[i], %[v]") - : [i] "+r" (w0), [v] "+Q" (v->counter) + : [i] "+&r" (w0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -135,7 +135,7 @@ static inline int atomic_fetch_and##name(int i, atomic_t *v) \ /* LSE atomics */ \ " mvn %w[i], %w[i]\n" \ " ldclr" #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -161,7 +161,7 @@ static inline void atomic_sub(int i, atomic_t *v) /* LSE atomics */ " neg %w[i], %w[i]\n" " stadd %w[i], %[v]") - : [i] "+r" (w0), [v] "+Q" (v->counter) + : [i] "+&r" (w0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -180,7 +180,7 @@ static inline int atomic_sub_return##name(int i, atomic_t *v) \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], w30, %[v]\n" \ " add %w[i], %w[i], w30") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS , ##cl); \ \ @@ -207,7 +207,7 @@ static inline int atomic_fetch_sub##name(int i, atomic_t *v) \ /* LSE atomics */ \ " neg %w[i], %w[i]\n" \ " ldadd" #mb " %w[i], %w[i], %[v]") \ - : [i] "+r" (w0), [v] "+Q" (v->counter) \ + : [i] "+&r" (w0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -314,7 +314,7 @@ static inline void atomic64_and(long i, atomic64_t *v) /* LSE atomics */ " mvn %[i], %[i]\n" " stclr %[i], %[v]") - : [i] "+r" (x0), [v] "+Q" (v->counter) + : [i] "+&r" (x0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -332,7 +332,7 @@ static inline long atomic64_fetch_and##name(long i, atomic64_t *v) \ /* LSE atomics */ \ " mvn %[i], %[i]\n" \ " ldclr" #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -358,7 +358,7 @@ static inline void atomic64_sub(long i, atomic64_t *v) /* LSE atomics */ " neg %[i], %[i]\n" " stadd %[i], %[v]") - : [i] "+r" (x0), [v] "+Q" (v->counter) + : [i] "+&r" (x0), [v] "+Q" (v->counter) : "r" (x1) : __LL_SC_CLOBBERS); } @@ -377,7 +377,7 @@ static inline long atomic64_sub_return##name(long i, atomic64_t *v) \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], x30, %[v]\n" \ " add %[i], %[i], x30") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -404,7 +404,7 @@ static inline long atomic64_fetch_sub##name(long i, atomic64_t *v) \ /* LSE atomics */ \ " neg %[i], %[i]\n" \ " ldadd" #mb " %[i], %[i], %[v]") \ - : [i] "+r" (x0), [v] "+Q" (v->counter) \ + : [i] "+&r" (x0), [v] "+Q" (v->counter) \ : "r" (x1) \ : __LL_SC_CLOBBERS, ##cl); \ \ @@ -516,7 +516,7 @@ static inline long __cmpxchg_double##name(unsigned long old1, \ " eor %[old1], %[old1], %[oldval1]\n" \ " eor %[old2], %[old2], %[oldval2]\n" \ " orr %[old1], %[old1], %[old2]") \ - : [old1] "+r" (x0), [old2] "+r" (x1), \ + : [old1] "+&r" (x0), [old2] "+&r" (x1), \ [v] "+Q" (*(unsigned long *)ptr) \ : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index b3423f54d59eac2291eba6005da5fb3e6c2dc260..829331c6703ff5cdb3307c4219512c8c87d39675 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -9,8 +9,6 @@ #ifndef __ASM_CPUFEATURE_H #define __ASM_CPUFEATURE_H -#include - #include #include #include @@ -27,6 +25,8 @@ #ifndef __ASSEMBLY__ +#include +#include #include extern const char *machine_name; @@ -98,6 +98,7 @@ struct arm64_cpu_capabilities { extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; +extern struct static_key_false arm64_const_caps_ready; bool this_cpu_has_cap(unsigned int cap); @@ -106,14 +107,27 @@ static inline bool cpu_have_feature(unsigned int num) return elf_hwcap & (1UL << num); } +/* System capability check for constant caps */ +static inline bool __cpus_have_const_cap(int num) +{ + if (num >= ARM64_NCAPS) + return false; + return static_branch_unlikely(&cpu_hwcap_keys[num]); +} + static inline bool cpus_have_cap(unsigned int num) { if (num >= ARM64_NCAPS) return false; - if (__builtin_constant_p(num)) - return static_branch_unlikely(&cpu_hwcap_keys[num]); + return test_bit(num, cpu_hwcaps); +} + +static inline bool cpus_have_const_cap(int num) +{ + if (static_branch_likely(&arm64_const_caps_ready)) + return __cpus_have_const_cap(num); else - return test_bit(num, cpu_hwcaps); + return cpus_have_cap(num); } static inline void cpus_set_cap(unsigned int num) @@ -123,7 +137,6 @@ static inline void cpus_set_cap(unsigned int num) num, ARM64_NCAPS); } else { __set_bit(num, cpu_hwcaps); - static_branch_enable(&cpu_hwcap_keys[num]); } } @@ -202,7 +215,7 @@ static inline bool cpu_supports_mixed_endian_el0(void) static inline bool system_supports_32bit_el0(void) { - return cpus_have_cap(ARM64_HAS_32BIT_EL0); + return cpus_have_const_cap(ARM64_HAS_32BIT_EL0); } static inline bool system_supports_mixed_endian_el0(void) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 0a33ea304e63e8e7e8d0edb07a51d8299469b652..2abb4493f4f6b2b03e08d596cf16026d52805276 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -358,9 +359,12 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, unsigned long vector_ptr) { /* - * Call initialization code, and switch to the full blown - * HYP code. + * Call initialization code, and switch to the full blown HYP code. + * If the cpucaps haven't been finalized yet, something has gone very + * wrong, and hyp will crash and burn when it uses any + * cpus_have_const_cap() wrapper. */ + BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr); } @@ -398,7 +402,7 @@ static inline void __cpu_init_stage2(void) static inline bool kvm_arm_harden_branch_predictor(void) { - return cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR); + return cpus_have_const_cap(ARM64_HARDEN_BRANCH_PREDICTOR); } #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 24a8369bbb69e20962caebb76128ac6726d87c19..ecc2ae66ad988566ad3b16895298338084a0e89a 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -341,7 +341,7 @@ static inline void *kvm_get_hyp_vector(void) vect = __bp_harden_hyp_vecs_start + data->hyp_vectors_slot * SZ_2K; - if (!cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN)) + if (!cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN)) vect = lm_alias(vect); } diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 24c780d4f1c6efccf0b6642f054e3d6f7c3abd7c..1464b50e560ac6d302a9509f556145fbc102dda8 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -38,7 +38,7 @@ typedef struct { static inline bool arm64_kernel_unmapped_at_el0(void) { return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && - cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); + cpus_have_const_cap(ARM64_UNMAP_KERNEL_AT_EL0); } typedef void (*bp_hardening_cb_t)(void); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 675bf45fc0f94b688be5667f96401d70afa8e202..2eea5929ccaca5a7d832d919cc8cc253f5b1ee4d 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -762,7 +762,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, * ThunderX leads to apparent I-cache corruption of kernel text, which * ends as well as you might imagine. Don't even try. */ - if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_27456)) { + if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_27456)) { str = "ARM64_WORKAROUND_CAVIUM_27456"; __kpti_forced = -1; } @@ -825,7 +825,7 @@ static int __init parse_kpti(char *str) __kpti_forced = enabled ? 1 : -1; return 0; } -__setup("kpti=", parse_kpti); +early_param("kpti", parse_kpti); #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ static const struct arm64_cpu_capabilities arm64_features[] = { @@ -1051,8 +1051,16 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, */ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) { - for (; caps->matches; caps++) - if (caps->enable && cpus_have_cap(caps->capability)) + for (; caps->matches; caps++) { + unsigned int num = caps->capability; + + if (!cpus_have_cap(num)) + continue; + + /* Ensure cpus_have_const_cap(num) works */ + static_branch_enable(&cpu_hwcap_keys[num]); + + if (caps->enable) { /* * Use stop_machine() as it schedules the work allowing * us to modify PSTATE, instead of on_each_cpu() which @@ -1060,6 +1068,8 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) * we return. */ stop_machine(caps->enable, (void *)caps, cpu_online_mask); + } + } } /* @@ -1163,6 +1173,14 @@ static void __init setup_feature_capabilities(void) enable_cpu_capabilities(arm64_features); } +DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready); +EXPORT_SYMBOL(arm64_const_caps_ready); + +static void __init mark_const_caps_ready(void) +{ + static_branch_enable(&arm64_const_caps_ready); +} + extern const struct arm64_cpu_capabilities arm64_errata[]; bool this_cpu_has_cap(unsigned int cap) @@ -1179,6 +1197,7 @@ void __init setup_cpu_features(void) /* Set the CPU feature capabilies */ setup_feature_capabilities(); enable_errata_workarounds(); + mark_const_caps_ready(); setup_elf_hwcaps(arm64_elf_hwcaps); if (system_supports_32bit_el0()) @@ -1203,5 +1222,5 @@ void __init setup_cpu_features(void) static bool __maybe_unused cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused) { - return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); + return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO)); } diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 08ca9dc390e134fd10596586d6baf0038e16b4f4..0a66fa1db63a2890b2761d77f269a29450ffaab5 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -360,7 +360,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, memset(childregs, 0, sizeof(struct pt_regs)); childregs->pstate = PSR_MODE_EL1h; if (IS_ENABLED(CONFIG_ARM64_UAO) && - cpus_have_cap(ARM64_HAS_UAO)) + cpus_have_const_cap(ARM64_HAS_UAO)) childregs->pstate |= PSR_UAO_BIT; p->thread.cpu_context.x19 = stack_start; p->thread.cpu_context.x20 = stk_sz; diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c index 01e88c8bcab0fd4aa96409fe751745141737cb39..8e2c1d68866cffdb031fa12814ea4a01e8f0b54b 100644 --- a/arch/arm64/mm/ioremap.c +++ b/arch/arm64/mm/ioremap.c @@ -64,6 +64,11 @@ static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size, addr = (unsigned long)area->addr; area->phys_addr = phys_addr; +#ifdef CONFIG_ARCH_MSM8953_SOC_SETTINGS + if (phys_addr >= MSM8953_TLMM_START_ADDR && + phys_addr <= MSM8953_TLMM_END_ADDR) + prot = __pgprot(PROT_DEVICE_nGnRnE); +#endif err = ioremap_page_range(addr, addr + size, phys_addr, prot); if (err) { vunmap((void *)addr); diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 3a9af60a426d2a49cc10ac858d23a45ae705b9ae..efb32b2fb8bc89b9d777c96dc469b69d8708b510 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -241,8 +241,9 @@ ENDPROC(idmap_cpu_replace_ttbr1) .macro __idmap_kpti_put_pgtable_ent_ng, type orr \type, \type, #PTE_NG // Same bit for blocks and pages - str \type, [cur_\()\type\()p] // Update the entry and ensure it - dc civac, cur_\()\type\()p // is visible to all CPUs. + str \type, [cur_\()\type\()p] // Update the entry and ensure + dmb sy // that it is visible to all + dc civac, cur_\()\type\()p // CPUs. .endm /* diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c index 6e4955bc542bfc591721aa23fdac1fdbaf66b586..fcd52cefee29619ce2f90913dd5b546a50183bbe 100644 --- a/arch/m68k/mm/kmap.c +++ b/arch/m68k/mm/kmap.c @@ -88,7 +88,8 @@ static inline void free_io_area(void *addr) for (p = &iolist ; (tmp = *p) ; p = &tmp->next) { if (tmp->addr == addr) { *p = tmp->next; - __iounmap(tmp->addr, tmp->size); + /* remove gap added in get_io_area() */ + __iounmap(tmp->addr, tmp->size - IO_SIZE); kfree(tmp); return; } diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 6054d49e608eec038e1bbd49599bc783270aa09a..8c9cbf13d32a0a471bc6f2653bbb3c459b1b2c2c 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -212,6 +212,12 @@ static int __init bcm47xx_cpu_fixes(void) */ if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706) cpu_wait = NULL; + + /* + * BCM47XX Erratum "R10: PCIe Transactions Periodically Fail" + * Enable ExternalSync for sync instruction to take effect + */ + set_c0_config7(MIPS_CONF7_ES); break; #endif } diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index ecabc00c1e665ae237faf60a10f07599d04a65c3..853b2f4954fa5e7be5e0d266e1146b56a9a13434 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -412,6 +412,8 @@ static inline type pfx##in##bwlq##p(unsigned long port) \ __val = *__addr; \ slow; \ \ + /* prevent prefetching of coherent DMA data prematurely */ \ + rmb(); \ return pfx##ioswab##bwlq(__addr, __val); \ } diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index df78b2ca70ebd8c6b57348f9e62f304394f4f3d0..22a6782f84f5010f8f9e348e557c8bd2cca19d1e 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -663,6 +663,8 @@ #define MIPS_CONF7_WII (_ULCAST_(1) << 31) #define MIPS_CONF7_RPS (_ULCAST_(1) << 2) +/* ExternalSync */ +#define MIPS_CONF7_ES (_ULCAST_(1) << 8) #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) @@ -2641,6 +2643,7 @@ __BUILD_SET_C0(status) __BUILD_SET_C0(cause) __BUILD_SET_C0(config) __BUILD_SET_C0(config5) +__BUILD_SET_C0(config7) __BUILD_SET_C0(intcontrol) __BUILD_SET_C0(intctl) __BUILD_SET_C0(srsmap) diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S index 2f7c734771f4e0ad283bb6bf5ee11a0f4b57d707..0df911e772ae0f55f0f46c964b1d1d699566b05b 100644 --- a/arch/mips/kernel/mcount.S +++ b/arch/mips/kernel/mcount.S @@ -116,10 +116,20 @@ ftrace_stub: NESTED(_mcount, PT_SIZE, ra) PTR_LA t1, ftrace_stub PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */ - bne t1, t2, static_trace + beq t1, t2, fgraph_trace nop + MCOUNT_SAVE_REGS + + move a0, ra /* arg1: self return address */ + jalr t2 /* (1) call *ftrace_trace_function */ + move a1, AT /* arg2: parent's return address */ + + MCOUNT_RESTORE_REGS + +fgraph_trace: #ifdef CONFIG_FUNCTION_GRAPH_TRACER + PTR_LA t1, ftrace_stub PTR_L t3, ftrace_graph_return bne t1, t3, ftrace_graph_caller nop @@ -128,24 +138,11 @@ NESTED(_mcount, PT_SIZE, ra) bne t1, t3, ftrace_graph_caller nop #endif - b ftrace_stub -#ifdef CONFIG_32BIT - addiu sp, sp, 8 -#else - nop -#endif -static_trace: - MCOUNT_SAVE_REGS - - move a0, ra /* arg1: self return address */ - jalr t2 /* (1) call *ftrace_trace_function */ - move a1, AT /* arg2: parent's return address */ - - MCOUNT_RESTORE_REGS #ifdef CONFIG_32BIT addiu sp, sp, 8 #endif + .globl ftrace_stub ftrace_stub: RETURN_BACK diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 6e716a5f117374fff602b6cad95f823c1d56d375..ebb575c4231b4d383363791bb96746ca22bbed66 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -699,6 +699,10 @@ int mips_set_process_fp_mode(struct task_struct *task, unsigned int value) if (value & ~known_bits) return -EOPNOTSUPP; + /* Setting FRE without FR is not supported. */ + if ((value & (PR_FP_MODE_FR | PR_FP_MODE_FRE)) == PR_FP_MODE_FRE) + return -EOPNOTSUPP; + /* Avoid inadvertently triggering emulation */ if ((value & PR_FP_MODE_FR) && raw_cpu_has_fpu && !(raw_current_cpu_data.fpu_id & MIPS_FPIR_F64)) diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 8f7bf74d1c0b2c180e570f48d5d2f8d839ed449b..4f64913b4b4c0d2e03c4362b5c93c51d460c4b23 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -838,7 +838,7 @@ long arch_ptrace(struct task_struct *child, long request, break; } #endif - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index bc9afbabbe143e5b9fc94a696ccab61cb4fb784b..b1e9457381389c2f4239a1292137474248bd4ed9 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -107,7 +107,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, addr & 1); break; } - tmp = get_fpr32(&fregs[addr - FPR_BASE], 0); + tmp = get_fpr64(&fregs[addr - FPR_BASE], 0); break; case PC: tmp = regs->cp0_epc; diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 903e76a9f158221b359c844f5e1e2ad23c852177..e2200100828d4b577ea92be85ab34816a51c9eeb 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -51,6 +51,27 @@ #define EX_PPR 88 /* SMT thread status register (priority) */ #define EX_CTR 96 +#define STF_ENTRY_BARRIER_SLOT \ + STF_ENTRY_BARRIER_FIXUP_SECTION; \ + nop; \ + nop; \ + nop + +#define STF_EXIT_BARRIER_SLOT \ + STF_EXIT_BARRIER_FIXUP_SECTION; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop; \ + nop + +/* + * r10 must be free to use, r13 must be paca + */ +#define INTERRUPT_TO_KERNEL \ + STF_ENTRY_BARRIER_SLOT + /* * Macros for annotating the expected destination of (h)rfid * @@ -67,16 +88,19 @@ rfid #define RFI_TO_USER \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback #define RFI_TO_USER_OR_KERNEL \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback #define RFI_TO_GUEST \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ rfid; \ b rfi_flush_fallback @@ -85,21 +109,25 @@ hrfid #define HRFI_TO_USER \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_USER_OR_KERNEL \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_GUEST \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback #define HRFI_TO_UNKNOWN \ + STF_EXIT_BARRIER_SLOT; \ RFI_FLUSH_SLOT; \ hrfid; \ b hrfi_flush_fallback @@ -225,6 +253,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943) #define __EXCEPTION_PROLOG_1(area, extra, vec) \ OPT_SAVE_REG_TO_PACA(area+EX_PPR, r9, CPU_FTR_HAS_PPR); \ OPT_SAVE_REG_TO_PACA(area+EX_CFAR, r10, CPU_FTR_CFAR); \ + INTERRUPT_TO_KERNEL; \ SAVE_CTR(r10, area); \ mfcr r9; \ extra(vec); \ diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h index 7b332342071c2d2a7a051a3679426a758d470176..0bf8202feca6559704cf34c89c3180b05d2da08f 100644 --- a/arch/powerpc/include/asm/feature-fixups.h +++ b/arch/powerpc/include/asm/feature-fixups.h @@ -189,6 +189,22 @@ void apply_feature_fixups(void); void setup_feature_keys(void); #endif +#define STF_ENTRY_BARRIER_FIXUP_SECTION \ +953: \ + .pushsection __stf_entry_barrier_fixup,"a"; \ + .align 2; \ +954: \ + FTR_ENTRY_OFFSET 953b-954b; \ + .popsection; + +#define STF_EXIT_BARRIER_FIXUP_SECTION \ +955: \ + .pushsection __stf_exit_barrier_fixup,"a"; \ + .align 2; \ +956: \ + FTR_ENTRY_OFFSET 955b-956b; \ + .popsection; + #define RFI_FLUSH_FIXUP_SECTION \ 951: \ .pushsection __rfi_flush_fixup,"a"; \ @@ -200,6 +216,9 @@ void setup_feature_keys(void); #ifndef __ASSEMBLY__ +extern long stf_barrier_fallback; +extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup; +extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup; extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup; #endif diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index dc0996b9d75db0e7e64e0192ba8d9d015dc6542e..9d978102bf0dad842067d5b9e78058fc81e1a7ba 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h @@ -313,6 +313,9 @@ #define H_CPU_CHAR_L1D_FLUSH_ORI30 (1ull << 61) // IBM bit 2 #define H_CPU_CHAR_L1D_FLUSH_TRIG2 (1ull << 60) // IBM bit 3 #define H_CPU_CHAR_L1D_THREAD_PRIV (1ull << 59) // IBM bit 4 +#define H_CPU_CHAR_BRANCH_HINTS_HONORED (1ull << 58) // IBM bit 5 +#define H_CPU_CHAR_THREAD_RECONFIG_CTRL (1ull << 57) // IBM bit 6 +#define H_CPU_CHAR_COUNT_CACHE_DISABLED (1ull << 56) // IBM bit 7 #define H_CPU_BEHAV_FAVOUR_SECURITY (1ull << 63) // IBM bit 0 #define H_CPU_BEHAV_L1D_FLUSH_PR (1ull << 62) // IBM bit 1 diff --git a/arch/powerpc/include/asm/security_features.h b/arch/powerpc/include/asm/security_features.h new file mode 100644 index 0000000000000000000000000000000000000000..44989b22383c24b92caaf3dbb3d9831c79cd967f --- /dev/null +++ b/arch/powerpc/include/asm/security_features.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Security related feature bit definitions. + * + * Copyright 2018, Michael Ellerman, IBM Corporation. + */ + +#ifndef _ASM_POWERPC_SECURITY_FEATURES_H +#define _ASM_POWERPC_SECURITY_FEATURES_H + + +extern unsigned long powerpc_security_features; +extern bool rfi_flush; + +/* These are bit flags */ +enum stf_barrier_type { + STF_BARRIER_NONE = 0x1, + STF_BARRIER_FALLBACK = 0x2, + STF_BARRIER_EIEIO = 0x4, + STF_BARRIER_SYNC_ORI = 0x8, +}; + +void setup_stf_barrier(void); +void do_stf_barrier_fixups(enum stf_barrier_type types); + +static inline void security_ftr_set(unsigned long feature) +{ + powerpc_security_features |= feature; +} + +static inline void security_ftr_clear(unsigned long feature) +{ + powerpc_security_features &= ~feature; +} + +static inline bool security_ftr_enabled(unsigned long feature) +{ + return !!(powerpc_security_features & feature); +} + + +// Features indicating support for Spectre/Meltdown mitigations + +// The L1-D cache can be flushed with ori r30,r30,0 +#define SEC_FTR_L1D_FLUSH_ORI30 0x0000000000000001ull + +// The L1-D cache can be flushed with mtspr 882,r0 (aka SPRN_TRIG2) +#define SEC_FTR_L1D_FLUSH_TRIG2 0x0000000000000002ull + +// ori r31,r31,0 acts as a speculation barrier +#define SEC_FTR_SPEC_BAR_ORI31 0x0000000000000004ull + +// Speculation past bctr is disabled +#define SEC_FTR_BCCTRL_SERIALISED 0x0000000000000008ull + +// Entries in L1-D are private to a SMT thread +#define SEC_FTR_L1D_THREAD_PRIV 0x0000000000000010ull + +// Indirect branch prediction cache disabled +#define SEC_FTR_COUNT_CACHE_DISABLED 0x0000000000000020ull + + +// Features indicating need for Spectre/Meltdown mitigations + +// The L1-D cache should be flushed on MSR[HV] 1->0 transition (hypervisor to guest) +#define SEC_FTR_L1D_FLUSH_HV 0x0000000000000040ull + +// The L1-D cache should be flushed on MSR[PR] 0->1 transition (kernel to userspace) +#define SEC_FTR_L1D_FLUSH_PR 0x0000000000000080ull + +// A speculation barrier should be used for bounds checks (Spectre variant 1) +#define SEC_FTR_BNDS_CHK_SPEC_BAR 0x0000000000000100ull + +// Firmware configuration indicates user favours security over performance +#define SEC_FTR_FAVOUR_SECURITY 0x0000000000000200ull + + +// Features enabled by default +#define SEC_FTR_DEFAULT \ + (SEC_FTR_L1D_FLUSH_HV | \ + SEC_FTR_L1D_FLUSH_PR | \ + SEC_FTR_BNDS_CHK_SPEC_BAR | \ + SEC_FTR_FAVOUR_SECURITY) + +#endif /* _ASM_POWERPC_SECURITY_FEATURES_H */ diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h index 6825a67cc3db33936416b8fc1053efc21f847f7c..3f160cd201074b1e30df2a294ceb4b83bd19ded8 100644 --- a/arch/powerpc/include/asm/setup.h +++ b/arch/powerpc/include/asm/setup.h @@ -48,7 +48,7 @@ enum l1d_flush_type { L1D_FLUSH_MTTRIG = 0x8, }; -void __init setup_rfi_flush(enum l1d_flush_type, bool enable); +void setup_rfi_flush(enum l1d_flush_type, bool enable); void do_rfi_flush_fixups(enum l1d_flush_type types); #endif /* !__ASSEMBLY__ */ diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index adb52d101133d856baf21d241b3f01cb1ab254e9..13885786282b53a91dfaf83810ac1f0a48ba6990 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -44,7 +44,7 @@ obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \ obj-$(CONFIG_VDSO32) += vdso32/ obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_ppc970.o cpu_setup_pa6t.o -obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o +obj-$(CONFIG_PPC_BOOK3S_64) += cpu_setup_power.o security.o obj-$(CONFIG_PPC_BOOK3S_64) += mce.o mce_power.o obj-$(CONFIG_PPC_BOOK3E_64) += exceptions-64e.o idle_book3e.o obj-$(CONFIG_PPC64) += vdso64/ diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index 9e05c8828ee218705f6fe508d5396e44a983a24f..ff45d007d19568d08d3b4eaba0ab863e406cfd5d 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -28,6 +28,7 @@ _GLOBAL(__setup_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_tlb_power7 @@ -41,6 +42,7 @@ _GLOBAL(__restore_cpu_power7) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR bl __init_LPCR bl __init_tlb_power7 @@ -57,6 +59,7 @@ _GLOBAL(__setup_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH bl __init_LPCR @@ -78,6 +81,7 @@ _GLOBAL(__restore_cpu_power8) beqlr li r0,0 mtspr SPRN_LPID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR ori r3, r3, LPCR_PECEDH bl __init_LPCR @@ -98,6 +102,7 @@ _GLOBAL(__setup_cpu_power9) li r0,0 mtspr SPRN_LPID,r0 mtspr SPRN_PID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) or r3, r3, r4 @@ -121,6 +126,7 @@ _GLOBAL(__restore_cpu_power9) li r0,0 mtspr SPRN_LPID,r0 mtspr SPRN_PID,r0 + mtspr SPRN_PCR,r0 mfspr r3,SPRN_LPCR LOAD_REG_IMMEDIATE(r4, LPCR_PECEDH | LPCR_PECE_HVEE | LPCR_HVICE) or r3, r3, r4 diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2dc52e6d2af47a682fb0cb55821be58e14653eb9..e24ae0fa80ed9b844aa7d3f7a967314b446a7e5c 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -586,6 +586,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT) * actually hit this code path. */ + isync slbie r6 slbie r6 /* Workaround POWER5 < DD2.1 issue */ slbmte r7,r0 diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 94b5dfb087e9e806ac5296a3f10a992c504e4a54..d50cc9b38b8021e31214448ebc0caa6968724ce4 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -846,7 +846,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_TM) #endif -EXC_REAL_MASKABLE(decrementer, 0x900, 0x980) +EXC_REAL_OOL_MASKABLE(decrementer, 0x900, 0x980) EXC_VIRT_MASKABLE(decrementer, 0x4900, 0x4980, 0x900) TRAMP_KVM(PACA_EXGEN, 0x900) EXC_COMMON_ASYNC(decrementer_common, 0x900, timer_interrupt) @@ -884,6 +884,7 @@ BEGIN_FTR_SECTION \ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) \ mr r9,r13 ; \ GET_PACA(r13) ; \ + INTERRUPT_TO_KERNEL ; \ mfspr r11,SPRN_SRR0 ; \ 0: @@ -1353,6 +1354,19 @@ masked_##_H##interrupt: \ ##_H##RFI_TO_KERNEL; \ b . +TRAMP_REAL_BEGIN(stf_barrier_fallback) + std r9,PACA_EXRFI+EX_R9(r13) + std r10,PACA_EXRFI+EX_R10(r13) + sync + ld r9,PACA_EXRFI+EX_R9(r13) + ld r10,PACA_EXRFI+EX_R10(r13) + ori 31,31,0 + .rept 14 + b 1f +1: + .endr + blr + /* * Real mode exceptions actually use this too, but alternate * instruction code patches (which end up in the common .text area) diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c index 8f0c7c5d93f2de840826bc22f115d5528c20ea1c..93a6eeba3ace2cec5dee8548d808bfdb688288e8 100644 --- a/arch/powerpc/kernel/fadump.c +++ b/arch/powerpc/kernel/fadump.c @@ -1033,6 +1033,9 @@ void fadump_cleanup(void) init_fadump_mem_struct(&fdm, be64_to_cpu(fdm_active->cpu_state_data.destination_address)); fadump_invalidate_dump(&fdm); + } else if (fw_dump.dump_registered) { + /* Un-register Firmware-assisted dump if it was registered. */ + fadump_unregister_dump(&fdm); } } diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 469d86d1c2a5a79f803c2afbac4c220cd478d5fc..532c585ec24b08bc47d3bec65fc3dfcdab57967f 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -175,8 +175,8 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) if (cpu_has_feature(CPU_FTR_DAWR)) { length_max = 512 ; /* 64 doublewords */ /* DAWR region can't cross 512 boundary */ - if ((bp->attr.bp_addr >> 10) != - ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 10)) + if ((bp->attr.bp_addr >> 9) != + ((bp->attr.bp_addr + bp->attr.bp_len - 1) >> 9)) return -EINVAL; } if (info->len > diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index d97370866a5fa74bcd7c637e5158e67691475b86..adfa63e7df8cd1d26e373bb01a5f4c3e45041684 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -2380,6 +2380,7 @@ static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, /* Create a new breakpoint request if one doesn't exist already */ hw_breakpoint_init(&attr); attr.bp_addr = hw_brk.address; + attr.bp_len = 8; arch_bp_generic_fields(hw_brk.type, &attr.bp_type); diff --git a/arch/powerpc/kernel/security.c b/arch/powerpc/kernel/security.c new file mode 100644 index 0000000000000000000000000000000000000000..2277df84ef6e5ad66d0171a8eecf4188a7b06e1a --- /dev/null +++ b/arch/powerpc/kernel/security.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Security related flags and so on. +// +// Copyright 2018, Michael Ellerman, IBM Corporation. + +#include +#include +#include +#include + +#include + + +unsigned long powerpc_security_features __read_mostly = SEC_FTR_DEFAULT; + +ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) +{ + bool thread_priv; + + thread_priv = security_ftr_enabled(SEC_FTR_L1D_THREAD_PRIV); + + if (rfi_flush || thread_priv) { + struct seq_buf s; + seq_buf_init(&s, buf, PAGE_SIZE - 1); + + seq_buf_printf(&s, "Mitigation: "); + + if (rfi_flush) + seq_buf_printf(&s, "RFI Flush"); + + if (rfi_flush && thread_priv) + seq_buf_printf(&s, ", "); + + if (thread_priv) + seq_buf_printf(&s, "L1D private per thread"); + + seq_buf_printf(&s, "\n"); + + return s.len; + } + + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (!security_ftr_enabled(SEC_FTR_BNDS_CHK_SPEC_BAR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) +{ + bool bcs, ccd, ori; + struct seq_buf s; + + seq_buf_init(&s, buf, PAGE_SIZE - 1); + + bcs = security_ftr_enabled(SEC_FTR_BCCTRL_SERIALISED); + ccd = security_ftr_enabled(SEC_FTR_COUNT_CACHE_DISABLED); + ori = security_ftr_enabled(SEC_FTR_SPEC_BAR_ORI31); + + if (bcs || ccd) { + seq_buf_printf(&s, "Mitigation: "); + + if (bcs) + seq_buf_printf(&s, "Indirect branch serialisation (kernel only)"); + + if (bcs && ccd) + seq_buf_printf(&s, ", "); + + if (ccd) + seq_buf_printf(&s, "Indirect branch cache disabled"); + } else + seq_buf_printf(&s, "Vulnerable"); + + if (ori) + seq_buf_printf(&s, ", ori31 speculation barrier enabled"); + + seq_buf_printf(&s, "\n"); + + return s.len; +} + +/* + * Store-forwarding barrier support. + */ + +static enum stf_barrier_type stf_enabled_flush_types; +static bool no_stf_barrier; +bool stf_barrier; + +static int __init handle_no_stf_barrier(char *p) +{ + pr_info("stf-barrier: disabled on command line."); + no_stf_barrier = true; + return 0; +} + +early_param("no_stf_barrier", handle_no_stf_barrier); + +/* This is the generic flag used by other architectures */ +static int __init handle_ssbd(char *p) +{ + if (!p || strncmp(p, "auto", 5) == 0 || strncmp(p, "on", 2) == 0 ) { + /* Until firmware tells us, we have the barrier with auto */ + return 0; + } else if (strncmp(p, "off", 3) == 0) { + handle_no_stf_barrier(NULL); + return 0; + } else + return 1; + + return 0; +} +early_param("spec_store_bypass_disable", handle_ssbd); + +/* This is the generic flag used by other architectures */ +static int __init handle_no_ssbd(char *p) +{ + handle_no_stf_barrier(NULL); + return 0; +} +early_param("nospec_store_bypass_disable", handle_no_ssbd); + +static void stf_barrier_enable(bool enable) +{ + if (enable) + do_stf_barrier_fixups(stf_enabled_flush_types); + else + do_stf_barrier_fixups(STF_BARRIER_NONE); + + stf_barrier = enable; +} + +void setup_stf_barrier(void) +{ + enum stf_barrier_type type; + bool enable, hv; + + hv = cpu_has_feature(CPU_FTR_HVMODE); + + /* Default to fallback in case fw-features are not available */ + if (cpu_has_feature(CPU_FTR_ARCH_300)) + type = STF_BARRIER_EIEIO; + else if (cpu_has_feature(CPU_FTR_ARCH_207S)) + type = STF_BARRIER_SYNC_ORI; + else if (cpu_has_feature(CPU_FTR_ARCH_206)) + type = STF_BARRIER_FALLBACK; + else + type = STF_BARRIER_NONE; + + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && hv)); + + if (type == STF_BARRIER_FALLBACK) { + pr_info("stf-barrier: fallback barrier available\n"); + } else if (type == STF_BARRIER_SYNC_ORI) { + pr_info("stf-barrier: hwsync barrier available\n"); + } else if (type == STF_BARRIER_EIEIO) { + pr_info("stf-barrier: eieio barrier available\n"); + } + + stf_enabled_flush_types = type; + + if (!no_stf_barrier) + stf_barrier_enable(enable); +} + +ssize_t cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) +{ + if (stf_barrier && stf_enabled_flush_types != STF_BARRIER_NONE) { + const char *type; + switch (stf_enabled_flush_types) { + case STF_BARRIER_EIEIO: + type = "eieio"; + break; + case STF_BARRIER_SYNC_ORI: + type = "hwsync"; + break; + case STF_BARRIER_FALLBACK: + type = "fallback"; + break; + default: + type = "unknown"; + } + return sprintf(buf, "Mitigation: Kernel entry/exit barrier (%s)\n", type); + } + + if (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) && + !security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR)) + return sprintf(buf, "Not affected\n"); + + return sprintf(buf, "Vulnerable\n"); +} + +#ifdef CONFIG_DEBUG_FS +static int stf_barrier_set(void *data, u64 val) +{ + bool enable; + + if (val == 1) + enable = true; + else if (val == 0) + enable = false; + else + return -EINVAL; + + /* Only do anything if we're changing state */ + if (enable != stf_barrier) + stf_barrier_enable(enable); + + return 0; +} + +static int stf_barrier_get(void *data, u64 *val) +{ + *val = stf_barrier ? 1 : 0; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(fops_stf_barrier, stf_barrier_get, stf_barrier_set, "%llu\n"); + +static __init int stf_barrier_debugfs_init(void) +{ + debugfs_create_file("stf_barrier", 0600, powerpc_debugfs_root, NULL, &fops_stf_barrier); + return 0; +} +device_initcall(stf_barrier_debugfs_init); +#endif /* CONFIG_DEBUG_FS */ diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 5243501d95ef0cf766fe39efc25733407b4cbaa3..fdba10695208f03f71a670a7e3a0723c19097f85 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -679,6 +679,7 @@ static int __init disable_hardlockup_detector(void) return 0; } early_initcall(disable_hardlockup_detector); +#endif /* CONFIG_HARDLOCKUP_DETECTOR */ #ifdef CONFIG_PPC_BOOK3S_64 static enum l1d_flush_type enabled_flush_types; @@ -716,9 +717,6 @@ static void do_nothing(void *unused) void rfi_flush_enable(bool enable) { - if (rfi_flush == enable) - return; - if (enable) { do_rfi_flush_fixups(enabled_flush_types); on_each_cpu(do_nothing, NULL, 1); @@ -728,11 +726,15 @@ void rfi_flush_enable(bool enable) rfi_flush = enable; } -static void init_fallback_flush(void) +static void __ref init_fallback_flush(void) { u64 l1d_size, limit; int cpu; + /* Only allocate the fallback flush area once (at boot time). */ + if (l1d_flush_fallback_area) + return; + l1d_size = ppc64_caches.dsize; limit = min(safe_stack_limit(), ppc64_rma_size); @@ -750,18 +752,18 @@ static void init_fallback_flush(void) } } -void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) +void setup_rfi_flush(enum l1d_flush_type types, bool enable) { if (types & L1D_FLUSH_FALLBACK) { - pr_info("rfi-flush: Using fallback displacement flush\n"); + pr_info("rfi-flush: fallback displacement flush available\n"); init_fallback_flush(); } if (types & L1D_FLUSH_ORI) - pr_info("rfi-flush: Using ori type flush\n"); + pr_info("rfi-flush: ori type flush available\n"); if (types & L1D_FLUSH_MTTRIG) - pr_info("rfi-flush: Using mttrig type flush\n"); + pr_info("rfi-flush: mttrig type flush available\n"); enabled_flush_types = types; @@ -772,13 +774,19 @@ void __init setup_rfi_flush(enum l1d_flush_type types, bool enable) #ifdef CONFIG_DEBUG_FS static int rfi_flush_set(void *data, u64 val) { + bool enable; + if (val == 1) - rfi_flush_enable(true); + enable = true; else if (val == 0) - rfi_flush_enable(false); + enable = false; else return -EINVAL; + /* Only do anything if we're changing state */ + if (enable != rfi_flush) + rfi_flush_enable(enable); + return 0; } @@ -797,13 +805,4 @@ static __init int rfi_flush_debugfs_init(void) } device_initcall(rfi_flush_debugfs_init); #endif - -ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) -{ - if (rfi_flush) - return sprintf(buf, "Mitigation: RFI Flush\n"); - - return sprintf(buf, "Vulnerable\n"); -} #endif /* CONFIG_PPC_BOOK3S_64 */ -#endif diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index b61fb7902018e82e68a2b2f5042de63136adb276..c16fddbb6ab8fc468b09a327725e9f48a4c2910c 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -133,6 +133,20 @@ SECTIONS RODATA #ifdef CONFIG_PPC64 + . = ALIGN(8); + __stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) { + __start___stf_entry_barrier_fixup = .; + *(__stf_entry_barrier_fixup) + __stop___stf_entry_barrier_fixup = .; + } + + . = ALIGN(8); + __stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) { + __start___stf_exit_barrier_fixup = .; + *(__stf_exit_barrier_fixup) + __stop___stf_exit_barrier_fixup = .; + } + . = ALIGN(8); __rfi_flush_fixup : AT(ADDR(__rfi_flush_fixup) - LOAD_OFFSET) { __start___rfi_flush_fixup = .; diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 46c8338a61bc81187f33307a7ef6ef5b805ecdfb..cf1398e3c2e08a41bfc4b6735d9942afdace1870 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,120 @@ void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) } #ifdef CONFIG_PPC_BOOK3S_64 +void do_stf_entry_barrier_fixups(enum stf_barrier_type types) +{ + unsigned int instrs[3], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___stf_entry_barrier_fixup), + end = PTRRELOC(&__stop___stf_entry_barrier_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + + i = 0; + if (types & STF_BARRIER_FALLBACK) { + instrs[i++] = 0x7d4802a6; /* mflr r10 */ + instrs[i++] = 0x60000000; /* branch patched below */ + instrs[i++] = 0x7d4803a6; /* mtlr r10 */ + } else if (types & STF_BARRIER_EIEIO) { + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ + } else if (types & STF_BARRIER_SYNC_ORI) { + instrs[i++] = 0x7c0004ac; /* hwsync */ + instrs[i++] = 0xe94d0000; /* ld r10,0(r13) */ + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + } + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + + if (types & STF_BARRIER_FALLBACK) + patch_branch(dest + 1, (unsigned long)&stf_barrier_fallback, + BRANCH_SET_LINK); + else + patch_instruction(dest + 1, instrs[1]); + + patch_instruction(dest + 2, instrs[2]); + } + + printk(KERN_DEBUG "stf-barrier: patched %d entry locations (%s barrier)\n", i, + (types == STF_BARRIER_NONE) ? "no" : + (types == STF_BARRIER_FALLBACK) ? "fallback" : + (types == STF_BARRIER_EIEIO) ? "eieio" : + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" + : "unknown"); +} + +void do_stf_exit_barrier_fixups(enum stf_barrier_type types) +{ + unsigned int instrs[6], *dest; + long *start, *end; + int i; + + start = PTRRELOC(&__start___stf_exit_barrier_fixup), + end = PTRRELOC(&__stop___stf_exit_barrier_fixup); + + instrs[0] = 0x60000000; /* nop */ + instrs[1] = 0x60000000; /* nop */ + instrs[2] = 0x60000000; /* nop */ + instrs[3] = 0x60000000; /* nop */ + instrs[4] = 0x60000000; /* nop */ + instrs[5] = 0x60000000; /* nop */ + + i = 0; + if (types & STF_BARRIER_FALLBACK || types & STF_BARRIER_SYNC_ORI) { + if (cpu_has_feature(CPU_FTR_HVMODE)) { + instrs[i++] = 0x7db14ba6; /* mtspr 0x131, r13 (HSPRG1) */ + instrs[i++] = 0x7db04aa6; /* mfspr r13, 0x130 (HSPRG0) */ + } else { + instrs[i++] = 0x7db243a6; /* mtsprg 2,r13 */ + instrs[i++] = 0x7db142a6; /* mfsprg r13,1 */ + } + instrs[i++] = 0x7c0004ac; /* hwsync */ + instrs[i++] = 0xe9ad0000; /* ld r13,0(r13) */ + instrs[i++] = 0x63ff0000; /* ori 31,31,0 speculation barrier */ + if (cpu_has_feature(CPU_FTR_HVMODE)) { + instrs[i++] = 0x7db14aa6; /* mfspr r13, 0x131 (HSPRG1) */ + } else { + instrs[i++] = 0x7db242a6; /* mfsprg r13,2 */ + } + } else if (types & STF_BARRIER_EIEIO) { + instrs[i++] = 0x7e0006ac; /* eieio + bit 6 hint */ + } + + for (i = 0; start < end; start++, i++) { + dest = (void *)start + *start; + + pr_devel("patching dest %lx\n", (unsigned long)dest); + + patch_instruction(dest, instrs[0]); + patch_instruction(dest + 1, instrs[1]); + patch_instruction(dest + 2, instrs[2]); + patch_instruction(dest + 3, instrs[3]); + patch_instruction(dest + 4, instrs[4]); + patch_instruction(dest + 5, instrs[5]); + } + printk(KERN_DEBUG "stf-barrier: patched %d exit locations (%s barrier)\n", i, + (types == STF_BARRIER_NONE) ? "no" : + (types == STF_BARRIER_FALLBACK) ? "fallback" : + (types == STF_BARRIER_EIEIO) ? "eieio" : + (types == (STF_BARRIER_SYNC_ORI)) ? "hwsync" + : "unknown"); +} + + +void do_stf_barrier_fixups(enum stf_barrier_type types) +{ + do_stf_entry_barrier_fixups(types); + do_stf_exit_barrier_fixups(types); +} + void do_rfi_flush_fixups(enum l1d_flush_type types) { unsigned int instrs[3], *dest; @@ -153,7 +268,14 @@ void do_rfi_flush_fixups(enum l1d_flush_type types) patch_instruction(dest + 2, instrs[2]); } - printk(KERN_DEBUG "rfi-flush: patched %d locations\n", i); + printk(KERN_DEBUG "rfi-flush: patched %d locations (%s flush)\n", i, + (types == L1D_FLUSH_NONE) ? "no" : + (types == L1D_FLUSH_FALLBACK) ? "fallback displacement" : + (types & L1D_FLUSH_ORI) ? (types & L1D_FLUSH_MTTRIG) + ? "ori+mttrig type" + : "ori type" : + (types & L1D_FLUSH_MTTRIG) ? "mttrig type" + : "unknown"); } #endif /* CONFIG_PPC_BOOK3S_64 */ diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index f602307a438669236fcdb557b05078d431eecec9..9ed90c502005ac268d838f9100b4c843cffdc7ad 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -3424,7 +3424,6 @@ static void pnv_pci_ioda2_release_pe_dma(struct pnv_ioda_pe *pe) WARN_ON(pe->table_group.group); } - pnv_pci_ioda2_table_free_pages(tbl); iommu_free_table(tbl, "pnv"); } diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 6f8b4c19373af7e6d63fb1401ecca67d220bd1f7..17203abf38e85b8840a6fbd4d2e4b6500ae00f80 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -37,53 +37,92 @@ #include #include #include +#include #include "powernv.h" + +static bool fw_feature_is(const char *state, const char *name, + struct device_node *fw_features) +{ + struct device_node *np; + bool rc = false; + + np = of_get_child_by_name(fw_features, name); + if (np) { + rc = of_property_read_bool(np, state); + of_node_put(np); + } + + return rc; +} + +static void init_fw_feat_flags(struct device_node *np) +{ + if (fw_feature_is("enabled", "inst-spec-barrier-ori31,31,0", np)) + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); + + if (fw_feature_is("enabled", "fw-bcctrl-serialized", np)) + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); + + if (fw_feature_is("enabled", "inst-l1d-flush-ori30,30,0", np)) + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); + + if (fw_feature_is("enabled", "inst-l1d-flush-trig2", np)) + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); + + if (fw_feature_is("enabled", "fw-l1d-thread-split", np)) + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); + + if (fw_feature_is("enabled", "fw-count-cache-disabled", np)) + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); + + /* + * The features below are enabled by default, so we instead look to see + * if firmware has *disabled* them, and clear them if so. + */ + if (fw_feature_is("disabled", "speculation-policy-favor-security", np)) + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); + + if (fw_feature_is("disabled", "needs-l1d-flush-msr-pr-0-to-1", np)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); + + if (fw_feature_is("disabled", "needs-l1d-flush-msr-hv-1-to-0", np)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); + + if (fw_feature_is("disabled", "needs-spec-barrier-for-bound-checks", np)) + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); +} + static void pnv_setup_rfi_flush(void) { struct device_node *np, *fw_features; enum l1d_flush_type type; - int enable; + bool enable; /* Default to fallback in case fw-features are not available */ type = L1D_FLUSH_FALLBACK; - enable = 1; np = of_find_node_by_name(NULL, "ibm,opal"); fw_features = of_get_child_by_name(np, "fw-features"); of_node_put(np); if (fw_features) { - np = of_get_child_by_name(fw_features, "inst-l1d-flush-trig2"); - if (np && of_property_read_bool(np, "enabled")) - type = L1D_FLUSH_MTTRIG; + init_fw_feat_flags(fw_features); + of_node_put(fw_features); - of_node_put(np); + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) + type = L1D_FLUSH_MTTRIG; - np = of_get_child_by_name(fw_features, "inst-l1d-flush-ori30,30,0"); - if (np && of_property_read_bool(np, "enabled")) + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) type = L1D_FLUSH_ORI; - - of_node_put(np); - - /* Enable unless firmware says NOT to */ - enable = 2; - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-hv-1-to-0"); - if (np && of_property_read_bool(np, "disabled")) - enable--; - - of_node_put(np); - - np = of_get_child_by_name(fw_features, "needs-l1d-flush-msr-pr-0-to-1"); - if (np && of_property_read_bool(np, "disabled")) - enable--; - - of_node_put(np); - of_node_put(fw_features); } - setup_rfi_flush(type, enable > 0); + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ + (security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) || \ + security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV)); + + setup_rfi_flush(type, enable); } static void __init pnv_setup_arch(void) @@ -91,6 +130,7 @@ static void __init pnv_setup_arch(void) set_arch_panic_timeout(10, ARCH_PANIC_TIMEOUT); pnv_setup_rfi_flush(); + setup_stf_barrier(); /* Initialize SMP */ pnv_smp_init(); diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c index 6a5e7467445c8ad09b387e49f93aeed5d088d33e..3784a7abfcc8033a2193d07c5190d48a82fa61d4 100644 --- a/arch/powerpc/platforms/pseries/mobility.c +++ b/arch/powerpc/platforms/pseries/mobility.c @@ -314,6 +314,9 @@ void post_mobility_fixup(void) printk(KERN_ERR "Post-mobility device tree update " "failed: %d\n", rc); + /* Possibly switch to a new RFI flush type */ + pseries_setup_rfi_flush(); + return; } diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index b1be7b713fe6b0084ef3518d4438e781349f6c17..62ff57cf6c249183097c6f8807fe2212c736dbd1 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h @@ -79,4 +79,6 @@ extern struct pci_controller_ops pseries_pci_controller_ops; unsigned long pseries_memory_block_size(void); +void pseries_setup_rfi_flush(void); + #endif /* _PSERIES_PSERIES_H */ diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 1845fc61191208acc71be9fdc9ba800c94b67578..91ade77558239e119b9e3d545ebf702eefb66c98 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -66,6 +66,7 @@ #include #include #include +#include #include "pseries.h" @@ -450,35 +451,78 @@ static void __init find_and_init_phbs(void) of_pci_check_probe_only(); } -static void pseries_setup_rfi_flush(void) +static void init_cpu_char_feature_flags(struct h_cpu_char_result *result) +{ + /* + * The features below are disabled by default, so we instead look to see + * if firmware has *enabled* them, and set them if so. + */ + if (result->character & H_CPU_CHAR_SPEC_BAR_ORI31) + security_ftr_set(SEC_FTR_SPEC_BAR_ORI31); + + if (result->character & H_CPU_CHAR_BCCTRL_SERIALISED) + security_ftr_set(SEC_FTR_BCCTRL_SERIALISED); + + if (result->character & H_CPU_CHAR_L1D_FLUSH_ORI30) + security_ftr_set(SEC_FTR_L1D_FLUSH_ORI30); + + if (result->character & H_CPU_CHAR_L1D_FLUSH_TRIG2) + security_ftr_set(SEC_FTR_L1D_FLUSH_TRIG2); + + if (result->character & H_CPU_CHAR_L1D_THREAD_PRIV) + security_ftr_set(SEC_FTR_L1D_THREAD_PRIV); + + if (result->character & H_CPU_CHAR_COUNT_CACHE_DISABLED) + security_ftr_set(SEC_FTR_COUNT_CACHE_DISABLED); + + /* + * The features below are enabled by default, so we instead look to see + * if firmware has *disabled* them, and clear them if so. + */ + if (!(result->behaviour & H_CPU_BEHAV_FAVOUR_SECURITY)) + security_ftr_clear(SEC_FTR_FAVOUR_SECURITY); + + if (!(result->behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) + security_ftr_clear(SEC_FTR_L1D_FLUSH_PR); + + if (!(result->behaviour & H_CPU_BEHAV_BNDS_CHK_SPEC_BAR)) + security_ftr_clear(SEC_FTR_BNDS_CHK_SPEC_BAR); +} + +void pseries_setup_rfi_flush(void) { struct h_cpu_char_result result; enum l1d_flush_type types; bool enable; long rc; - /* Enable by default */ - enable = true; + /* + * Set features to the defaults assumed by init_cpu_char_feature_flags() + * so it can set/clear again any features that might have changed after + * migration, and in case the hypercall fails and it is not even called. + */ + powerpc_security_features = SEC_FTR_DEFAULT; rc = plpar_get_cpu_characteristics(&result); - if (rc == H_SUCCESS) { - types = L1D_FLUSH_NONE; + if (rc == H_SUCCESS) + init_cpu_char_feature_flags(&result); - if (result.character & H_CPU_CHAR_L1D_FLUSH_TRIG2) - types |= L1D_FLUSH_MTTRIG; - if (result.character & H_CPU_CHAR_L1D_FLUSH_ORI30) - types |= L1D_FLUSH_ORI; + /* + * We're the guest so this doesn't apply to us, clear it to simplify + * handling of it elsewhere. + */ + security_ftr_clear(SEC_FTR_L1D_FLUSH_HV); - /* Use fallback if nothing set in hcall */ - if (types == L1D_FLUSH_NONE) - types = L1D_FLUSH_FALLBACK; + types = L1D_FLUSH_FALLBACK; - if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) - enable = false; - } else { - /* Default to fallback if case hcall is not available */ - types = L1D_FLUSH_FALLBACK; - } + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2)) + types |= L1D_FLUSH_MTTRIG; + + if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_ORI30)) + types |= L1D_FLUSH_ORI; + + enable = security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) && \ + security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR); setup_rfi_flush(types, enable); } @@ -501,6 +545,7 @@ static void __init pSeries_setup_arch(void) fwnmi_init(); pseries_setup_rfi_flush(); + setup_stf_barrier(); /* By default, only probe PCI (can be overridden by rtas_pci) */ pci_add_flags(PCI_PROBE_ONLY); diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index a4fd00064c80e915844267df53820a455ef81c8f..771cfd2e1e6d8bdfa8e34c1bab6423d181a42181 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -1187,7 +1187,7 @@ cleanup_critical: jl 0f clg %r9,BASED(.Lcleanup_table+104) # .Lload_fpu_regs_end jl .Lcleanup_load_fpu_regs -0: BR_EX %r14 +0: BR_EX %r14,%r11 .align 8 .Lcleanup_table: @@ -1217,7 +1217,7 @@ cleanup_critical: ni __SIE_PROG0C+3(%r9),0xfe # no longer in SIE lctlg %c1,%c1,__LC_USER_ASCE # load primary asce larl %r9,sie_exit # skip forward to sie_exit - BR_EX %r14 + BR_EX %r14,%r11 #endif .Lcleanup_system_call: diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c index f87a55d7709469c63d8234fa9d3455513025dc55..9b3f2e212b3775523a82844a05c135f6089e95d5 100644 --- a/arch/sparc/kernel/ds.c +++ b/arch/sparc/kernel/ds.c @@ -908,7 +908,7 @@ static int register_services(struct ds_info *dp) pbuf.req.handle = cp->handle; pbuf.req.major = 1; pbuf.req.minor = 0; - strcpy(pbuf.req.svc_id, cp->service_id); + strcpy(pbuf.id_buf, cp->service_id); err = __ds_send(lp, &pbuf, msg_len); if (err > 0) diff --git a/arch/sparc/lib/multi3.S b/arch/sparc/lib/multi3.S index d6b6c97fe3c73061f911737a5da23ab41a3eab77..703127aaf4a5015ee4a1099e6129735f7162222b 100644 --- a/arch/sparc/lib/multi3.S +++ b/arch/sparc/lib/multi3.S @@ -5,26 +5,26 @@ .align 4 ENTRY(__multi3) /* %o0 = u, %o1 = v */ mov %o1, %g1 - srl %o3, 0, %g4 - mulx %g4, %g1, %o1 + srl %o3, 0, %o4 + mulx %o4, %g1, %o1 srlx %g1, 0x20, %g3 - mulx %g3, %g4, %g5 - sllx %g5, 0x20, %o5 - srl %g1, 0, %g4 + mulx %g3, %o4, %g7 + sllx %g7, 0x20, %o5 + srl %g1, 0, %o4 sub %o1, %o5, %o5 srlx %o5, 0x20, %o5 - addcc %g5, %o5, %g5 + addcc %g7, %o5, %g7 srlx %o3, 0x20, %o5 - mulx %g4, %o5, %g4 + mulx %o4, %o5, %o4 mulx %g3, %o5, %o5 sethi %hi(0x80000000), %g3 - addcc %g5, %g4, %g5 - srlx %g5, 0x20, %g5 + addcc %g7, %o4, %g7 + srlx %g7, 0x20, %g7 add %g3, %g3, %g3 movcc %xcc, %g0, %g3 - addcc %o5, %g5, %o5 - sllx %g4, 0x20, %g4 - add %o1, %g4, %o1 + addcc %o5, %g7, %o5 + sllx %o4, 0x20, %o4 + add %o1, %o4, %o1 add %o5, %g3, %g2 mulx %g1, %o2, %g1 add %g1, %g2, %g1 diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c index 60a391b8c4a282bda0d06b5ff8f227bcc9a6b902..dd1958436591c8fa5baaab7979fed97eb9faf977 100644 --- a/arch/x86/crypto/crc32c-intel_glue.c +++ b/arch/x86/crypto/crc32c-intel_glue.c @@ -58,16 +58,11 @@ asmlinkage unsigned int crc_pcl(const u8 *buffer, int len, unsigned int crc_init); static int crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_EAGERFPU; -#if defined(X86_FEATURE_EAGER_FPU) #define set_pcl_breakeven_point() \ do { \ if (!use_eager_fpu()) \ crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_NOEAGERFPU; \ } while (0) -#else -#define set_pcl_breakeven_point() \ - (crc32c_pcl_breakeven = CRC32C_PCL_BREAKEVEN_NOEAGERFPU) -#endif #endif /* CONFIG_X86_64 */ static u32 crc32c_intel_le_hw_byte(u32 crc, unsigned char const *data, size_t length) diff --git a/arch/x86/include/asm/barrier.h b/arch/x86/include/asm/barrier.h index 78d1c6a3d221f5cc3fa7c8fed690de345ecd6766..eb53c2c78a1f971d6037b98923c56118c1a1a428 100644 --- a/arch/x86/include/asm/barrier.h +++ b/arch/x86/include/asm/barrier.h @@ -37,7 +37,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, { unsigned long mask; - asm ("cmp %1,%2; sbb %0,%0;" + asm volatile ("cmp %1,%2; sbb %0,%0;" :"=r" (mask) :"g"(size),"r" (index) :"cc"); diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index c278f276c9b32b125ed2506aafa0a39ae2716c7f..aea30afeddb8879e081ef81b5b5c2564ba1122be 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -104,7 +104,7 @@ #define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ #define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ #define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ -#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ +/* free, was #define X86_FEATURE_EAGER_FPU ( 3*32+29) * "eagerfpu" Non lazy FPU restore */ #define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 2737366ea5830df0f3b54b69be488c41768dc799..8852e3afa1adc2134f0badd9e8c1375ec492ea66 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h @@ -62,7 +62,7 @@ extern u64 fpu__get_supported_xfeatures_mask(void); */ static __always_inline __pure bool use_eager_fpu(void) { - return static_cpu_has(X86_FEATURE_EAGER_FPU); + return true; } static __always_inline __pure bool use_xsaveopt(void) diff --git a/arch/x86/include/asm/kvm_emulate.h b/arch/x86/include/asm/kvm_emulate.h index fc3c7e49c8e48982552c551a74925dda6cd6eebd..ae357d0afc91f331f169894f42196e6aee4764a0 100644 --- a/arch/x86/include/asm/kvm_emulate.h +++ b/arch/x86/include/asm/kvm_emulate.h @@ -105,11 +105,12 @@ struct x86_emulate_ops { * @addr: [IN ] Linear address from which to read. * @val: [OUT] Value read from memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to read from memory. + * @system:[IN ] Whether the access is forced to be at CPL0. */ int (*read_std)(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, - struct x86_exception *fault); + struct x86_exception *fault, bool system); /* * read_phys: Read bytes of standard (non-emulated/special) memory. @@ -127,10 +128,11 @@ struct x86_emulate_ops { * @addr: [IN ] Linear address to which to write. * @val: [OUT] Value write to memory, zero-extended to 'u_long'. * @bytes: [IN ] Number of bytes to write to memory. + * @system:[IN ] Whether the access is forced to be at CPL0. */ int (*write_std)(struct x86_emulate_ctxt *ctxt, unsigned long addr, void *val, unsigned int bytes, - struct x86_exception *fault); + struct x86_exception *fault, bool system); /* * fetch: Read bytes of standard (non-emulated/special) memory. * Used for instruction fetch. diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index b0fd028b2eeedfebe4ebb52de5aeafd21b4b7c8a..7a4279d8a90275aa670f305f93d8b22a9d2f2dea 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -848,6 +848,13 @@ void get_cpu_cap(struct cpuinfo_x86 *c) init_scattered_cpuid_features(c); init_speculation_control(c); + + /* + * Clear/Set all flags overridden by options, after probe. + * This needs to happen each time we re-probe, which may happen + * several times during CPU initialization. + */ + apply_forced_caps(c); } static void identify_cpu_without_cpuid(struct cpuinfo_x86 *c) diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index f46071cb2c90f421e4433c6c59986c8ae52cc944..3e0199ee5a2f24a64bf7fcab96f6a57e0f2fab1c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -143,6 +143,11 @@ static struct severity { SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR), USER ), + MCESEV( + PANIC, "Data load in unrecoverable area of kernel", + SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA), + KERNEL + ), #endif MCESEV( PANIC, "Action required: unknown MCACOD", diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 7bbd50fa72ad55b0a5a6b56cdd1ddb87d86f8f22..c49e146d433294f2efa49d7022b2f3b67129954c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -738,23 +738,25 @@ EXPORT_SYMBOL_GPL(machine_check_poll); static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp, struct pt_regs *regs) { - int i, ret = 0; char *tmp; + int i; for (i = 0; i < mca_cfg.banks; i++) { m->status = mce_rdmsrl(msr_ops.status(i)); - if (m->status & MCI_STATUS_VAL) { - __set_bit(i, validp); - if (quirk_no_way_out) - quirk_no_way_out(i, m, regs); - } + if (!(m->status & MCI_STATUS_VAL)) + continue; + + __set_bit(i, validp); + if (quirk_no_way_out) + quirk_no_way_out(i, m, regs); if (mce_severity(m, mca_cfg.tolerant, &tmp, true) >= MCE_PANIC_SEVERITY) { + mce_read_aux(m, i); *msg = tmp; - ret = 1; + return 1; } } - return ret; + return 0; } /* @@ -1140,13 +1142,18 @@ void do_machine_check(struct pt_regs *regs, long error_code) lmce = m.mcgstatus & MCG_STATUS_LMCES; /* + * Local machine check may already know that we have to panic. + * Broadcast machine check begins rendezvous in mce_start() * Go through all banks in exclusion of the other CPUs. This way we * don't report duplicated events on shared banks because the first one - * to see it will clear it. If this is a Local MCE, then no need to - * perform rendezvous. + * to see it will clear it. */ - if (!lmce) + if (lmce) { + if (no_way_out) + mce_panic("Fatal local machine check", &m, msg); + } else { order = mce_start(&no_way_out); + } for (i = 0; i < cfg->banks; i++) { __clear_bit(i, toclear); @@ -1222,12 +1229,17 @@ void do_machine_check(struct pt_regs *regs, long error_code) no_way_out = worst >= MCE_PANIC_SEVERITY; } else { /* - * Local MCE skipped calling mce_reign() - * If we found a fatal error, we need to panic here. + * If there was a fatal machine check we should have + * already called mce_panic earlier in this function. + * Since we re-read the banks, we might have found + * something new. Check again to see if we found a + * fatal error. We call "mce_severity()" again to + * make sure we have the right "msg". */ - if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) - mce_panic("Machine check from unknown source", - NULL, NULL); + if (worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3) { + mce_severity(&m, cfg->tolerant, &msg, true); + mce_panic("Local fatal machine check!", &m, msg); + } } /* diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c index 6f0ab305dd5e117ce9f25651e630ea88dac2586f..9f3657891b875b52456eb66a316fca0a5ec4d6d1 100644 --- a/arch/x86/kernel/fpu/init.c +++ b/arch/x86/kernel/fpu/init.c @@ -15,10 +15,7 @@ */ static void fpu__init_cpu_ctx_switch(void) { - if (!boot_cpu_has(X86_FEATURE_EAGER_FPU)) - stts(); - else - clts(); + clts(); } /* @@ -233,42 +230,6 @@ static void __init fpu__init_system_xstate_size_legacy(void) fpu_user_xstate_size = fpu_kernel_xstate_size; } -/* - * FPU context switching strategies: - * - * Against popular belief, we don't do lazy FPU saves, due to the - * task migration complications it brings on SMP - we only do - * lazy FPU restores. - * - * 'lazy' is the traditional strategy, which is based on setting - * CR0::TS to 1 during context-switch (instead of doing a full - * restore of the FPU state), which causes the first FPU instruction - * after the context switch (whenever it is executed) to fault - at - * which point we lazily restore the FPU state into FPU registers. - * - * Tasks are of course under no obligation to execute FPU instructions, - * so it can easily happen that another context-switch occurs without - * a single FPU instruction being executed. If we eventually switch - * back to the original task (that still owns the FPU) then we have - * not only saved the restores along the way, but we also have the - * FPU ready to be used for the original task. - * - * 'lazy' is deprecated because it's almost never a performance win - * and it's much more complicated than 'eager'. - * - * 'eager' switching is by default on all CPUs, there we switch the FPU - * state during every context switch, regardless of whether the task - * has used FPU instructions in that time slice or not. This is done - * because modern FPU context saving instructions are able to optimize - * state saving and restoration in hardware: they can detect both - * unused and untouched FPU state and optimize accordingly. - * - * [ Note that even in 'lazy' mode we might optimize context switches - * to use 'eager' restores, if we detect that a task is using the FPU - * frequently. See the fpu->counter logic in fpu/internal.h for that. ] - */ -static enum { ENABLE, DISABLE } eagerfpu = ENABLE; - /* * Find supported xfeatures based on cpu features and command-line input. * This must be called after fpu__init_parse_early_param() is called and @@ -276,40 +237,10 @@ static enum { ENABLE, DISABLE } eagerfpu = ENABLE; */ u64 __init fpu__get_supported_xfeatures_mask(void) { - /* Support all xfeatures known to us */ - if (eagerfpu != DISABLE) - return XCNTXT_MASK; - - /* Warning of xfeatures being disabled for no eagerfpu mode */ - if (xfeatures_mask & XFEATURE_MASK_EAGER) { - pr_err("x86/fpu: eagerfpu switching disabled, disabling the following xstate features: 0x%llx.\n", - xfeatures_mask & XFEATURE_MASK_EAGER); - } - - /* Return a mask that masks out all features requiring eagerfpu mode */ - return ~XFEATURE_MASK_EAGER; -} - -/* - * Disable features dependent on eagerfpu. - */ -static void __init fpu__clear_eager_fpu_features(void) -{ - setup_clear_cpu_cap(X86_FEATURE_MPX); + return XCNTXT_MASK; } -/* - * Pick the FPU context switching strategy: - * - * When eagerfpu is AUTO or ENABLE, we ensure it is ENABLE if either of - * the following is true: - * - * (1) the cpu has xsaveopt, as it has the optimization and doing eager - * FPU switching has a relatively low cost compared to a plain xsave; - * (2) the cpu has xsave features (e.g. MPX) that depend on eager FPU - * switching. Should the kernel boot with noxsaveopt, we support MPX - * with eager FPU switching at a higher cost. - */ +/* Legacy code to initialize eager fpu mode. */ static void __init fpu__init_system_ctx_switch(void) { static bool on_boot_cpu __initdata = 1; @@ -318,17 +249,6 @@ static void __init fpu__init_system_ctx_switch(void) on_boot_cpu = 0; WARN_ON_FPU(current->thread.fpu.fpstate_active); - - if (boot_cpu_has(X86_FEATURE_XSAVEOPT) && eagerfpu != DISABLE) - eagerfpu = ENABLE; - - if (xfeatures_mask & XFEATURE_MASK_EAGER) - eagerfpu = ENABLE; - - if (eagerfpu == ENABLE) - setup_force_cpu_cap(X86_FEATURE_EAGER_FPU); - - printk(KERN_INFO "x86/fpu: Using '%s' FPU context switches.\n", eagerfpu == ENABLE ? "eager" : "lazy"); } /* @@ -337,11 +257,6 @@ static void __init fpu__init_system_ctx_switch(void) */ static void __init fpu__init_parse_early_param(void) { - if (cmdline_find_option_bool(boot_command_line, "eagerfpu=off")) { - eagerfpu = DISABLE; - fpu__clear_eager_fpu_features(); - } - if (cmdline_find_option_bool(boot_command_line, "no387")) setup_clear_cpu_cap(X86_FEATURE_FPU); diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 91c48cdfe81f36679d38f63c1e50395d4cd71d0e..516be613bd41a3b5adc87365a94e43b30efd2300 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -414,25 +414,38 @@ void free_insn_page(void *page) module_memfree(page); } +/* Prepare reljump right after instruction to boost */ +static void prepare_boost(struct kprobe *p, int length) +{ + if (can_boost(p->ainsn.insn, p->addr) && + MAX_INSN_SIZE - length >= RELATIVEJUMP_SIZE) { + /* + * These instructions can be executed directly if it + * jumps back to correct address. + */ + synthesize_reljump(p->ainsn.insn + length, p->addr + length); + p->ainsn.boostable = 1; + } else { + p->ainsn.boostable = -1; + } +} + static int arch_copy_kprobe(struct kprobe *p) { - int ret; + int len; set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1); /* Copy an instruction with recovering if other optprobe modifies it.*/ - ret = __copy_instruction(p->ainsn.insn, p->addr); - if (!ret) + len = __copy_instruction(p->ainsn.insn, p->addr); + if (!len) return -EINVAL; /* * __copy_instruction can modify the displacement of the instruction, * but it doesn't affect boostable check. */ - if (can_boost(p->ainsn.insn, p->addr)) - p->ainsn.boostable = 0; - else - p->ainsn.boostable = -1; + prepare_boost(p, len); set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1); @@ -897,21 +910,6 @@ static void resume_execution(struct kprobe *p, struct pt_regs *regs, break; } - if (p->ainsn.boostable == 0) { - if ((regs->ip > copy_ip) && - (regs->ip - copy_ip) + 5 < MAX_INSN_SIZE) { - /* - * These instructions can be executed directly if it - * jumps back to correct address. - */ - synthesize_reljump((void *)regs->ip, - (void *)orig_ip + (regs->ip - copy_ip)); - p->ainsn.boostable = 1; - } else { - p->ainsn.boostable = -1; - } - } - regs->ip += orig_ip - copy_ip; no_change: diff --git a/arch/x86/kernel/quirks.c b/arch/x86/kernel/quirks.c index 0bee04d41bed04406de00732cb1d73e5f6f32c33..b57100a2c83441504d2f6cf1a49a9a62c4f7342c 100644 --- a/arch/x86/kernel/quirks.c +++ b/arch/x86/kernel/quirks.c @@ -643,12 +643,19 @@ static void quirk_intel_brickland_xeon_ras_cap(struct pci_dev *pdev) /* Skylake */ static void quirk_intel_purley_xeon_ras_cap(struct pci_dev *pdev) { - u32 capid0; + u32 capid0, capid5; pci_read_config_dword(pdev, 0x84, &capid0); + pci_read_config_dword(pdev, 0x98, &capid5); - if ((capid0 & 0xc0) == 0xc0) + /* + * CAPID0{7:6} indicate whether this is an advanced RAS SKU + * CAPID5{8:5} indicate that various NVDIMM usage modes are + * enabled, so memory machine check recovery is also enabled. + */ + if ((capid0 & 0xc0) == 0xc0 || (capid5 & 0x1e0)) static_branch_inc(&mcsafe_key); + } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x0ec3, quirk_intel_brickland_xeon_ras_cap); DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2fc0, quirk_intel_brickland_xeon_ras_cap); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index f2142932ff0bbeebf16395453a13f3ac10b66357..5bbfa2f63b8cd279e4a4ca5fbd963f6ade1bbef2 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -799,16 +799,18 @@ static void math_error(struct pt_regs *regs, int error_code, int trapnr) char *str = (trapnr == X86_TRAP_MF) ? "fpu exception" : "simd exception"; - if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, SIGFPE) == NOTIFY_STOP) - return; cond_local_irq_enable(regs); if (!user_mode(regs)) { - if (!fixup_exception(regs, trapnr)) { - task->thread.error_code = error_code; - task->thread.trap_nr = trapnr; + if (fixup_exception(regs, trapnr)) + return; + + task->thread.error_code = error_code; + task->thread.trap_nr = trapnr; + + if (notify_die(DIE_TRAP, str, regs, error_code, + trapnr, SIGFPE) != NOTIFY_STOP) die(str, regs, error_code); - } return; } diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 4ef267fb635adb47c2478385b0ade4af39bde7a9..e783a5daaab2f681cf38856579b82f7cc291b211 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -352,8 +352,6 @@ SECTIONS DISCARDS /DISCARD/ : { *(.eh_frame) - *(__func_stack_frame_non_standard) - *(__unreachable) } } diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h index c38369781239ad6f6fc54d5559c7b5b6f8eea2e7..8a841b9d8f84039c7374bc6e6e3c3cd1c5ca8eb4 100644 --- a/arch/x86/kvm/cpuid.h +++ b/arch/x86/kvm/cpuid.h @@ -179,7 +179,7 @@ static inline bool guest_cpuid_has_spec_ctrl(struct kvm_vcpu *vcpu) if (best && (best->ebx & bit(X86_FEATURE_AMD_IBRS))) return true; best = kvm_find_cpuid_entry(vcpu, 7, 0); - return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SSBD))); + return best && (best->edx & (bit(X86_FEATURE_SPEC_CTRL) | bit(X86_FEATURE_SPEC_CTRL_SSBD))); } static inline bool guest_cpuid_has_arch_capabilities(struct kvm_vcpu *vcpu) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index c8d573822e60e81b7e32c78b8e7dd5a175a305ee..510cfc06701ad4a7a17247c4e95b673316381317 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -802,6 +802,19 @@ static inline int jmp_rel(struct x86_emulate_ctxt *ctxt, int rel) return assign_eip_near(ctxt, ctxt->_eip + rel); } +static int linear_read_system(struct x86_emulate_ctxt *ctxt, ulong linear, + void *data, unsigned size) +{ + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, true); +} + +static int linear_write_system(struct x86_emulate_ctxt *ctxt, + ulong linear, void *data, + unsigned int size) +{ + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, true); +} + static int segmented_read_std(struct x86_emulate_ctxt *ctxt, struct segmented_address addr, void *data, @@ -813,7 +826,7 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, false, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->read_std(ctxt, linear, data, size, &ctxt->exception, false); } static int segmented_write_std(struct x86_emulate_ctxt *ctxt, @@ -827,7 +840,7 @@ static int segmented_write_std(struct x86_emulate_ctxt *ctxt, rc = linearize(ctxt, addr, size, true, &linear); if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception); + return ctxt->ops->write_std(ctxt, linear, data, size, &ctxt->exception, false); } /* @@ -1500,8 +1513,7 @@ static int read_interrupt_descriptor(struct x86_emulate_ctxt *ctxt, return emulate_gp(ctxt, index << 3 | 0x2); addr = dt.address + index * 8; - return ctxt->ops->read_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + return linear_read_system(ctxt, addr, desc, sizeof *desc); } static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt, @@ -1564,8 +1576,7 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->read_std(ctxt, *desc_addr_p, desc, sizeof(*desc), - &ctxt->exception); + return linear_read_system(ctxt, *desc_addr_p, desc, sizeof(*desc)); } /* allowed just for 8 bytes segments */ @@ -1579,8 +1590,7 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, if (rc != X86EMUL_CONTINUE) return rc; - return ctxt->ops->write_std(ctxt, addr, desc, sizeof *desc, - &ctxt->exception); + return linear_write_system(ctxt, addr, desc, sizeof *desc); } static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, @@ -1741,8 +1751,7 @@ static int __load_segment_descriptor(struct x86_emulate_ctxt *ctxt, return ret; } } else if (ctxt->mode == X86EMUL_MODE_PROT64) { - ret = ctxt->ops->read_std(ctxt, desc_addr+8, &base3, - sizeof(base3), &ctxt->exception); + ret = linear_read_system(ctxt, desc_addr+8, &base3, sizeof(base3)); if (ret != X86EMUL_CONTINUE) return ret; if (is_noncanonical_address(get_desc_base(&seg_desc) | @@ -2055,11 +2064,11 @@ static int __emulate_int_real(struct x86_emulate_ctxt *ctxt, int irq) eip_addr = dt.address + (irq << 2); cs_addr = dt.address + (irq << 2) + 2; - rc = ops->read_std(ctxt, cs_addr, &cs, 2, &ctxt->exception); + rc = linear_read_system(ctxt, cs_addr, &cs, 2); if (rc != X86EMUL_CONTINUE) return rc; - rc = ops->read_std(ctxt, eip_addr, &eip, 2, &ctxt->exception); + rc = linear_read_system(ctxt, eip_addr, &eip, 2); if (rc != X86EMUL_CONTINUE) return rc; @@ -2903,12 +2912,12 @@ static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt, #ifdef CONFIG_X86_64 base |= ((u64)base3) << 32; #endif - r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL); + r = ops->read_std(ctxt, base + 102, &io_bitmap_ptr, 2, NULL, true); if (r != X86EMUL_CONTINUE) return false; if (io_bitmap_ptr + port/8 > desc_limit_scaled(&tr_seg)) return false; - r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL); + r = ops->read_std(ctxt, base + io_bitmap_ptr + port/8, &perm, 2, NULL, true); if (r != X86EMUL_CONTINUE) return false; if ((perm >> bit_idx) & mask) @@ -3037,35 +3046,30 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_16 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); - ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; save_state_to_tss16(ctxt, &tss_seg); - ret = ops->write_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_write_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; - ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; if (old_tss_sel != 0xffff) { tss_seg.prev_task_link = old_tss_sel; - ret = ops->write_std(ctxt, new_tss_base, - &tss_seg.prev_task_link, - sizeof tss_seg.prev_task_link, - &ctxt->exception); + ret = linear_write_system(ctxt, new_tss_base, + &tss_seg.prev_task_link, + sizeof tss_seg.prev_task_link); if (ret != X86EMUL_CONTINUE) return ret; } @@ -3181,38 +3185,34 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, u16 tss_selector, u16 old_tss_sel, ulong old_tss_base, struct desc_struct *new_desc) { - const struct x86_emulate_ops *ops = ctxt->ops; struct tss_segment_32 tss_seg; int ret; u32 new_tss_base = get_desc_base(new_desc); u32 eip_offset = offsetof(struct tss_segment_32, eip); u32 ldt_sel_offset = offsetof(struct tss_segment_32, ldt_selector); - ret = ops->read_std(ctxt, old_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, old_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; save_state_to_tss32(ctxt, &tss_seg); /* Only GP registers and segment selectors are saved */ - ret = ops->write_std(ctxt, old_tss_base + eip_offset, &tss_seg.eip, - ldt_sel_offset - eip_offset, &ctxt->exception); + ret = linear_write_system(ctxt, old_tss_base + eip_offset, &tss_seg.eip, + ldt_sel_offset - eip_offset); if (ret != X86EMUL_CONTINUE) return ret; - ret = ops->read_std(ctxt, new_tss_base, &tss_seg, sizeof tss_seg, - &ctxt->exception); + ret = linear_read_system(ctxt, new_tss_base, &tss_seg, sizeof tss_seg); if (ret != X86EMUL_CONTINUE) return ret; if (old_tss_sel != 0xffff) { tss_seg.prev_task_link = old_tss_sel; - ret = ops->write_std(ctxt, new_tss_base, - &tss_seg.prev_task_link, - sizeof tss_seg.prev_task_link, - &ctxt->exception); + ret = linear_write_system(ctxt, new_tss_base, + &tss_seg.prev_task_link, + sizeof tss_seg.prev_task_link); if (ret != X86EMUL_CONTINUE) return ret; } diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index ebceda2119011d3c825a1ae3ffb3fc7a633f933f..7cb107707fedab2e1f050d47dfcb81541b311ed3 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -6928,8 +6928,7 @@ static int nested_vmx_check_vmptr(struct kvm_vcpu *vcpu, int exit_reason, vmcs_read32(VMX_INSTRUCTION_INFO), false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vmptr, - sizeof(vmptr), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &vmptr, sizeof(vmptr), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7469,8 +7468,8 @@ static int handle_vmread(struct kvm_vcpu *vcpu) vmx_instruction_info, true, &gva)) return 1; /* _system ok, as nested_vmx_check_permission verified cpl=0 */ - kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_long_mode(vcpu) ? 8 : 4), NULL); + kvm_write_guest_virt_system(vcpu, gva, &field_value, + (is_long_mode(vcpu) ? 8 : 4), NULL); } nested_vmx_succeed(vcpu); @@ -7505,8 +7504,8 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, exit_qualification, vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, - &field_value, (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &field_value, + (is_64_bit_mode(vcpu) ? 8 : 4), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7603,9 +7602,9 @@ static int handle_vmptrst(struct kvm_vcpu *vcpu) vmx_instruction_info, true, &vmcs_gva)) return 1; /* ok to use *_system, as nested_vmx_check_permission verified cpl=0 */ - if (kvm_write_guest_virt_system(&vcpu->arch.emulate_ctxt, vmcs_gva, - (void *)&to_vmx(vcpu)->nested.current_vmptr, - sizeof(u64), &e)) { + if (kvm_write_guest_virt_system(vcpu, vmcs_gva, + (void *)&to_vmx(vcpu)->nested.current_vmptr, + sizeof(u64), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7659,8 +7658,7 @@ static int handle_invept(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &operand, - sizeof(operand), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &operand, sizeof(operand), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } @@ -7723,8 +7721,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu) if (get_vmx_mem_address(vcpu, vmcs_readl(EXIT_QUALIFICATION), vmx_instruction_info, false, &gva)) return 1; - if (kvm_read_guest_virt(&vcpu->arch.emulate_ctxt, gva, &vpid, - sizeof(u32), &e)) { + if (kvm_read_guest_virt(vcpu, gva, &vpid, sizeof(u32), &e)) { kvm_inject_page_fault(vcpu, &e); return 1; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4aa265ae8cf799b1cdd3bad83cc29bb8ba4c96de..5ca23af44c81bba10be3b1257e2c0e769876a786 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -4395,11 +4395,10 @@ static int kvm_fetch_guest_virt(struct x86_emulate_ctxt *ctxt, return X86EMUL_CONTINUE; } -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception) { - struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); u32 access = (kvm_x86_ops->get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, @@ -4407,12 +4406,17 @@ int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, } EXPORT_SYMBOL_GPL(kvm_read_guest_virt); -static int kvm_read_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, unsigned int bytes, - struct x86_exception *exception) +static int emulator_read_std(struct x86_emulate_ctxt *ctxt, + gva_t addr, void *val, unsigned int bytes, + struct x86_exception *exception, bool system) { struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); - return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, exception); + u32 access = 0; + + if (!system && kvm_x86_ops->get_cpl(vcpu) == 3) + access |= PFERR_USER_MASK; + + return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, access, exception); } static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, @@ -4424,18 +4428,16 @@ static int kvm_read_guest_phys_system(struct x86_emulate_ctxt *ctxt, return r < 0 ? X86EMUL_IO_NEEDED : X86EMUL_CONTINUE; } -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, - gva_t addr, void *val, - unsigned int bytes, - struct x86_exception *exception) +static int kvm_write_guest_virt_helper(gva_t addr, void *val, unsigned int bytes, + struct kvm_vcpu *vcpu, u32 access, + struct x86_exception *exception) { - struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); void *data = val; int r = X86EMUL_CONTINUE; while (bytes) { gpa_t gpa = vcpu->arch.walk_mmu->gva_to_gpa(vcpu, addr, - PFERR_WRITE_MASK, + access, exception); unsigned offset = addr & (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); @@ -4456,6 +4458,27 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, out: return r; } + +static int emulator_write_std(struct x86_emulate_ctxt *ctxt, gva_t addr, void *val, + unsigned int bytes, struct x86_exception *exception, + bool system) +{ + struct kvm_vcpu *vcpu = emul_to_vcpu(ctxt); + u32 access = PFERR_WRITE_MASK; + + if (!system && kvm_x86_ops->get_cpl(vcpu) == 3) + access |= PFERR_USER_MASK; + + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, + access, exception); +} + +int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, + unsigned int bytes, struct x86_exception *exception) +{ + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, + PFERR_WRITE_MASK, exception); +} EXPORT_SYMBOL_GPL(kvm_write_guest_virt_system); static int vcpu_mmio_gva_to_gpa(struct kvm_vcpu *vcpu, unsigned long gva, @@ -5180,8 +5203,8 @@ static void emulator_set_hflags(struct x86_emulate_ctxt *ctxt, unsigned emul_fla static const struct x86_emulate_ops emulate_ops = { .read_gpr = emulator_read_gpr, .write_gpr = emulator_write_gpr, - .read_std = kvm_read_guest_virt_system, - .write_std = kvm_write_guest_virt_system, + .read_std = emulator_read_std, + .write_std = emulator_write_std, .read_phys = kvm_read_guest_phys_system, .fetch = kvm_fetch_guest_virt, .read_emulated = emulator_read_emulated, diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index e8ff3e4ce38a53e167bc475f0d2b91b5fd9065b3..2133a18f2d36459d430f4d92ceb3759864f3b3e3 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -161,11 +161,11 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip); void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr); u64 get_kvmclock_ns(struct kvm *kvm); -int kvm_read_guest_virt(struct x86_emulate_ctxt *ctxt, +int kvm_read_guest_virt(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception); -int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt, +int kvm_write_guest_virt_system(struct kvm_vcpu *vcpu, gva_t addr, void *val, unsigned int bytes, struct x86_exception *exception); diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c index f92bdb9f4e4688c500b3bbfa85069e41cb56b76c..ae9b84cae57c86b6a68a603aaa796a0cf1f7d2cf 100644 --- a/arch/x86/mm/init.c +++ b/arch/x86/mm/init.c @@ -653,7 +653,9 @@ void __init init_mem_mapping(void) */ int devmem_is_allowed(unsigned long pagenr) { - if (page_is_ram(pagenr)) { + if (region_intersects(PFN_PHYS(pagenr), PAGE_SIZE, + IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE) + != REGION_DISJOINT) { /* * For disallowed memory regions in the low 1MB range, * request that the page be shown as all zeros. diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index e3a3f5a648846cd1d7faaf31aec2e0f7e4804466..2986a13b9786db2d553a9d3dd66dcc984d05921c 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -472,6 +472,12 @@ static void __init xen_init_cpuid_mask(void) cpuid_leaf1_ecx_set_mask = (1 << (X86_FEATURE_MWAIT % 32)); } +static void __init xen_init_capabilities(void) +{ + if (xen_pv_domain()) + setup_force_cpu_cap(X86_FEATURE_XENPV); +} + static void xen_set_debugreg(int reg, unsigned long val) { HYPERVISOR_set_debugreg(reg, val); @@ -1634,6 +1640,7 @@ asmlinkage __visible void __init xen_start_kernel(void) xen_init_irq_ops(); xen_init_cpuid_mask(); + xen_init_capabilities(); #ifdef CONFIG_X86_LOCAL_APIC /* @@ -1978,12 +1985,6 @@ bool xen_hvm_need_lapic(void) } EXPORT_SYMBOL_GPL(xen_hvm_need_lapic); -static void xen_set_cpu_features(struct cpuinfo_x86 *c) -{ - if (xen_pv_domain()) - set_cpu_cap(c, X86_FEATURE_XENPV); -} - static void xen_pin_vcpu(int cpu) { static bool disable_pinning; @@ -2030,7 +2031,6 @@ const struct hypervisor_x86 x86_hyper_xen = { .init_platform = xen_hvm_guest_init, #endif .x2apic_available = xen_x2apic_para_available, - .set_cpu_features = xen_set_cpu_features, .pin_vcpu = xen_pin_vcpu, }; EXPORT_SYMBOL(x86_hyper_xen); diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index a11540e51f62d3a32e20374258ae7714a5c7d229..8eca26ef6471541299aeee4d0b954ab81e630b48 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -87,6 +88,8 @@ static void cpu_bringup(void) cpu_data(cpu).x86_max_cores = 1; set_cpu_sibling_map(cpu); + speculative_store_bypass_ht_init(); + xen_setup_cpu_clockevents(); notify_cpu_starting(cpu); @@ -375,6 +378,8 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus) } set_cpu_sibling_map(0); + speculative_store_bypass_ht_init(); + xen_pmu_init(0); if (xen_smp_intr_init(0)) diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index ce37d5b899fead50d312f06ed3c3f3982309d294..44bd9a377ad1e62912c5540ff209cb9df6d59926 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -334,7 +334,7 @@ do_unaligned_user (struct pt_regs *regs) info.si_errno = 0; info.si_code = BUS_ADRALN; info.si_addr = (void *) regs->excvaddr; - force_sig_info(SIGSEGV, &info, current); + force_sig_info(SIGBUS, &info, current); } #endif diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index ce2df8c9c583970be0177d2a50de85316fb1c2b2..7e6a43ffdcbedac9bea63c1c8662924e3b5f5881 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -249,6 +249,15 @@ int x509_note_signature(void *context, size_t hdrlen, return -EINVAL; } + if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0) { + /* Discard the BIT STRING metadata */ + if (vlen < 1 || *(const u8 *)value != 0) + return -EBADMSG; + + value++; + vlen--; + } + ctx->cert->raw_sig = value; ctx->cert->raw_sig_size = vlen; return 0; diff --git a/drivers/android/Kconfig b/drivers/android/Kconfig index 01de42c8b74bd7032197512ea79c658606f660e4..bb2a5b58162218e7a0b91d7fa3d7f32a800cc6ab 100644 --- a/drivers/android/Kconfig +++ b/drivers/android/Kconfig @@ -32,9 +32,9 @@ config ANDROID_BINDER_DEVICES therefore logically separated from the other devices. config ANDROID_BINDER_IPC_32BIT - bool + bool "Android Binder IPC 32BIT Driver" depends on !64BIT && ANDROID_BINDER_IPC - default y + default n ---help--- The Binder API has been changed to support both 32 and 64bit applications in a mixed environment. diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 0e2c0ac5792db715b10ebc69a16a17445e8edcbb..82c59a143a14a370fc58baf4bd809dc4575f9cee 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4426,9 +4426,6 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, - /* Sandisk devices which are known to not handle LPM well */ - { "SanDisk SD7UB3Q*G1001", NULL, ATA_HORKAGE_NOLPM, }, - /* devices that don't properly handle queued TRIM commands */ { "Micron_M500IT_*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, diff --git a/drivers/ata/libata-zpodd.c b/drivers/ata/libata-zpodd.c index f3a65a3140d3c7e51bef6dce19f676de768abfdf..0ad96c647541a94bb6e1c68d79d7a661a9bdd703 100644 --- a/drivers/ata/libata-zpodd.c +++ b/drivers/ata/libata-zpodd.c @@ -34,7 +34,7 @@ struct zpodd { static int eject_tray(struct ata_device *dev) { struct ata_taskfile tf; - const char cdb[] = { GPCMD_START_STOP_UNIT, + static const char cdb[ATAPI_CDB_LEN] = { GPCMD_START_STOP_UNIT, 0, 0, 0, 0x02, /* LoEj */ 0, 0, 0, 0, 0, 0, 0, @@ -55,7 +55,7 @@ static enum odd_mech_type zpodd_get_mech_type(struct ata_device *dev) unsigned int ret; struct rm_feature_desc *desc = (void *)(buf + 8); struct ata_taskfile tf; - char cdb[] = { GPCMD_GET_CONFIGURATION, + static const char cdb[] = { GPCMD_GET_CONFIGURATION, 2, /* only 1 feature descriptor requested */ 0, 3, /* 3, removable medium feature */ 0, 0, 0,/* reserved */ diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 81bfeec67b773a92e0ad463f0191cb961dcbfea2..d0fac641e717afcc2c3e5dd002015caa5737bf9a 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -1151,8 +1151,8 @@ static void eprom_get_byte(struct zatm_dev *zatm_dev, unsigned char *byte, } -static unsigned char eprom_try_esi(struct atm_dev *dev, unsigned short cmd, - int offset, int swap) +static int eprom_try_esi(struct atm_dev *dev, unsigned short cmd, int offset, + int swap) { unsigned char buf[ZEPROM_SIZE]; struct zatm_dev *zatm_dev; diff --git a/drivers/base/core.c b/drivers/base/core.c index 42728680a678cea1cf8ecb0d9edc97ad881c990f..4bb8016096215e54434124d8dcb5dbcd637c8511 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -764,7 +764,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) dir = kzalloc(sizeof(*dir), GFP_KERNEL); if (!dir) - return NULL; + return ERR_PTR(-ENOMEM); dir->class = class; kobject_init(&dir->kobj, &class_dir_ktype); @@ -774,7 +774,7 @@ class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); if (retval < 0) { kobject_put(&dir->kobj); - return NULL; + return ERR_PTR(retval); } return &dir->kobj; } @@ -1081,6 +1081,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); kobj = get_device_parent(dev, parent); + if (IS_ERR(kobj)) { + error = PTR_ERR(kobj); + goto parent_error; + } if (kobj) dev->kobj.parent = kobj; @@ -1179,6 +1183,7 @@ int device_add(struct device *dev) kobject_del(&dev->kobj); Error: cleanup_glue_dir(dev, glue_dir); +parent_error: put_device(parent); name_error: kfree(dev->p); @@ -1996,6 +2001,11 @@ int device_move(struct device *dev, struct device *new_parent, device_pm_lock(); new_parent = get_device(new_parent); new_parent_kobj = get_device_parent(dev, new_parent); + if (IS_ERR(new_parent_kobj)) { + error = PTR_ERR(new_parent_kobj); + put_device(new_parent); + goto out; + } pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), __func__, new_parent ? dev_name(new_parent) : ""); diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 94001aafc6d0cb8142b14377a780b22eb6e01b8e..e494a938a9f1fcbeabb9c5469f87e82b4aa430ec 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -651,7 +651,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) rcu_read_unlock(); /* Scaling up? Scale voltage before frequency */ - if (freq > old_freq) { + if (freq >= old_freq) { ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min, u_volt_max); if (ret) diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index c6755c9a0aeab4bf55dc6265cd41aad1c02c8ea1..51c233c4e0587b933a87446dfe99a2e8beb3ec47 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -269,8 +269,8 @@ void drbd_request_endio(struct bio *bio) what = COMPLETED_OK; } - bio_put(req->private_bio); req->private_bio = ERR_PTR(bio->bi_error); + bio_put(bio); /* not req_mod(), we need irqsave here! */ spin_lock_irqsave(&device->resource->req_lock, flags); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 194db0e278aa20cdb66e6df5bffcae69049e6177..8beee2a7aa3b7143e6fb71c489ae1ecdf7ddd5aa 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3900,7 +3900,6 @@ static void cancel_tasks_sync(struct rbd_device *rbd_dev) { dout("%s rbd_dev %p\n", __func__, rbd_dev); - cancel_delayed_work_sync(&rbd_dev->watch_dwork); cancel_work_sync(&rbd_dev->acquired_lock_work); cancel_work_sync(&rbd_dev->released_lock_work); cancel_delayed_work_sync(&rbd_dev->lock_dwork); @@ -3918,6 +3917,7 @@ static void rbd_unregister_watch(struct rbd_device *rbd_dev) rbd_dev->watch_state = RBD_WATCH_STATE_UNREGISTERED; mutex_unlock(&rbd_dev->watch_mutex); + cancel_delayed_work_sync(&rbd_dev->watch_dwork); ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc); } diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 74b2f4a146430486d2597bb217524901388e2d9d..3a8b9aef96a6974613952727f9271321de38eb67 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -939,6 +939,12 @@ static int qca_setup(struct hci_uart *hu) } else if (ret == -ENOENT) { /* No patch/nvm-config found, run with original fw/config */ ret = 0; + } else if (ret == -EAGAIN) { + /* + * Userspace firmware loader will return -EAGAIN in case no + * patch/nvm-config is found, so run with original fw/config. + */ + ret = 0; } /* Setup bdaddr */ diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index d84dea6c2df25165d0c3e284fb50e21d8fb97e0a..b7e61c8a232453aaebae412ee74a187dc28334ad 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -79,6 +79,16 @@ #define FASTRPC_CTX_MAGIC (0xbeeddeed) #define FASTRPC_CTX_MAX (256) #define FASTRPC_CTXID_MASK (0xFF0) +#define NUM_DEVICES 2 /* adsprpc-smd, adsprpc-smd-secure */ +#define MINOR_NUM_DEV 0 +#define MINOR_NUM_SECURE_DEV 1 +#define NON_SECURE_CHANNEL 0 +#define SECURE_CHANNEL 1 + +#define ADSP_DOMAIN_ID (0) +#define MDSP_DOMAIN_ID (1) +#define SDSP_DOMAIN_ID (2) +#define CDSP_DOMAIN_ID (3) #define IS_CACHE_ALIGNED(x) (((x) & ((L1_CACHE_BYTES)-1)) == 0) @@ -282,6 +292,8 @@ struct fastrpc_channel_ctx { int ramdumpenabled; void *remoteheap_ramdump_dev; struct fastrpc_glink_info link; + /* Indicates, if channel is restricted to secure node only */ + int secure; }; struct fastrpc_apps { @@ -380,6 +392,8 @@ struct fastrpc_file { struct mutex map_mutex; struct mutex fl_map_mutex; int refcount; + /* Identifies the device (MINOR_NUM_DEV / MINOR_NUM_SECURE_DEV) */ + int dev_minor; }; static struct fastrpc_apps gfa; @@ -1854,7 +1868,11 @@ static void fastrpc_init(struct fastrpc_apps *me) init_completion(&me->channel[i].work); init_completion(&me->channel[i].workport); me->channel[i].sesscount = 0; + /* All channels are secure by default except CDSP */ + me->channel[i].secure = SECURE_CHANNEL; } + /* Set CDSP channel to non secure */ + me->channel[CDSP_DOMAIN_ID].secure = NON_SECURE_CHANNEL; } static int fastrpc_release_current_dsp_process(struct fastrpc_file *fl); @@ -2487,6 +2505,31 @@ static int fastrpc_mmap_remove(struct fastrpc_file *fl, uintptr_t va, static void fastrpc_mmap_add(struct fastrpc_mmap *map); +static inline void get_fastrpc_ioctl_mmap_64( + struct fastrpc_ioctl_mmap_64 *mmap64, + struct fastrpc_ioctl_mmap *immap) +{ + immap->fd = mmap64->fd; + immap->flags = mmap64->flags; + immap->vaddrin = (uintptr_t)mmap64->vaddrin; + immap->size = mmap64->size; +} + +static inline void put_fastrpc_ioctl_mmap_64( + struct fastrpc_ioctl_mmap_64 *mmap64, + struct fastrpc_ioctl_mmap *immap) +{ + mmap64->vaddrout = (uint64_t)immap->vaddrout; +} + +static inline void get_fastrpc_ioctl_munmap_64( + struct fastrpc_ioctl_munmap_64 *munmap64, + struct fastrpc_ioctl_munmap *imunmap) +{ + imunmap->vaddrout = (uintptr_t)munmap64->vaddrout; + imunmap->size = munmap64->size; +} + static int fastrpc_internal_munmap(struct fastrpc_file *fl, struct fastrpc_ioctl_munmap *ud) { @@ -2943,6 +2986,9 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s\n\n", chan->name); + len += scnprintf(fileinfo + len, + DEBUGFS_SIZE - len, "%s %d\n", + "secure:", chan->secure); len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s %d\n", "sesscount:", chan->sesscount); @@ -2971,6 +3017,9 @@ static ssize_t fastrpc_debugfs_read(struct file *filp, char __user *buffer, len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s %d\n\n", "SSRCOUNT:", fl->ssrcount); + len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, + "%s %d\n\n", + "DEV_MINOR:", fl->dev_minor); len += scnprintf(fileinfo + len, DEBUGFS_SIZE - len, "%s\n", "LIST OF BUFS:"); @@ -3107,6 +3156,19 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) struct fastrpc_file *fl = NULL; struct fastrpc_apps *me = &gfa; + /* + * Indicates the device node opened + * MINOR_NUM_DEV or MINOR_NUM_SECURE_DEV + */ + int dev_minor = MINOR(inode->i_rdev); + + VERIFY(err, ((dev_minor == MINOR_NUM_DEV) || + (dev_minor == MINOR_NUM_SECURE_DEV))); + if (err) { + pr_err("adsprpc: Invalid dev minor num %d\n", dev_minor); + return err; + } + VERIFY(err, NULL != (fl = kzalloc(sizeof(*fl), GFP_KERNEL))); if (err) return err; @@ -3123,6 +3185,8 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) fl->apps = me; fl->mode = FASTRPC_MODE_SERIAL; fl->cid = -1; + fl->dev_minor = dev_minor; + if (debugfs_file != NULL) fl->debugfs_file = debugfs_file; fl->qos_request = 0; @@ -3150,6 +3214,23 @@ static int fastrpc_get_info(struct fastrpc_file *fl, uint32_t *info) VERIFY(err, cid < NUM_CHANNELS); if (err) goto bail; + /* Check to see if the device node is non-secure */ + if (fl->dev_minor == MINOR_NUM_DEV) { + /* + * For non secure device node check and make sure that + * the channel allows non-secure access + * If not, bail. Session will not start. + * cid will remain -1 and client will not be able to + * invoke any other methods without failure + */ + if (fl->apps->channel[cid].secure == SECURE_CHANNEL) { + err = -EPERM; + pr_err("adsprpc: GetInfo failed dev %d, cid %d, secure %d\n", + fl->dev_minor, cid, + fl->apps->channel[cid].secure); + goto bail; + } + } fl->cid = cid; fl->ssrcount = fl->apps->channel[cid].ssrcount; VERIFY(err, !fastrpc_session_alloc_locked( @@ -3209,12 +3290,18 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, union { struct fastrpc_ioctl_invoke_crc inv; struct fastrpc_ioctl_mmap mmap; + struct fastrpc_ioctl_mmap_64 mmap64; struct fastrpc_ioctl_munmap munmap; + struct fastrpc_ioctl_munmap_64 munmap64; struct fastrpc_ioctl_munmap_fd munmap_fd; struct fastrpc_ioctl_init_attrs init; struct fastrpc_ioctl_perf perf; struct fastrpc_ioctl_control cp; } p; + union { + struct fastrpc_ioctl_mmap mmap; + struct fastrpc_ioctl_munmap munmap; + } i; void *param = (char *)ioctl_param; struct fastrpc_file *fl = (struct fastrpc_file *)file->private_data; int size = 0, err = 0; @@ -3278,24 +3365,27 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, goto bail; break; case FASTRPC_IOCTL_MMAP_64: - K_COPY_FROM_USER(err, 0, &p.mmap, param, - sizeof(p.mmap)); + K_COPY_FROM_USER(err, 0, &p.mmap64, param, + sizeof(p.mmap64)); if (err) goto bail; - VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &p.mmap))); + get_fastrpc_ioctl_mmap_64(&p.mmap64, &i.mmap); + VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &i.mmap))); if (err) goto bail; - K_COPY_TO_USER(err, 0, param, &p.mmap, sizeof(p.mmap)); + put_fastrpc_ioctl_mmap_64(&p.mmap64, &i.mmap); + K_COPY_TO_USER(err, 0, param, &p.mmap64, sizeof(p.mmap64)); if (err) goto bail; break; case FASTRPC_IOCTL_MUNMAP_64: - K_COPY_FROM_USER(err, 0, &p.munmap, param, - sizeof(p.munmap)); + K_COPY_FROM_USER(err, 0, &p.munmap64, param, + sizeof(p.munmap64)); if (err) goto bail; + get_fastrpc_ioctl_munmap_64(&p.munmap64, &i.munmap); VERIFY(err, 0 == (err = fastrpc_internal_munmap(fl, - &p.munmap))); + &i.munmap))); if (err) goto bail; break; @@ -3512,8 +3602,16 @@ static int fastrpc_get_service_location_notify(struct notifier_block *nb, pdr->domain_list[i].name, pdr->domain_list[i].instance_id, &spd->pdrnb, &curr_state); - if (IS_ERR(spd->pdrhandle)) + if (IS_ERR(spd->pdrhandle)) { pr_err("ADSPRPC: Unable to register notifier\n"); + } else if (curr_state == + SERVREG_NOTIF_SERVICE_STATE_UP_V01) { + pr_info("ADSPRPC: STATE_UP_V01 received\n"); + spd->ispdup = 1; + } else if (curr_state == + SERVREG_NOTIF_SERVICE_STATE_UNINIT_V01) { + pr_info("ADSPRPC: STATE_UNINIT_V01 received\n"); + } break; } } @@ -3721,6 +3819,25 @@ static void init_secure_vmid_list(struct device *dev, char *prop_name, } } +static void configure_secure_channels(uint32_t secure_domains) +{ + struct fastrpc_apps *me = &gfa; + int ii = 0; + /* + * secure_domains contains the bitmask of the secure channels + * Bit 0 - ADSP + * Bit 1 - MDSP + * Bit 2 - SLPI + * Bit 3 - CDSP + */ + for (ii = ADSP_DOMAIN_ID; ii <= CDSP_DOMAIN_ID; ++ii) { + int secure = (secure_domains >> ii) & 0x01; + + me->channel[ii].secure = secure; + } +} + + static int fastrpc_probe(struct platform_device *pdev) { int err = 0; @@ -3731,7 +3848,7 @@ static int fastrpc_probe(struct platform_device *pdev) struct cma *cma; uint32_t val; int ret = 0; - + uint32_t secure_domains; if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute")) { @@ -3741,6 +3858,16 @@ static int fastrpc_probe(struct platform_device *pdev) of_property_read_u32(dev->of_node, "qcom,rpc-latency-us", &me->latency); + if (of_get_property(dev->of_node, + "qcom,secure-domains", NULL) != NULL) { + VERIFY(err, !of_property_read_u32(dev->of_node, + "qcom,secure-domains", + &secure_domains)); + if (!err) + configure_secure_channels(secure_domains); + else + pr_info("adsprpc: unable to read the domain configuration from dts\n"); + } } if (of_device_is_compatible(dev->of_node, "qcom,msm-fastrpc-compute-cb")) @@ -3886,6 +4013,7 @@ static int __init fastrpc_device_init(void) { struct fastrpc_apps *me = &gfa; struct device *dev = NULL; + struct device *secure_dev = NULL; int err = 0, i; memset(me, 0, sizeof(*me)); @@ -3903,7 +4031,7 @@ static int __init fastrpc_device_init(void) cdev_init(&me->cdev, &fops); me->cdev.owner = THIS_MODULE; VERIFY(err, 0 == cdev_add(&me->cdev, MKDEV(MAJOR(me->dev_no), 0), - 1)); + NUM_DEVICES)); if (err) goto cdev_init_bail; me->class = class_create(THIS_MODULE, "fastrpc"); @@ -3911,14 +4039,30 @@ static int __init fastrpc_device_init(void) if (err) goto class_create_bail; me->compat = (fops.compat_ioctl == NULL) ? 0 : 1; + + /* + * Create devices and register with sysfs + * Create first device with minor number 0 + */ dev = device_create(me->class, NULL, - MKDEV(MAJOR(me->dev_no), 0), - NULL, gcinfo[0].name); + MKDEV(MAJOR(me->dev_no), MINOR_NUM_DEV), + NULL, DEVICE_NAME); VERIFY(err, !IS_ERR_OR_NULL(dev)); if (err) goto device_create_bail; + + /* Create secure device with minor number for secure device */ + secure_dev = device_create(me->class, NULL, + MKDEV(MAJOR(me->dev_no), MINOR_NUM_SECURE_DEV), + NULL, DEVICE_NAME_SECURE); + VERIFY(err, !IS_ERR_OR_NULL(secure_dev)); + if (err) + goto device_create_bail; + for (i = 0; i < NUM_CHANNELS; i++) { - me->channel[i].dev = dev; + me->channel[i].dev = secure_dev; + if (i == CDSP_DOMAIN_ID) + me->channel[i].dev = dev; me->channel[i].ssrcount = 0; me->channel[i].prevssrcount = 0; me->channel[i].issubsystemup = 1; @@ -3943,7 +4087,11 @@ static int __init fastrpc_device_init(void) &me->channel[i].nb); } if (!IS_ERR_OR_NULL(dev)) - device_destroy(me->class, MKDEV(MAJOR(me->dev_no), 0)); + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), + MINOR_NUM_DEV)); + if (!IS_ERR_OR_NULL(secure_dev)) + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), + MINOR_NUM_SECURE_DEV)); class_destroy(me->class); class_create_bail: cdev_del(&me->cdev); @@ -3965,10 +4113,15 @@ static void __exit fastrpc_device_exit(void) for (i = 0; i < NUM_CHANNELS; i++) { if (!gcinfo[i].name) continue; - device_destroy(me->class, MKDEV(MAJOR(me->dev_no), i)); subsys_notif_unregister_notifier(me->channel[i].handle, &me->channel[i].nb); } + + /* Destroy the secure and non secure devices */ + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), MINOR_NUM_DEV)); + device_destroy(me->class, MKDEV(MAJOR(me->dev_no), + MINOR_NUM_SECURE_DEV)); + class_destroy(me->class); cdev_del(&me->cdev); unregister_chrdev_region(me->dev_no, NUM_CHANNELS); diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index 952b87ca319b5701b46bef6ad5a6a9a17391462f..25a2ad85374f6a225984754c45fa09c848141de2 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -36,6 +36,7 @@ #define FASTRPC_GLINK_GUID "fastrpcglink-apps-dsp" #define FASTRPC_SMD_GUID "fastrpcsmd-apps-dsp" #define DEVICE_NAME "adsprpc-smd" +#define DEVICE_NAME_SECURE "adsprpc-smd-secure" /* Set for buffers that have no virtual mapping in userspace */ #define FASTRPC_ATTR_NOVA 0x1 diff --git a/drivers/char/diag/diag_debugfs.c b/drivers/char/diag/diag_debugfs.c index a7f29e63e214c22af31289a6158575a3affb2407..acee74a14cda0dacdd745de49fd0b98f98e5089b 100644 --- a/drivers/char/diag/diag_debugfs.c +++ b/drivers/char/diag/diag_debugfs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -797,6 +797,7 @@ static ssize_t diag_dbgfs_read_glinkinfo(struct file *file, char __user *ubuf, return ret; } +#ifdef CONFIG_IPC_LOGGING static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf, size_t count, loff_t *ppos) { @@ -827,6 +828,7 @@ static ssize_t diag_dbgfs_write_debug(struct file *fp, const char __user *buf, diag_debug_mask = (uint16_t)value; return count; } +#endif #ifdef CONFIG_DIAGFWD_BRIDGE_CODE #ifdef CONFIG_USB_QCOM_DIAG_BRIDGE @@ -1086,9 +1088,11 @@ const struct file_operations diag_dbgfs_power_ops = { .read = diag_dbgfs_read_power, }; +#ifdef CONFIG_IPC_LOGGING const struct file_operations diag_dbgfs_debug_ops = { .write = diag_dbgfs_write_debug }; +#endif int diag_debugfs_init(void) { @@ -1145,11 +1149,12 @@ int diag_debugfs_init(void) if (!entry) goto err; +#ifdef CONFIG_IPC_LOGGING entry = debugfs_create_file("debug", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_debug_ops); if (!entry) goto err; - +#endif #ifdef CONFIG_DIAGFWD_BRIDGE_CODE entry = debugfs_create_file("bridge", 0444, diag_dbgfs_dent, 0, &diag_dbgfs_bridge_ops); diff --git a/drivers/char/diag/diag_ipc_logging.h b/drivers/char/diag/diag_ipc_logging.h index 4b8dd1b12c1c231e161e49e5c948fc2932094034..839c8ca02e7c8f73f6f0bf7fabf58551c9a2e1ff 100644 --- a/drivers/char/diag/diag_ipc_logging.h +++ b/drivers/char/diag/diag_ipc_logging.h @@ -26,9 +26,7 @@ #define DIAG_DEBUG_BRIDGE 0x0040 #define DIAG_DEBUG_CONTROL 0x0080 -#define DIAG_DEBUG - -#ifdef DIAG_DEBUG +#ifdef CONFIG_IPC_LOGGING extern uint16_t diag_debug_mask; extern void *diag_ipc_log; diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index 44cf56cd892186b1cb268a4e804136180deb3a55..a3c19c4a6e5c9d73912526414517f3ea7c762809 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -169,6 +169,9 @@ static void diag_send_log_mask_update(uint8_t peripheral, int equip_id) mutex_lock(&mask_info->lock); for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + if (!mask->ptr) + continue; + if (equip_id != i && equip_id != ALL_EQUIP_ID) continue; @@ -399,6 +402,8 @@ static void diag_send_msg_mask_update(uint8_t peripheral, int first, int last) } for (i = 0; i < msg_mask_tbl_count_local; i++, mask++) { + if (!mask->ptr) + continue; mutex_lock(&driver->msg_mask_lock); if (((mask->ssid_first > first) || (mask->ssid_last_tools < last)) && first != ALL_SSID) { @@ -642,6 +647,8 @@ static int diag_cmd_get_build_mask(unsigned char *src_buf, int src_len, rsp.padding = 0; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { + if (!build_mask->ptr) + continue; if (build_mask->ssid_first != req->ssid_first) continue; num_entries = req->ssid_last - req->ssid_first + 1; @@ -718,6 +725,8 @@ static int diag_cmd_get_msg_mask(unsigned char *src_buf, int src_len, return -EINVAL; } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; if ((req->ssid_first < mask->ssid_first) || (req->ssid_first > mask->ssid_last_tools)) { continue; @@ -784,6 +793,8 @@ static int diag_cmd_set_msg_mask(unsigned char *src_buf, int src_len, return -EINVAL; } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; if (i < (driver->msg_mask_tbl_count - 1)) { mask_next = mask; mask_next++; @@ -1551,7 +1562,8 @@ static int diag_create_msg_mask_table(void) mutex_lock(&msg_mask.lock); mutex_lock(&driver->msg_mask_lock); driver->msg_mask_tbl_count = MSG_MASK_TBL_CNT; - for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + for (i = 0; (i < driver->msg_mask_tbl_count) && mask; + i++, mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(mask, &range); @@ -1575,7 +1587,8 @@ static int diag_create_build_time_mask(void) mutex_lock(&driver->msg_mask_lock); driver->bt_msg_mask_tbl_count = MSG_MASK_TBL_CNT; build_mask = (struct diag_msg_mask_t *)msg_bt_mask.ptr; - for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { + for (i = 0; (i < driver->bt_msg_mask_tbl_count) && build_mask; + i++, build_mask++) { range.ssid_first = msg_mask_tbl[i].ssid_first; range.ssid_last = msg_mask_tbl[i].ssid_last; err = diag_create_msg_mask_table_entry(build_mask, &range); @@ -1698,7 +1711,7 @@ static int diag_create_log_mask_table(void) mutex_lock(&log_mask.lock); mask = (struct diag_log_mask_t *)(log_mask.ptr); - for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + for (i = 0; (i < MAX_EQUIP_ID) && mask; i++, mask++) { mask->equip_id = i; mask->num_items = LOG_GET_ITEM_NUM(log_code_last_tbl[i]); mask->num_items_tools = mask->num_items; @@ -2080,6 +2093,8 @@ int diag_copy_to_user_msg_mask(char __user *buf, size_t count, return -EINVAL; } for (i = 0; i < driver->msg_mask_tbl_count; i++, mask++) { + if (!mask->ptr) + continue; ptr = mask_info->update_buf; len = 0; mutex_lock(&mask->lock); @@ -2151,6 +2166,8 @@ int diag_copy_to_user_log_mask(char __user *buf, size_t count, return -EINVAL; } for (i = 0; i < MAX_EQUIP_ID; i++, mask++) { + if (!mask->ptr) + continue; ptr = mask_info->update_buf; len = 0; mutex_lock(&mask->lock); diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index c00fbfc0324b9efcf698e0b7abd024489f675ffe..393f20fb7d3618b3bb20dd187147b642b54cb2ae 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -160,11 +160,12 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) return -EIO; } pid = session_info->pid; - mutex_unlock(&driver->md_session_lock); ch = &diag_md[id]; - if (!ch || !ch->md_info_inited) + if (!ch || !ch->md_info_inited) { + mutex_unlock(&driver->md_session_lock); return -EINVAL; + } spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -180,8 +181,10 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } spin_unlock_irqrestore(&ch->lock, flags); - if (found) + if (found) { + mutex_unlock(&driver->md_session_lock); return -ENOMEM; + } spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -194,6 +197,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } } spin_unlock_irqrestore(&ch->lock, flags); + mutex_unlock(&driver->md_session_lock); if (!found) { pr_err_ratelimited("diag: Unable to find an empty space in table, please reduce logging rate, proc: %d\n", @@ -202,6 +206,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) } found = 0; + mutex_lock(&driver->diagchar_mutex); for (i = 0; i < driver->num_clients && !found; i++) { if ((driver->client_map[i].pid != pid) || (driver->client_map[i].pid == 0)) @@ -215,6 +220,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) pr_debug("diag: wake up logging process\n"); wake_up_interruptible(&driver->wait_q); } + mutex_unlock(&driver->diagchar_mutex); if (!found) return -EINVAL; diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index a1692300b0f62289bf505ef14cbe208e1161e700..8b089eb6c850e9d9f6c3c171809755d0eddf3c2d 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -162,7 +162,7 @@ static struct mutex apps_data_mutex; #define DIAGPKT_MAX_DELAYED_RSP 0xFFFF -#ifdef DIAG_DEBUG +#ifdef CONFIG_IPC_LOGGING uint16_t diag_debug_mask; void *diag_ipc_log; #endif @@ -3804,7 +3804,7 @@ void diag_ws_release(void) pm_relax(driver->diag_dev); } -#ifdef DIAG_DEBUG +#ifdef CONFIG_IPC_LOGGING static void diag_debug_init(void) { diag_ipc_log = ipc_log_context_create(DIAG_IPC_LOG_PAGES, "diag", 0); diff --git a/drivers/char/diag/diagfwd_cntl.c b/drivers/char/diag/diagfwd_cntl.c index ac4394b308baacd7e33e82f85aa04d749ab514fa..a6d5ca8a952abde7f65201c9dfacc68a354c4e91 100644 --- a/drivers/char/diag/diagfwd_cntl.c +++ b/drivers/char/diag/diagfwd_cntl.c @@ -668,7 +668,7 @@ static void process_ssid_range_report(uint8_t *buf, uint32_t len, mask_ptr = (struct diag_msg_mask_t *)msg_mask.ptr; found = 0; for (j = 0; j < driver->msg_mask_tbl_count; j++, mask_ptr++) { - if (!mask_ptr || !ssid_range) { + if (!mask_ptr->ptr || !ssid_range) { found = 1; break; } @@ -747,7 +747,7 @@ static void diag_build_time_mask_update(uint8_t *buf, num_items = range->ssid_last - range->ssid_first + 1; for (i = 0; i < driver->bt_msg_mask_tbl_count; i++, build_mask++) { - if (!build_mask) { + if (!build_mask->ptr) { found = 1; break; } diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index 2022e7be73b597236dbb0e3b0247f9b73c1e59f8..848ce0642f738ee161b25edb28c727c310205e5f 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -191,6 +191,7 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) { int i, ctx = 0; uint32_t max_size = 0; + unsigned long flags; unsigned char *temp_buf = NULL; struct diag_md_info *ch = NULL; @@ -205,12 +206,17 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) max_size = MAX_PERIPHERAL_HDLC_BUF_SZ; } + mutex_lock(&driver->md_session_lock); if (buf->len < max_size) { if (driver->logging_mode == DIAG_MEMORY_DEVICE_MODE || driver->logging_mode == DIAG_MULTI_MODE) { ch = &diag_md[DIAG_LOCAL_PROC]; - for (i = 0; ch != NULL && - i < ch->num_tbl_entries; i++) { + if (!ch || !ch->md_info_inited) { + mutex_unlock(&driver->md_session_lock); + return -EINVAL; + } + spin_lock_irqsave(&ch->lock, flags); + for (i = 0; i < ch->num_tbl_entries; i++) { if (ch->tbl[i].buf == buf->data) { ctx = ch->tbl[i].ctx; ch->tbl[i].buf = NULL; @@ -223,18 +229,22 @@ static int check_bufsize_for_encoding(struct diagfwd_buf_t *buf, uint32_t len) break; } } + spin_unlock_irqrestore(&ch->lock, flags); } temp_buf = krealloc(buf->data, max_size + APF_DIAG_PADDING, GFP_KERNEL); - if (!temp_buf) + if (!temp_buf) { + mutex_unlock(&driver->md_session_lock); return -ENOMEM; + } DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "Reallocated data buffer: %pK with size: %d\n", temp_buf, max_size); buf->data = temp_buf; buf->len = max_size; } + mutex_unlock(&driver->md_session_lock); } return buf->len; @@ -385,6 +395,8 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, goto end; } } + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); if (write_len > 0) { err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len, @@ -392,18 +404,18 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, if (err) { pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n", __func__, err); - goto end; + goto end_write; } } - mutex_unlock(&fwd_info->data_mutex); - mutex_unlock(&driver->hdlc_disable_mutex); + diagfwd_queue_read(fwd_info); return; end: - diag_ws_release(); mutex_unlock(&fwd_info->data_mutex); mutex_unlock(&driver->hdlc_disable_mutex); +end_write: + diag_ws_release(); if (buf) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "Marking buffer as free p: %d, t: %d, buf_num: %d\n", @@ -690,24 +702,26 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, } } + mutex_unlock(&fwd_info->data_mutex); + mutex_unlock(&driver->hdlc_disable_mutex); + if (write_len > 0) { err = diag_mux_write(DIAG_LOCAL_PROC, write_buf, write_len, temp_buf->ctxt); if (err) { pr_err_ratelimited("diag: In %s, unable to write to mux error: %d\n", __func__, err); - goto end; + goto end_write; } } - mutex_unlock(&fwd_info->data_mutex); - mutex_unlock(&driver->hdlc_disable_mutex); diagfwd_queue_read(fwd_info); return; end: - diag_ws_release(); mutex_unlock(&fwd_info->data_mutex); mutex_unlock(&driver->hdlc_disable_mutex); +end_write: + diag_ws_release(); if (temp_buf) { DIAG_LOG(DIAG_DEBUG_PERIPHERALS, "Marking buffer as free p: %d, t: %d, buf_num: %d\n", diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index feafdab734ae20b268e3078bd71822ef382a408e..4835b588b7833fb554ac0394c8c7ada8262d6892 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -522,11 +522,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) if (status & BT_H_BUSY) /* clear a leftover H_BUSY */ BT_CONTROL(BT_H_BUSY); + bt->timeout = bt->BT_CAP_req2rsp; + /* Read BT capabilities if it hasn't been done yet */ if (!bt->BT_CAP_outreqs) BT_STATE_CHANGE(BT_STATE_CAPABILITIES_BEGIN, SI_SM_CALL_WITHOUT_DELAY); - bt->timeout = bt->BT_CAP_req2rsp; BT_SI_SM_RETURN(SI_SM_IDLE); case BT_STATE_XACTION_START: diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 9ff8532299570315aa1fd7f366d30bd4020e98b6..8d097d10fd13b1be1acad4d24e8360e16aec72cb 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -388,8 +389,20 @@ static int tpm_add_legacy_sysfs(struct tpm_chip *chip) */ int tpm_chip_register(struct tpm_chip *chip) { +#ifdef CONFIG_OF + struct device_node *np; +#endif int rc; +#ifdef CONFIG_OF + np = of_find_node_by_name(NULL, "vtpm"); + if (np) { + if (of_property_read_bool(np, "powered-while-suspended")) + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + } + of_node_put(np); +#endif + if (chip->ops->flags & TPM_OPS_AUTO_STARTUP) { if (chip->flags & TPM_CHIP_FLAG_TPM2) rc = tpm2_auto_startup(chip); diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 830d7e30e508ae68203d8ab3f929744a6cafe6e2..faf2db122ab99e4b403a57c97bfa363350617a96 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -803,6 +803,10 @@ int tpm_do_selftest(struct tpm_chip *chip) loops = jiffies_to_msecs(duration) / delay_msec; rc = tpm_continue_selftest(chip); + if (rc == TPM_ERR_INVALID_POSTINIT) { + chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED; + dev_info(&chip->dev, "TPM not ready (%d)\n", rc); + } /* This may fail if there was no TPM driver during a suspend/resume * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST) */ @@ -969,6 +973,9 @@ int tpm_pm_suspend(struct device *dev) if (chip == NULL) return -ENODEV; + if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED) + return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { tpm2_shutdown(chip, TPM2_SU_STATE); return 0; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index aa4299cf7e5aa48dee72afd2c1fbef3708b0f4d5..a4fc2badf633b7f3a3e31380f027416e949a44cf 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -143,6 +143,7 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_TPM2 = BIT(1), TPM_CHIP_FLAG_IRQ = BIT(2), TPM_CHIP_FLAG_VIRTUAL = BIT(3), + TPM_CHIP_FLAG_ALWAYS_POWERED = BIT(5), }; struct tpm_chip { diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index 45ad168e1496562fb79ccd2c4fceb0f5a9ea2087..2bb2551c62457aa335908d200a7d50cb8fc8d0c1 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -132,19 +132,8 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_pll *pll = to_clk_pll(hw); - unsigned int pllr; - u16 mul; - u8 div; - - regmap_read(pll->regmap, PLL_REG(pll->id), &pllr); - - div = PLL_DIV(pllr); - mul = PLL_MUL(pllr, pll->layout); - - if (!div || !mul) - return 0; - return (parent_rate / div) * (mul + 1); + return (parent_rate / pll->div) * (pll->mul + 1); } static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index 25c41cd9cdfc76332a7836114e939a225cf72d17..7ecc5eac3d7fa9dd3a5cb8c4302baa8af3623014 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -243,8 +243,9 @@ struct clk *cpg_mssr_clk_src_twocell_get(struct of_phandle_args *clkspec, dev_err(dev, "Cannot get %s clock %u: %ld", type, clkidx, PTR_ERR(clk)); else - dev_dbg(dev, "clock (%u, %u) is %pC at %pCr Hz\n", - clkspec->args[0], clkspec->args[1], clk, clk); + dev_dbg(dev, "clock (%u, %u) is %pC at %lu Hz\n", + clkspec->args[0], clkspec->args[1], clk, + clk_get_rate(clk)); return clk; } @@ -304,7 +305,7 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, if (IS_ERR_OR_NULL(clk)) goto fail; - dev_dbg(dev, "Core clock %pC at %pCr Hz\n", clk, clk); + dev_dbg(dev, "Core clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); priv->clks[id] = clk; return; @@ -372,7 +373,7 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod, if (IS_ERR(clk)) goto fail; - dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk); + dev_dbg(dev, "Module clock %pC at %lu Hz\n", clk, clk_get_rate(clk)); priv->clks[id] = clk; return; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index f474e70a1b6b4e99140cf0708461cf8129f4db52..6e16d9fe9b6fc51d8ba3ef049e4915edfb410670 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -773,6 +773,8 @@ static ssize_t store_##file_name \ struct cpufreq_policy new_policy; \ \ memcpy(&new_policy, policy, sizeof(*policy)); \ + new_policy.min = policy->user_policy.min; \ + new_policy.max = policy->user_policy.max; \ \ new_policy.min = new_policy.user_policy.min; \ new_policy.max = new_policy.user_policy.max; \ diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c index 854a567811002329e9b39068ad8d4834e9b8cf71..fd96af1d2ef0c1285a6042bfb8fdf4ed29de0e55 100644 --- a/drivers/cpuidle/cpuidle-powernv.c +++ b/drivers/cpuidle/cpuidle-powernv.c @@ -32,9 +32,31 @@ static struct cpuidle_state *cpuidle_state_table; static u64 stop_psscr_table[CPUIDLE_STATE_MAX]; -static u64 snooze_timeout; +static u64 default_snooze_timeout; static bool snooze_timeout_en; +static u64 get_snooze_timeout(struct cpuidle_device *dev, + struct cpuidle_driver *drv, + int index) +{ + int i; + + if (unlikely(!snooze_timeout_en)) + return default_snooze_timeout; + + for (i = index + 1; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; + struct cpuidle_state_usage *su = &dev->states_usage[i]; + + if (s->disabled || su->disable) + continue; + + return s->target_residency * tb_ticks_per_usec; + } + + return default_snooze_timeout; +} + static int snooze_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -44,7 +66,7 @@ static int snooze_loop(struct cpuidle_device *dev, local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); - snooze_exit_time = get_tb() + snooze_timeout; + snooze_exit_time = get_tb() + get_snooze_timeout(dev, drv, index); ppc64_runlatch_off(); while (!need_resched()) { HMT_low(); @@ -337,11 +359,9 @@ static int powernv_idle_probe(void) cpuidle_state_table = powernv_states; /* Device tree can indicate more idle states */ max_idle_state = powernv_add_idle_states(); - if (max_idle_state > 1) { + default_snooze_timeout = TICK_USEC * tb_ticks_per_usec; + if (max_idle_state > 1) snooze_timeout_en = true; - snooze_timeout = powernv_states[1].target_residency * - tb_ticks_per_usec; - } } else return -ENODEV; diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 8643667a65e1c9de633722af0361277ae28c5371..19f2289a64e98359b167296c59b66b15e520a41d 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -1,7 +1,7 @@ /* * QTI Crypto Engine driver. * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -6118,13 +6118,15 @@ EXPORT_SYMBOL(qce_open); int qce_close(void *handle) { struct qce_device *pce_dev = (struct qce_device *) handle; + int ret = -1; if (handle == NULL) return -ENODEV; mutex_lock(&qce_iomap_mutex); - qce_enable_clk(pce_dev); - qce_sps_exit(pce_dev); + ret = qce_enable_clk(pce_dev); + if (!ret) + qce_sps_exit(pce_dev); if (pce_dev->iobase) iounmap(pce_dev->iobase); @@ -6137,7 +6139,8 @@ int qce_close(void *handle) if (pce_dev->enable_s1_smmu) qce_iommu_release_iomapping(pce_dev); - qce_disable_clk(pce_dev); + if (!ret) + qce_disable_clk(pce_dev); __qce_deinit_clk(pce_dev); mutex_unlock(&qce_iomap_mutex); kfree(handle); diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index d8305ddf87d0787c57ebc539eaf9088337c5fe32..ff6ac4e824b5eeb7ef0a84ce8c3e40d840ad107a 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -1081,7 +1081,7 @@ static void omap_sham_finish_req(struct ahash_request *req, int err) if (test_bit(FLAGS_SGS_COPIED, &dd->flags)) free_pages((unsigned long)sg_virt(ctx->sg), - get_order(ctx->sg->length)); + get_order(ctx->sg->length + ctx->bufcnt)); if (test_bit(FLAGS_SGS_ALLOCED, &dd->flags)) kfree(ctx->sg); diff --git a/drivers/crypto/vmx/aes.c b/drivers/crypto/vmx/aes.c index 022c7ab7351a08c4f6afdff324e0b51eb1214bb1..b0cd5aff3822f56bad6a623a55e408fd402a03bd 100644 --- a/drivers/crypto/vmx/aes.c +++ b/drivers/crypto/vmx/aes.c @@ -53,8 +53,6 @@ static int p8_aes_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_cipher_set_flags(fallback, crypto_cipher_get_flags((struct diff --git a/drivers/crypto/vmx/aes_cbc.c b/drivers/crypto/vmx/aes_cbc.c index 94ad5c0adbcbd3002e4813d70b100459cfa1ec57..46131701c3789d4e3e02fc0642c76301a0a8d4e9 100644 --- a/drivers/crypto/vmx/aes_cbc.c +++ b/drivers/crypto/vmx/aes_cbc.c @@ -55,8 +55,6 @@ static int p8_aes_cbc_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_blkcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/aes_ctr.c b/drivers/crypto/vmx/aes_ctr.c index 7cf6d31c1123a117d55dc3de87ed543a3c6279a6..6ef7548c5c877f3cd47cd0666026f28243140a68 100644 --- a/drivers/crypto/vmx/aes_ctr.c +++ b/drivers/crypto/vmx/aes_ctr.c @@ -53,8 +53,6 @@ static int p8_aes_ctr_init(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name((struct crypto_tfm *) fallback)); crypto_blkcipher_set_flags( fallback, diff --git a/drivers/crypto/vmx/ghash.c b/drivers/crypto/vmx/ghash.c index 27a94a11900926d9614d5a747f7e95d07f21afb1..1c4b5b889fbacf181c074baf21d7ae0d65d64c3e 100644 --- a/drivers/crypto/vmx/ghash.c +++ b/drivers/crypto/vmx/ghash.c @@ -64,8 +64,6 @@ static int p8_ghash_init_tfm(struct crypto_tfm *tfm) alg, PTR_ERR(fallback)); return PTR_ERR(fallback); } - printk(KERN_INFO "Using '%s' as fallback implementation.\n", - crypto_tfm_alg_driver_name(crypto_shash_tfm(fallback))); crypto_shash_set_flags(fallback, crypto_shash_get_flags((struct crypto_shash diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 6b54e02da10c9c447b5dc573a2bd79f94329ebcb..e48140e760430ad72183d0e6999621993b1f36b9 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -551,7 +551,7 @@ EXPORT_SYMBOL_GPL(dma_buf_detach); struct sg_table *dma_buf_map_attachment(struct dma_buf_attachment *attach, enum dma_data_direction direction) { - struct sg_table *sg_table = ERR_PTR(-EINVAL); + struct sg_table *sg_table; might_sleep(); diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 065b765c02b46964334a211fcef3074a325708fe..0ce5bd95d25b211c8f8d661c11cef7877a8e6403 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -559,6 +559,7 @@ static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) { u64 time = sched_clock(); unsigned int index = atomic_inc_return(&gpii->dbg_index) - 1; + unsigned long offset = addr - gpii->regs; u32 val; val = readl_relaxed(addr); @@ -568,13 +569,14 @@ static inline u32 gpi_read_reg(struct gpii *gpii, void __iomem *addr) (gpii->dbg_log + index)->val = val; (gpii->dbg_log + index)->read = true; GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", - addr - gpii->regs, val); + offset, val); return val; } static inline void gpi_write_reg(struct gpii *gpii, void __iomem *addr, u32 val) { u64 time = sched_clock(); unsigned int index = atomic_inc_return(&gpii->dbg_index) - 1; + unsigned long offset = addr - gpii->regs; index &= (GPI_DBG_LOG_SIZE - 1); (gpii->dbg_log + index)->addr = addr; @@ -583,7 +585,7 @@ static inline void gpi_write_reg(struct gpii *gpii, void __iomem *addr, u32 val) (gpii->dbg_log + index)->read = false; GPII_REG(gpii, GPI_DBG_COMMON, "offset:0x%lx val:0x%x\n", - addr - gpii->regs, val); + offset, val); writel_relaxed(val, addr); } #else @@ -1244,11 +1246,13 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, /* Event TR RP gen. don't match descriptor TR */ if (gpi_desc->wp != tre) { + phys_addr_t p_wp = to_physical(ch_ring, gpi_desc->wp); + phys_addr_t p_tre = to_physical(ch_ring, tre); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, - "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n", - to_physical(ch_ring, gpi_desc->wp), - to_physical(ch_ring, tre)); + "EOT/EOB received for wrong TRE %pa != %pa\n", + &p_wp, &p_tre); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; @@ -1331,11 +1335,13 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, /* TRE Event generated didn't match descriptor's TRE */ if (gpi_desc->wp != ev_rp) { + phys_addr_t p_wp = to_physical(ch_ring, gpi_desc->wp); + phys_addr_t p_ev_rp = to_physical(ch_ring, ev_rp); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); GPII_ERR(gpii, gpii_chan->chid, - "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n", - to_physical(ch_ring, gpi_desc->wp), - to_physical(ch_ring, ev_rp)); + "EOT\EOB received for wrong TRE %pa != %pa\n", + &p_wp, &p_ev_rp); gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, __LINE__); return; @@ -1588,12 +1594,12 @@ static int gpi_alloc_chan(struct gpii_chan *gpii_chan, bool send_alloc_cmd) { gpii_chan->ch_cntxt_base_reg, CNTXT_3_RING_BASE_MSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { /* program MSB of DB register with ring base */ gpii_chan->ch_cntxt_db_reg, CNTXT_5_RING_RP_MSB - CNTXT_4_RING_RP_LSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { gpii->regs, @@ -1682,13 +1688,13 @@ static int gpi_alloc_ev_chan(struct gpii *gpii) { gpii->ev_cntxt_base_reg, CNTXT_3_RING_BASE_MSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { /* program db msg with ring base msb */ gpii->ev_cntxt_db_reg, CNTXT_5_RING_RP_MSB - CNTXT_4_RING_RP_LSB, - (u32)(ring->phys_addr >> 32), + MSM_GPI_RING_PHYS_ADDR_UPPER(ring), }, { gpii->ev_cntxt_base_reg, @@ -1825,7 +1831,7 @@ static int gpi_alloc_ring(struct gpi_ring *ring, len = 1 << bit; ring->alloc_size = (len + (len - 1)); GPII_INFO(gpii, GPI_DBG_COMMON, - "#el:%u el_size:%u len:%u actual_len:%llu alloc_size:%lu\n", + "#el:%u el_size:%u len:%u actual_len:%llu alloc_size:%zx\n", elements, el_size, (elements * el_size), len, ring->alloc_size); ring->pre_aligned = dma_alloc_coherent(gpii->gpi_dev->dev, @@ -1833,7 +1839,7 @@ static int gpi_alloc_ring(struct gpi_ring *ring, &ring->dma_handle, GFP_KERNEL); if (!ring->pre_aligned) { GPII_CRITIC(gpii, GPI_DBG_COMMON, - "could not alloc size:%lu mem for ring\n", + "could not alloc size:%zx mem for ring\n", ring->alloc_size); return -ENOMEM; } @@ -1853,8 +1859,8 @@ static int gpi_alloc_ring(struct gpi_ring *ring, smp_wmb(); GPII_INFO(gpii, GPI_DBG_COMMON, - "phy_pre:0x%0llx phy_alig:0x%0llx len:%u el_size:%u elements:%u\n", - ring->dma_handle, ring->phys_addr, ring->len, ring->el_size, + "phy_pre:%pad phy_alig:%pa len:%u el_size:%u elements:%u\n", + &ring->dma_handle, &ring->phys_addr, ring->len, ring->el_size, ring->elements); return 0; @@ -2064,6 +2070,10 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, void *tre, *wp = NULL; const gfp_t gfp = GFP_ATOMIC; struct gpi_desc *gpi_desc; +#ifdef CONFIG_QCOM_GPI_DMA_DEBUG + phys_addr_t p_wp, p_rp; +#endif + GPII_VERB(gpii, gpii_chan->chid, "enter\n"); @@ -2106,9 +2116,12 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, gpi_desc->db = ch_ring->wp; gpi_desc->wp = wp; gpi_desc->gpii_chan = gpii_chan; - GPII_VERB(gpii, gpii_chan->chid, "exit wp:0x%0llx rp:0x%0llx\n", - to_physical(ch_ring, ch_ring->wp), - to_physical(ch_ring, ch_ring->rp)); +#ifdef CONFIG_QCOM_GPI_DMA_DEBUG + p_wp = to_physical(ch_ring, ch_ring->wp); + p_rp = to_physical(ch_ring, ch_ring->rp); +#endif + GPII_VERB(gpii, gpii_chan->chid, "exit wp:%pa rp:%pa\n", + &p_wp, &p_rp); return vchan_tx_prep(&gpii_chan->vc, &gpi_desc->vd, flags); } @@ -2558,28 +2571,12 @@ static struct dma_iommu_mapping *gpi_create_mapping(struct gpi_dev *gpi_dev) size = gpi_dev->iova_size; } - GPI_LOG(gpi_dev, "Creating iommu mapping of base:0x%llx size:%lu\n", - base, size); + GPI_LOG(gpi_dev, "Creating iommu mapping of base:%pad size:%zx\n", + &base, size); return arm_iommu_create_mapping(&platform_bus_type, base, size); } -static int gpi_dma_mask(struct gpi_dev *gpi_dev) -{ - int mask = 64; - - if (gpi_dev->smmu_cfg && !(gpi_dev->smmu_cfg & GPI_SMMU_S1_BYPASS)) { - unsigned long addr; - - addr = gpi_dev->iova_base + gpi_dev->iova_size + 1; - mask = find_last_bit(&addr, 64); - } - - GPI_LOG(gpi_dev, "Setting dma mask to %d\n", mask); - - return dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(mask)); -} - static int gpi_smmu_init(struct gpi_dev *gpi_dev) { struct dma_iommu_mapping *mapping = NULL; @@ -2643,9 +2640,10 @@ static int gpi_smmu_init(struct gpi_dev *gpi_dev) } } - ret = gpi_dma_mask(gpi_dev); + GPI_LOG(gpi_dev, "Setting dma mask to 64\n"); + ret = dma_set_mask(gpi_dev->dev, DMA_BIT_MASK(64)); if (ret) { - GPI_ERR(gpi_dev, "Error setting dma_mask, ret:%d\n", ret); + GPI_ERR(gpi_dev, "Error setting dma_mask to 64, ret:%d\n", ret); goto error_set_mask; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 56b24198741c3db7a3cbb77b656eb1175ed5cd71..dd00764974639118f4f2361a7bd1cb50a6308d4f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3204,6 +3204,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, struct gpio_desc *desc = NULL; int status; enum gpio_lookup_flags lookupflags = 0; + /* Maybe we have a device name, maybe not */ + const char *devname = dev ? dev_name(dev) : "?"; dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id); @@ -3232,8 +3234,11 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - /* If a connection label was passed use that, else use the device name as label */ - status = gpiod_request(desc, con_id ? con_id : dev_name(dev)); + /* + * If a connection label was passed use that, else attempt to use + * the device name as label + */ + status = gpiod_request(desc, con_id ? con_id : devname); if (status < 0) return ERR_PTR(status); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 639410926cadaccda947ae877b0fc8b8815c4427..876a2d99666bf222ad8cde951e263bb311ffd1bd 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -1062,6 +1062,7 @@ int drm_dp_psr_setup_time(const u8 psr_cap[EDP_PSR_RECEIVER_CAP_SIZE]) static const u16 psr_setup_time_us[] = { PSR_SETUP_TIME(330), PSR_SETUP_TIME(275), + PSR_SETUP_TIME(220), PSR_SETUP_TIME(165), PSR_SETUP_TIME(110), PSR_SETUP_TIME(55), diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index ca227e820a3069baf508be8268907300f3f0c49f..847ba40e1f265238f81013fc6b5ae946edcdbfdc 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -205,6 +205,7 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) return -ENOMEM; filp->private_data = priv; + filp->f_mode |= FMODE_UNSIGNED_OFFSET; priv->filp = filp; priv->pid = get_pid(task_pid(current)); priv->minor = minor; diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3517c0ed984ae04a25c0f3cfa36c0933f6909d4c..479d64184da5b150e0593fb7a0bf100f19982d07 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -864,6 +864,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_EXACT_MATCH(DMI_BOARD_NAME, "D525MW"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Radiant P845", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Radiant Systems Inc"), + DMI_MATCH(DMI_PRODUCT_NAME, "P845"), + }, + }, { } /* terminating entry */ }; diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c index 359655a8f97320845932f1d4b349307cb9f5187e..6e6efa5cd41616fa6f5cc46e092279a7af03264f 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ b/drivers/gpu/drm/msm/dp/dp_debug.c @@ -104,7 +104,7 @@ static ssize_t dp_debug_write_edid(struct file *file, size = min_t(size_t, count, SZ_1K); buf = kzalloc(size, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto bail; } @@ -172,7 +172,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file, size = min_t(size_t, count, SZ_2K); buf = kzalloc(size, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto bail; } @@ -493,7 +493,7 @@ static ssize_t dp_debug_read_edid_modes(struct file *file, goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto error; } @@ -538,7 +538,7 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, return 0; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state); @@ -624,7 +624,7 @@ static ssize_t dp_debug_bw_code_read(struct file *file, return 0; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; len += snprintf(buf + len, (SZ_4K - len), @@ -745,7 +745,7 @@ static ssize_t dp_debug_read_hdr(struct file *file, goto error; buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) { + if (ZERO_OR_NULL_PTR(buf)) { rc = -ENOMEM; goto error; } diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index d9839e7e994d8e0fec9fc1b887a0701ba8ac67cf..a0a0daf42c6a99f5026e68a5b6542f0778c6e74c 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -1462,6 +1462,9 @@ int dp_display_get_displays(void **displays, int count) int dp_display_get_num_of_displays(void) { + if (!g_dp_display) + return 0; + return 1; } diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c index 2b7b2171351e9bffdc38f1a553091788ffc10eb0..f277ac0f36f58483c709201b4cf057a06a6e2e31 100644 --- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c +++ b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c @@ -26,6 +26,9 @@ #define DP_INTR_STATUS2 (0x00000024) #define DP_INTR_STATUS3 (0x00000028) + +#define DP_DPCD_CP_IRQ (0x201) + #define dp_read(offset) readl_relaxed((offset)) #define dp_write(offset, data) writel_relaxed((data), (offset)) #define DP_HDCP_RXCAPS_LENGTH 3 @@ -393,6 +396,7 @@ static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl, if (bytes_written != write_size) { pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", offset, write_size, bytes_written); + rc = bytes_written; break; } @@ -675,6 +679,18 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl, return rc; } +static void dp_hdcp2p2_clear_cp_irq(struct dp_hdcp2p2_ctrl *ctrl) +{ + int rc = 0; + u8 buf = BIT(2); + u32 const default_timeout_us = 500; + + rc = dp_hdcp2p2_aux_write_message(ctrl, &buf, 1, + DP_DPCD_CP_IRQ, default_timeout_us); + if (rc) + pr_err("error clearing irq_vector\n"); +} + static int dp_hdcp2p2_cp_irq(void *input) { int rc = 0; @@ -709,6 +725,7 @@ static int dp_hdcp2p2_cp_irq(void *input) kthread_queue_work(&ctrl->worker, &ctrl->link); + dp_hdcp2p2_clear_cp_irq(ctrl); return 0; error: return rc; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index d58a7466b7e1a054f62fc5fc65962f9f97874e8f..c5a1a9fcc20b3e16fe33d7088cb8fbbcd818ac0b 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1130,7 +1130,7 @@ static ssize_t debugfs_misr_read(struct file *file, return 0; buf = kzalloc(max_len, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; mutex_lock(&display->display_lock); @@ -1248,7 +1248,7 @@ static ssize_t debugfs_alter_esd_check_mode(struct file *file, return 0; buf = kzalloc(len, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; if (copy_from_user(buf, user_buf, user_len)) { @@ -1320,7 +1320,7 @@ static ssize_t debugfs_read_esd_check_mode(struct file *file, } buf = kzalloc(len, GFP_KERNEL); - if (!buf) + if (ZERO_OR_NULL_PTR(buf)) return -ENOMEM; esd_config = &display->panel->esd_config; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index f0ea21130829a046276764a9d1487c3438640e91..bf511e3ece77099de46b40235002fc26cad26d50 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -377,7 +377,7 @@ static int dsi_panel_reset(struct dsi_panel *panel) if (r_config->sequence[i].sleep_ms) usleep_range(r_config->sequence[i].sleep_ms * 1000, - r_config->sequence[i].sleep_ms * 1000); + (r_config->sequence[i].sleep_ms * 1000) + 100); } if (gpio_is_valid(panel->bl_config.en_gpio)) { @@ -1566,7 +1566,7 @@ static int dsi_panel_create_cmd_packets(const char *data, return rc; } -void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) +static void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) { u32 i = 0; struct dsi_cmd_desc *cmd; @@ -1575,7 +1575,10 @@ void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set) cmd = &set->cmds[i]; kfree(cmd->msg.tx_buf); } +} +static void dsi_panel_dealloc_cmd_packets(struct dsi_panel_cmd_set *set) +{ kfree(set->cmds); } @@ -3160,8 +3163,10 @@ void dsi_panel_put_mode(struct dsi_display_mode *mode) if (!mode->priv_info) return; - for (i = 0; i < DSI_CMD_SET_MAX; i++) + for (i = 0; i < DSI_CMD_SET_MAX; i++) { dsi_panel_destroy_cmd_packets(&mode->priv_info->cmd_sets[i]); + dsi_panel_dealloc_cmd_packets(&mode->priv_info->cmd_sets[i]); + } kfree(mode->priv_info); } @@ -3363,9 +3368,9 @@ int dsi_panel_update_pps(struct dsi_panel *panel) if (rc) { pr_err("[%s] failed to send DSI_CMD_SET_PPS cmds, rc=%d\n", panel->name, rc); - goto error; } + dsi_panel_destroy_cmd_packets(set); error: mutex_unlock(&panel->panel_lock); return rc; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c index 3da0fc3f0a268b74057ab7342244cccf415cdbc7..45f757703764e420a25f69ebb11294d3623be56c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_timing_v2_0.c @@ -113,7 +113,7 @@ void dsi_phy_hw_v2_0_update_timing_params( else timing->lane[i][4] = desc->hs_rqst.reg_value; - timing->lane[i][5] = 0x3; + timing->lane[i][5] = 0x2; timing->lane[i][6] = 0x4; timing->lane[i][7] = 0xA0; pr_debug("[%d][%d %d %d %d %d]\n", i, timing->lane[i][0], 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 4392c60eb0f356d82f8a4628cb05bdf8f7036f01..c0e9d441542d8fa132e51c55472fe0c8d933c692 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 @@ -92,7 +92,7 @@ void dsi_phy_hw_v3_0_update_timing_params( timing->lane_v3[6] = desc->hs_prepare.reg_value; timing->lane_v3[7] = desc->hs_trail.reg_value; timing->lane_v3[8] = desc->hs_rqst.reg_value; - timing->lane_v3[9] = 0x03; + timing->lane_v3[9] = 0x02; timing->lane_v3[10] = 0x04; timing->lane_v3[11] = 0x00; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index fcdddb34f92597ec6b0b060c2d46c2a5b5df66c4..978aba28a9b1c685405c4578293a7ae18f454f38 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -158,6 +158,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_ENABLE_SUI_ENHANCEMENT, + CRTC_PROP_IDLE_PC_STATE, /* total # of properties */ CRTC_PROP_COUNT diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 34d840006ef6d10c02881be688cbd782e49e10ae..cb4e82d30c56b27b638dd78817b35a279cd9ae43 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -3689,6 +3689,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, struct sde_kms *sde_kms; struct sde_crtc_state *cstate; bool is_error, reset_req; + enum sde_crtc_idle_pc_state idle_pc_state; if (!crtc) { SDE_ERROR("invalid argument\n"); @@ -3719,6 +3720,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, is_error = _sde_crtc_prepare_for_kickoff_rot(dev, crtc); + idle_pc_state = sde_crtc_get_property(cstate, CRTC_PROP_IDLE_PC_STATE); + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct sde_encoder_kickoff_params params = { 0 }; @@ -3734,6 +3737,10 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc, crtc->state); if (sde_encoder_prepare_for_kickoff(encoder, ¶ms)) reset_req = true; + + if (idle_pc_state != IDLE_PC_NONE) + sde_encoder_control_idle_pc(encoder, + (idle_pc_state == IDLE_PC_ENABLE) ? true : false); } /* @@ -4233,6 +4240,13 @@ static void sde_crtc_disable(struct drm_crtc *crtc) sde_encoder_register_frame_event_callback(encoder, NULL, NULL); cstate->rsc_client = NULL; cstate->rsc_update = false; + + /* + * reset idle power-collapse to original state during suspend; + * user-mode will change the state on resume, if required + */ + if (sde_kms->catalog->has_idle_pc) + sde_encoder_control_idle_pc(encoder, true); } if (sde_crtc->power_event) @@ -4976,6 +4990,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, {CAPTURE_DSPP_OUT, "capture_pp_out"}, }; + static const struct drm_prop_enum_list e_idle_pc_state[] = { + {IDLE_PC_NONE, "idle_pc_none"}, + {IDLE_PC_ENABLE, "idle_pc_enable"}, + {IDLE_PC_DISABLE, "idle_pc_disable"}, + }; + SDE_DEBUG("\n"); if (!crtc || !catalog) { @@ -5055,6 +5075,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "enable_sui_enhancement", 0, 0, U64_MAX, 0, CRTC_PROP_ENABLE_SUI_ENHANCEMENT); + if (catalog->has_idle_pc) + msm_property_install_enum(&sde_crtc->property_info, + "idle_pc_state", 0x0, 0, e_idle_pc_state, + ARRAY_SIZE(e_idle_pc_state), + CRTC_PROP_IDLE_PC_STATE); + if (catalog->has_cwb_support) msm_property_install_enum(&sde_crtc->property_info, "capture_mode", 0, 0, e_cwb_data_points, @@ -6163,6 +6189,7 @@ static int _sde_crtc_event_enable(struct sde_kms *kms, unsigned long flags; bool found = false; int ret, i = 0; + bool add_event = false; crtc = to_sde_crtc(crtc_drm); spin_lock_irqsave(&crtc->spin_lock, flags); @@ -6212,11 +6239,24 @@ static int _sde_crtc_event_enable(struct sde_kms *kms, } INIT_LIST_HEAD(&node->irq.list); + + mutex_lock(&crtc->crtc_lock); ret = node->func(crtc_drm, true, &node->irq); + if (!ret) { + spin_lock_irqsave(&crtc->spin_lock, flags); + list_add_tail(&node->list, &crtc->user_event_list); + add_event = true; + spin_unlock_irqrestore(&crtc->spin_lock, flags); + } + mutex_unlock(&crtc->crtc_lock); + sde_power_resource_enable(&priv->phandle, kms->core_client, false); } + if (add_event) + return 0; + if (!ret) { spin_lock_irqsave(&crtc->spin_lock, flags); list_add_tail(&node->list, &crtc->user_event_list); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 99177b1117455adec749e17c4c492b6abdad0188..709a51f15618c1dc11ce2374626b71a81882979d 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -58,6 +58,18 @@ enum sde_crtc_output_capture_point { CAPTURE_DSPP_OUT }; +/** + * enum sde_crtc_idle_pc_state: states of idle power collapse + * @IDLE_PC_NONE: no-op + * @IDLE_PC_ENABLE: enable idle power-collapse + * @IDLE_PC_DISABLE: disable idle power-collapse + */ +enum sde_crtc_idle_pc_state { + IDLE_PC_NONE, + IDLE_PC_ENABLE, + IDLE_PC_DISABLE, +}; + /** * @connectors : Currently associated drm connectors for retire event * @num_connectors: Number of associated drm connectors for retire event diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 73864b617cc4e514cffc79a992994070fb364056..763993c89d7601a3e1fb25ddc54c4822c8cdc6da 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -200,7 +200,8 @@ enum sde_enc_rc_states { * @disp_info: local copy of msm_display_info struct * @misr_enable: misr enable/disable status * @misr_frame_count: misr frame count before start capturing the data - * @idle_pc_supported: indicate if idle power collaps is supported + * @idle_pc_enabled: indicate if idle power collapse is enabled + * currently. This can be controlled by user-mode * @rc_lock: resource control mutex lock to protect * virt encoder over various state changes * @rc_state: resource controller state @@ -250,7 +251,7 @@ struct sde_encoder_virt { bool misr_enable; u32 misr_frame_count; - bool idle_pc_supported; + bool idle_pc_enabled; struct mutex rc_lock; enum sde_enc_rc_states rc_state; struct kthread_delayed_work delayed_off_work; @@ -265,6 +266,8 @@ struct sde_encoder_virt { struct sde_rect cur_conn_roi; struct sde_rect prv_conn_roi; struct drm_crtc *crtc; + + bool elevated_ahb_vote; }; #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) @@ -1849,6 +1852,7 @@ static int _sde_encoder_resource_control_helper(struct drm_encoder *drm_enc, return rc; } + sde_enc->elevated_ahb_vote = true; /* enable DSI clks */ rc = sde_connector_clk_ctrl(sde_enc->cur_master->connector, true); @@ -1922,6 +1926,25 @@ static void sde_encoder_input_event_handler(struct input_handle *handle, &sde_enc->input_event_work); } +void sde_encoder_control_idle_pc(struct drm_encoder *drm_enc, bool enable) +{ + struct sde_encoder_virt *sde_enc; + + if (!drm_enc) { + SDE_ERROR("invalid encoder\n"); + return; + } + sde_enc = to_sde_encoder_virt(drm_enc); + + /* return early if there is no state change */ + if (sde_enc->idle_pc_enabled == enable) + return; + + sde_enc->idle_pc_enabled = enable; + + SDE_DEBUG("idle-pc state:%d\n", sde_enc->idle_pc_enabled); + SDE_EVT32(sde_enc->idle_pc_enabled); +} static int sde_encoder_resource_control(struct drm_encoder *drm_enc, u32 sw_event) @@ -1948,7 +1971,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, * when idle_pc is not supported, process only KICKOFF, STOP and MODESET * events and return early for other events (ie wb display). */ - if (!sde_enc->idle_pc_supported && + if (!sde_enc->idle_pc_enabled && (sw_event != SDE_ENC_RC_EVENT_KICKOFF && sw_event != SDE_ENC_RC_EVENT_PRE_MODESET && sw_event != SDE_ENC_RC_EVENT_POST_MODESET && @@ -1956,9 +1979,9 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, sw_event != SDE_ENC_RC_EVENT_PRE_STOP)) return 0; - SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc_supported:%d\n", sw_event, - sde_enc->idle_pc_supported); - SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported, + SDE_DEBUG_ENC(sde_enc, "sw_event:%d, idle_pc:%d\n", + sw_event, sde_enc->idle_pc_enabled); + SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_enabled, sde_enc->rc_state, SDE_EVTLOG_FUNC_ENTRY); switch (sw_event) { @@ -2348,7 +2371,7 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, break; } - SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_supported, + SDE_EVT32_VERBOSE(DRMID(drm_enc), sw_event, sde_enc->idle_pc_enabled, sde_enc->rc_state, SDE_EVTLOG_FUNC_EXIT); return 0; } @@ -2689,14 +2712,12 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) struct msm_compression_info *comp_info = NULL; struct drm_display_mode *cur_mode = NULL; struct msm_mode_info mode_info; - struct msm_display_info *disp_info; if (!drm_enc) { SDE_ERROR("invalid encoder\n"); return; } sde_enc = to_sde_encoder_virt(drm_enc); - disp_info = &sde_enc->disp_info; if (!sde_kms_power_resource_is_enabled(drm_enc->dev)) { SDE_ERROR("power resource is not enabled\n"); @@ -2817,14 +2838,14 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) SDE_EVT32(DRMID(drm_enc)); + if (sde_enc->input_handler) + input_unregister_handler(sde_enc->input_handler); + /* wait for idle */ sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); kthread_flush_work(&sde_enc->input_event_work); - if (sde_enc->input_handler) - input_unregister_handler(sde_enc->input_handler); - /* * For primary command mode encoders, execute the resource control * pre-stop operations before the physical encoders are disabled, to @@ -3298,6 +3319,8 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) struct sde_hw_ctl *ctl; uint32_t i, pending_flush; unsigned long lock_flags; + struct msm_drm_private *priv = NULL; + struct sde_kms *sde_kms = NULL; if (!sde_enc) { SDE_ERROR("invalid encoder\n"); @@ -3375,6 +3398,20 @@ static void _sde_encoder_kickoff_phys(struct sde_encoder_virt *sde_enc) _sde_encoder_trigger_start(sde_enc->cur_master); spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); + + if (sde_enc->elevated_ahb_vote) { + priv = sde_enc->base.dev->dev_private; + if (priv != NULL) { + sde_kms = to_sde_kms(priv->kms); + if (sde_kms != NULL) { + sde_power_scale_reg_bus(&priv->phandle, + sde_kms->core_client, + VOTE_INDEX_LOW, + false); + } + } + sde_enc->elevated_ahb_vote = false; + } } static void _sde_encoder_ppsplit_swap_intf_for_right_only_update( @@ -4483,7 +4520,7 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, if ((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) || (disp_info->capabilities & MSM_DISPLAY_CAP_VID_MODE)) - sde_enc->idle_pc_supported = sde_kms->catalog->has_idle_pc; + sde_enc->idle_pc_enabled = sde_kms->catalog->has_idle_pc; mutex_lock(&sde_enc->enc_lock); for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 42b9e5880e05154faadb6f06cdb98acad0d65a22..c40db41adecf1db32547587fe9b8e93ed6b2454a 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -257,4 +257,11 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc); */ int sde_encoder_in_clone_mode(struct drm_encoder *enc); +/** + * sde_encoder_control_idle_pc - control enable/disable of idle power collapse + * @drm_enc: Pointer to drm encoder structure + * @enable: enable/disable flag + */ +void sde_encoder_control_idle_pc(struct drm_encoder *enc, bool enable); + #endif /* __SDE_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index d363d62746f09d05e940083ca9a0005ab30c07b2..74bf5187bd89871a07b30f1ef91ab7a172863159 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -40,6 +40,20 @@ #define POLL_TIME_USEC_FOR_LN_CNT 500 #define MAX_POLL_CNT 10 +static bool _sde_encoder_phys_is_ppsplit(struct sde_encoder_phys *phys_enc) +{ + enum sde_rm_topology_name topology; + + if (!phys_enc) + return false; + + topology = sde_connector_get_topology_name(phys_enc->connector); + if (topology == SDE_RM_TOPOLOGY_PPSPLIT) + return true; + + return false; +} + static bool sde_encoder_phys_vid_is_master( struct sde_encoder_phys *phys_enc) { @@ -313,12 +327,14 @@ static void programmable_rot_fetch_config(struct sde_encoder_phys *phys_enc, if (!phys_enc->sde_kms->splash_data.cont_splash_en) { SDE_EVT32(DRMID(phys_enc->parent), f.enable, f.fetch_start); - phys_enc->hw_ctl->ops.get_bitmask_intf( - phys_enc->hw_ctl, &flush_mask, - vid_enc->hw_intf->idx); - phys_enc->hw_ctl->ops.update_pending_flush( - phys_enc->hw_ctl, flush_mask); - + if (!_sde_encoder_phys_is_ppsplit(phys_enc) || + sde_encoder_phys_vid_is_master(phys_enc)) { + phys_enc->hw_ctl->ops.get_bitmask_intf( + phys_enc->hw_ctl, &flush_mask, + vid_enc->hw_intf->idx); + phys_enc->hw_ctl->ops.update_pending_flush( + phys_enc->hw_ctl, flush_mask); + } spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags); vid_enc->hw_intf->ops.setup_rot_start(vid_enc->hw_intf, &f); spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags); @@ -496,20 +512,6 @@ static void sde_encoder_phys_vid_underrun_irq(void *arg, int irq_idx) phys_enc); } -static bool _sde_encoder_phys_is_ppsplit(struct sde_encoder_phys *phys_enc) -{ - enum sde_rm_topology_name topology; - - if (!phys_enc) - return false; - - topology = sde_connector_get_topology_name(phys_enc->connector); - if (topology == SDE_RM_TOPOLOGY_PPSPLIT) - return true; - - return false; -} - static bool _sde_encoder_phys_is_dual_ctl(struct sde_encoder_phys *phys_enc) { enum sde_rm_topology_name topology; 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 82dd64abe66ce3440c4a6faeeabca2a38f3382c7..4bbcb3ae567ce1097be3ddea6472c42da7610690 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -32,7 +32,6 @@ #define TO_S15D16(_x_) ((_x_) << 7) -#define MULTIPLE_CONN_DETECTED(x) (x > 1) /** * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix * @@ -453,11 +452,9 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc) static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, struct drm_crtc_state *crtc_state) { - struct drm_connector *conn; - struct drm_connector_state *conn_state; + struct drm_encoder *encoder; struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); const struct sde_wb_cfg *wb_cfg = wb_enc->hw_wb->caps; - int conn_count = 0; phys_enc->in_clone_mode = false; @@ -465,21 +462,16 @@ static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, if (!(wb_cfg->features & BIT(SDE_WB_HAS_CWB))) return; - /* Count the number of connectors on the given crtc */ - drm_for_each_connector(conn, crtc_state->crtc->dev) { - conn_state = - drm_atomic_get_connector_state(crtc_state->state, conn); - if ((conn->state && conn->state->crtc == crtc_state->crtc) || - (conn_state && - conn_state->crtc == crtc_state->crtc)) - conn_count++; + /* if any other encoder is connected to same crtc enable clone mode*/ + drm_for_each_encoder(encoder, crtc_state->crtc->dev) { + if (encoder->crtc != crtc_state->crtc) + continue; + if (phys_enc->parent != encoder) { + phys_enc->in_clone_mode = true; + break; + } } - - /* Enable clone mode If crtc has multiple connectors & one is WB */ - if (MULTIPLE_CONN_DETECTED(conn_count)) - phys_enc->in_clone_mode = true; - SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode); } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 9a4c7857d023ee3ae9cf729eee1c077a372ce2f8..ed0e7b818da7db3b1d319ac3c7f98af0a4fbfd9f 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -926,6 +926,12 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, return; } + if (sde_kms->first_kickoff) { + sde_power_scale_reg_bus(&priv->phandle, sde_kms->core_client, + VOTE_INDEX_HIGH, false); + sde_kms->first_kickoff = false; + } + for_each_crtc_in_state(state, crtc, crtc_state, i) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -2658,7 +2664,15 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms) SDE_DEBUG("info.is_connected = %s, info.is_primary = %s\n", ((info.is_connected) ? "true" : "false"), ((info.is_primary) ? "true" : "false")); - break; + + /** + * Since we are supporting one DSI for splash, use the display + * which is marked as primary. + */ + if (!info.is_primary) + continue; + else + break; } if (!encoder) { @@ -3083,8 +3097,10 @@ static void sde_kms_handle_power_event(u32 event_type, void *usr) if (event_type == SDE_POWER_EVENT_POST_ENABLE) { sde_irq_update(msm_kms, true); sde_vbif_init_memtypes(sde_kms); + sde_kms->first_kickoff = true; } else if (event_type == SDE_POWER_EVENT_PRE_DISABLE) { sde_irq_update(msm_kms, false); + sde_kms->first_kickoff = false; } } diff --git a/drivers/gpu/drm/msm/sde/sde_kms.h b/drivers/gpu/drm/msm/sde/sde_kms.h index 450695dd4ce38ae800044734759fc7668608b2d1..fb79fe79436b66cbd35168ef6d8d6bdccd65d39f 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.h +++ b/drivers/gpu/drm/msm/sde/sde_kms.h @@ -288,6 +288,8 @@ struct sde_kms { atomic_t detach_sec_cb; atomic_t detach_all_cb; struct mutex secure_transition_lock; + + bool first_kickoff; }; struct vsync_info { @@ -374,7 +376,8 @@ static inline bool sde_kms_is_secure_session_inprogress(struct sde_kms *sde_kms) return false; mutex_lock(&sde_kms->secure_transition_lock); - if (sde_kms->smmu_state.state == DETACHED) + if ((sde_kms->smmu_state.state == DETACHED) + || (sde_kms->smmu_state.state == DETACH_ALL_REQ)) ret = true; mutex_unlock(&sde_kms->secure_transition_lock); diff --git a/drivers/gpu/drm/msm/sde_io_util.c b/drivers/gpu/drm/msm/sde_io_util.c index d5a438e5f26cd6f599f790b010319cce921a125f..f8300109b6fd40cc2966735057ed41a843f7b0f5 100644 --- a/drivers/gpu/drm/msm/sde_io_util.c +++ b/drivers/gpu/drm/msm/sde_io_util.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2017, 2018, The Linux Foundation. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -230,7 +231,7 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) need_sleep = !regulator_is_enabled(in_vreg[i].vreg); if (in_vreg[i].pre_on_sleep && need_sleep) usleep_range(in_vreg[i].pre_on_sleep * 1000, - in_vreg[i].pre_on_sleep * 1000); + (in_vreg[i].pre_on_sleep * 1000) + 10); rc = regulator_set_load(in_vreg[i].vreg, in_vreg[i].enable_load); if (rc < 0) { @@ -242,7 +243,7 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) rc = regulator_enable(in_vreg[i].vreg); if (in_vreg[i].post_on_sleep && need_sleep) usleep_range(in_vreg[i].post_on_sleep * 1000, - in_vreg[i].post_on_sleep * 1000); + (in_vreg[i].post_on_sleep * 1000) + 10); if (rc < 0) { DEV_ERR("%pS->%s: %s enable failed\n", __builtin_return_address(0), __func__, @@ -254,13 +255,13 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) for (i = num_vreg-1; i >= 0; i--) { if (in_vreg[i].pre_off_sleep) usleep_range(in_vreg[i].pre_off_sleep * 1000, - in_vreg[i].pre_off_sleep * 1000); + (in_vreg[i].pre_off_sleep * 1000) + 10); regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); regulator_disable(in_vreg[i].vreg); if (in_vreg[i].post_off_sleep) usleep_range(in_vreg[i].post_off_sleep * 1000, - in_vreg[i].post_off_sleep * 1000); + (in_vreg[i].post_off_sleep * 1000) + 10); } } return rc; @@ -272,13 +273,13 @@ int msm_dss_enable_vreg(struct dss_vreg *in_vreg, int num_vreg, int enable) for (i--; i >= 0; i--) { if (in_vreg[i].pre_off_sleep) usleep_range(in_vreg[i].pre_off_sleep * 1000, - in_vreg[i].pre_off_sleep * 1000); + (in_vreg[i].pre_off_sleep * 1000) + 10); regulator_set_load(in_vreg[i].vreg, in_vreg[i].disable_load); regulator_disable(in_vreg[i].vreg); if (in_vreg[i].post_off_sleep) usleep_range(in_vreg[i].post_off_sleep * 1000, - in_vreg[i].post_off_sleep * 1000); + (in_vreg[i].post_off_sleep * 1000) + 10); } return rc; diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 67ea2ce03a23f1e4feb0c36ed1fd40ac31d7394f..39d0fdcb17d2f021470ebd49d557fac583c76941 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -136,7 +136,10 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y, if (cmd > (char *) urb->transfer_buffer) { /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; + int len; + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ = 0xAF; + len = cmd - (char *) urb->transfer_buffer; ret = udl_submit_urb(dev, urb, len); bytes_sent += len; } else diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c index 917dcb978c2ccc921c1dfcf90329973ff3044b59..9259a2f8bf3a7958c6bb1849ddfcbcf8ba9bbe54 100644 --- a/drivers/gpu/drm/udl/udl_transfer.c +++ b/drivers/gpu/drm/udl/udl_transfer.c @@ -152,11 +152,11 @@ static void udl_compress_hline16( raw_pixels_count_byte = cmd++; /* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + (min(MAX_CMD_PIXELS + 1, - min((int)(pixel_end - pixel) / bpp, - (int)(cmd_buffer_end - cmd) / 2))) * bpp; + cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, + (unsigned long)(pixel_end - pixel) / bpp, + (unsigned long)(cmd_buffer_end - 1 - cmd) / 2) * bpp; - prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp); + prefetch_range((void *) pixel, cmd_pixel_end - pixel); pixel_val16 = get_pixel_val16(pixel, bpp); while (pixel < cmd_pixel_end) { @@ -192,6 +192,9 @@ static void udl_compress_hline16( if (pixel > raw_pixel_start) { /* finalize last RAW span */ *raw_pixels_count_byte = ((pixel-raw_pixel_start) / bpp) & 0xFF; + } else { + /* undo unused byte */ + cmd--; } *cmd_pixels_count_byte = ((pixel - cmd_pixel_start) / bpp) & 0xFF; diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 757f9d736d6a2c3fd75a9ecbe4b828cf8cb98afa..2585a27452bc656b6ca0f3d08958c77b3f692b9d 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -294,11 +294,11 @@ void adreno_efuse_speed_bin_array(struct adreno_device *adreno_dev) */ count = of_property_count_u32_elems(device->pdev->dev.of_node, "qcom,gpu-speed-bin-vectors"); - if (count <= 0) + + if ((count <= 0) || (count % vector_size)) return; - bin_vector = kmalloc(sizeof(count * sizeof(unsigned int)), - GFP_KERNEL); + bin_vector = kmalloc_array(count, sizeof(unsigned int), GFP_KERNEL); if (bin_vector == NULL) { KGSL_DRV_ERR(device, "Unable to allocate memory for speed-bin vector\n"); @@ -3424,6 +3424,47 @@ static int adreno_readtimestamp(struct kgsl_device *device, return status; } +/** + * adreno_device_private_create(): Allocate an adreno_device_private structure + */ +static struct kgsl_device_private *adreno_device_private_create(void) +{ + struct adreno_device_private *adreno_priv = + kzalloc(sizeof(*adreno_priv), GFP_KERNEL); + + if (adreno_priv) { + INIT_LIST_HEAD(&adreno_priv->perfcounter_list); + return &adreno_priv->dev_priv; + } + return NULL; +} + +/** + * adreno_device_private_destroy(): Destroy an adreno_device_private structure + * and release the perfcounters held by the kgsl fd. + * @dev_priv: The kgsl device private structure + */ +static void adreno_device_private_destroy(struct kgsl_device_private *dev_priv) +{ + struct kgsl_device *device = dev_priv->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct adreno_device_private *adreno_priv = + container_of(dev_priv, struct adreno_device_private, + dev_priv); + struct adreno_perfcounter_list_node *p, *tmp; + + mutex_lock(&device->mutex); + list_for_each_entry_safe(p, tmp, &adreno_priv->perfcounter_list, node) { + adreno_perfcounter_put(adreno_dev, p->groupid, + p->countable, PERFCOUNTER_FLAG_NONE); + list_del(&p->node); + kfree(p); + } + mutex_unlock(&device->mutex); + + kfree(adreno_priv); +} + static inline s64 adreno_ticks_to_us(u32 ticks, u32 freq) { freq /= 1000000; @@ -3705,6 +3746,8 @@ static const struct kgsl_functable adreno_functable = { .snapshot = adreno_snapshot, .irq_handler = adreno_irq_handler, .drain = adreno_drain, + .device_private_create = adreno_device_private_create, + .device_private_destroy = adreno_device_private_destroy, /* Optional functions */ .snapshot_gmu = adreno_snapshot_gmu, .drawctxt_create = adreno_drawctxt_create, diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index fbf298d8749b07507160eed65250486abcd92e5b..fc32fb9cf58a6267af58a69a2310c02a4d0e4901 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -326,6 +326,29 @@ struct adreno_firmware { struct kgsl_memdesc memdesc; }; +/** + * struct adreno_perfcounter_list_node - struct to store perfcounters + * allocated by a process on a kgsl fd. + * @groupid: groupid of the allocated perfcounter + * @countable: countable assigned to the allocated perfcounter + * @node: list node for perfcounter_list of a process + */ +struct adreno_perfcounter_list_node { + unsigned int groupid; + unsigned int countable; + struct list_head node; +}; + +/** + * struct adreno_device_private - Adreno private structure per fd + * @dev_priv: the kgsl device private structure + * @perfcounter_list: list of perfcounters used by the process + */ +struct adreno_device_private { + struct kgsl_device_private dev_priv; + struct list_head perfcounter_list; +}; + /** * struct adreno_gpu_core - A specific GPU core definition * @gpurev: Unique GPU revision identifier diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c index aa8c2bf76d414039391a79215a00bf2097dfd853..82629c6fcf235f85d40dde88e1122c60214d41f8 100644 --- a/drivers/gpu/msm/adreno_ioctl.c +++ b/drivers/gpu/msm/adreno_ioctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2002,2007-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 @@ -16,6 +16,50 @@ #include "adreno.h" #include "adreno_a5xx.h" +/* + * Add a perfcounter to the per-fd list. + * Call with the device mutex held + */ +static int adreno_process_perfcounter_add(struct kgsl_device_private *dev_priv, + unsigned int groupid, unsigned int countable) +{ + struct adreno_device_private *adreno_priv = container_of(dev_priv, + struct adreno_device_private, dev_priv); + struct adreno_perfcounter_list_node *perfctr; + + perfctr = kmalloc(sizeof(*perfctr), GFP_KERNEL); + if (!perfctr) + return -ENOMEM; + + perfctr->groupid = groupid; + perfctr->countable = countable; + + /* add the pair to process perfcounter list */ + list_add(&perfctr->node, &adreno_priv->perfcounter_list); + return 0; +} + +/* + * Remove a perfcounter from the per-fd list. + * Call with the device mutex held + */ +static int adreno_process_perfcounter_del(struct kgsl_device_private *dev_priv, + unsigned int groupid, unsigned int countable) +{ + struct adreno_device_private *adreno_priv = container_of(dev_priv, + struct adreno_device_private, dev_priv); + struct adreno_perfcounter_list_node *p; + + list_for_each_entry(p, &adreno_priv->perfcounter_list, node) { + if (p->groupid == groupid && p->countable == countable) { + list_del(&p->node); + kfree(p); + return 0; + } + } + return -ENODEV; +} + long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv, unsigned int cmd, void *data) { @@ -42,6 +86,15 @@ long adreno_ioctl_perfcounter_get(struct kgsl_device_private *dev_priv, get->groupid, get->countable, &get->offset, &get->offset_hi, PERFCOUNTER_FLAG_NONE); + /* Add the perfcounter into the list */ + if (!result) { + result = adreno_process_perfcounter_add(dev_priv, get->groupid, + get->countable); + if (result) + adreno_perfcounter_put(adreno_dev, get->groupid, + get->countable, PERFCOUNTER_FLAG_NONE); + } + adreno_perfcntr_active_oob_put(adreno_dev); mutex_unlock(&device->mutex); @@ -58,8 +111,15 @@ long adreno_ioctl_perfcounter_put(struct kgsl_device_private *dev_priv, int result; mutex_lock(&device->mutex); - result = adreno_perfcounter_put(adreno_dev, put->groupid, - put->countable, PERFCOUNTER_FLAG_NONE); + + /* Delete the perfcounter from the process list */ + result = adreno_process_perfcounter_del(dev_priv, put->groupid, + put->countable); + + /* Put the perfcounter refcount */ + if (!result) + adreno_perfcounter_put(adreno_dev, put->groupid, + put->countable, PERFCOUNTER_FLAG_NONE); mutex_unlock(&device->mutex); return (long) result; diff --git a/drivers/gpu/msm/adreno_snapshot.c b/drivers/gpu/msm/adreno_snapshot.c index b5999e6fb6a255976c7e0d3c7af74ee726278ecc..22939199c28ca00216a87fb1e9cfa3e8a6840cb9 100644 --- a/drivers/gpu/msm/adreno_snapshot.c +++ b/drivers/gpu/msm/adreno_snapshot.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -400,6 +400,8 @@ static void snapshot_rb_ibs(struct kgsl_device *device, ibsize = rbptr[index + 3]; } + index = (index + 1) % KGSL_RB_DWORDS; + /* Don't parse known global IBs */ if (iommu_is_setstate_addr(device, ibaddr, ibsize)) continue; @@ -410,9 +412,8 @@ static void snapshot_rb_ibs(struct kgsl_device *device, parse_ib(device, snapshot, snapshot->process, ibaddr, ibsize); - } - - index = (index + 1) % KGSL_RB_DWORDS; + } else + index = (index + 1) % KGSL_RB_DWORDS; } } diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 3b55fc6f74edbacd084c3bdd8bf9df18ce284bb1..572dc406e15da10b2ac647c7a02e238fae8f6f63 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -764,7 +764,7 @@ static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state) mutex_lock(&device->mutex); status = kgsl_pwrctrl_change_state(device, KGSL_STATE_SUSPEND); - if (status == 0) + if (status == 0 && device->state == KGSL_STATE_SUSPEND) device->ftbl->dispatcher_halt(device); mutex_unlock(&device->mutex); @@ -1119,7 +1119,8 @@ static int kgsl_release(struct inode *inodep, struct file *filep) /* Close down the process wide resources for the file */ kgsl_process_private_close(dev_priv, dev_priv->process_priv); - kfree(dev_priv); + /* Destroy the device-specific structure */ + device->ftbl->device_private_destroy(dev_priv); result = kgsl_close_device(device); pm_runtime_put(&device->pdev->dev); @@ -1187,7 +1188,7 @@ static int kgsl_open(struct inode *inodep, struct file *filep) } result = 0; - dev_priv = kzalloc(sizeof(struct kgsl_device_private), GFP_KERNEL); + dev_priv = device->ftbl->device_private_create(); if (dev_priv == NULL) { result = -ENOMEM; goto err; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index c8c6456343e5d4c752523e275110b162d16fd8e1..4a98a240810a6a1713b593218a89518df6b3fd71 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -156,6 +156,8 @@ struct kgsl_functable { struct kgsl_snapshot *snapshot); irqreturn_t (*irq_handler)(struct kgsl_device *device); int (*drain)(struct kgsl_device *device); + struct kgsl_device_private * (*device_private_create)(void); + void (*device_private_destroy)(struct kgsl_device_private *dev_priv); /* * Optional functions - these functions are not mandatory. The * driver will check that the function pointer is not NULL before diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c index acfb522a432ae51ff16d0a475783eed167969d7c..29423691c10515038ef3cc76ca1f72386af1f320 100644 --- a/drivers/hid/hid-debug.c +++ b/drivers/hid/hid-debug.c @@ -1152,6 +1152,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, goto out; if (list->tail > list->head) { len = list->tail - list->head; + if (len > count) + len = count; if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1161,6 +1163,8 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, list->head += len; } else { len = HID_DEBUG_BUFSIZE - list->head; + if (len > count) + len = count; if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) { ret = -EFAULT; @@ -1168,7 +1172,9 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer, } list->head = 0; ret += len; - goto copy_rest; + count -= len; + if (count > 0) + goto copy_rest; } } diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 2548c5dbdc75ff558f96b04dcc99e5c109002ca3..00bce002b3571f4cdad73bf09d1f393ded605ed5 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -477,7 +477,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) return; } - if ((ret_size > size) || (ret_size <= 2)) { + if ((ret_size > size) || (ret_size < 2)) { dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", __func__, size, ret_size); return; diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 20d647d2dd2cbfa5fb57fbc85de236147cf448ab..00aafe032e58c3e5bbcdaf26b7a118c5d5c340d4 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -202,8 +202,7 @@ static void ish_remove(struct pci_dev *pdev) kfree(ishtp_dev); } -#ifdef CONFIG_PM -static struct device *ish_resume_device; +static struct device __maybe_unused *ish_resume_device; /** * ish_resume_handler() - Work function to complete resume @@ -214,7 +213,7 @@ static struct device *ish_resume_device; * in that case a simple resume message is enough, others we need * a reset sequence. */ -static void ish_resume_handler(struct work_struct *work) +static void __maybe_unused ish_resume_handler(struct work_struct *work) { struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -245,7 +244,7 @@ static void ish_resume_handler(struct work_struct *work) * * Return: 0 to the pm core */ -static int ish_suspend(struct device *device) +static int __maybe_unused ish_suspend(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -271,7 +270,7 @@ static int ish_suspend(struct device *device) return 0; } -static DECLARE_WORK(resume_work, ish_resume_handler); +static __maybe_unused DECLARE_WORK(resume_work, ish_resume_handler); /** * ish_resume() - ISH resume callback * @device: device pointer @@ -280,7 +279,7 @@ static DECLARE_WORK(resume_work, ish_resume_handler); * * Return: 0 to the pm core */ -static int ish_resume(struct device *device) +static int __maybe_unused ish_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ishtp_device *dev = pci_get_drvdata(pdev); @@ -294,21 +293,14 @@ static int ish_resume(struct device *device) return 0; } -static const struct dev_pm_ops ish_pm_ops = { - .suspend = ish_suspend, - .resume = ish_resume, -}; -#define ISHTP_ISH_PM_OPS (&ish_pm_ops) -#else -#define ISHTP_ISH_PM_OPS NULL -#endif /* CONFIG_PM */ +static SIMPLE_DEV_PM_OPS(ish_pm_ops, ish_suspend, ish_resume); static struct pci_driver ish_driver = { .name = KBUILD_MODNAME, .id_table = ish_pci_tbl, .probe = ish_probe, .remove = ish_remove, - .driver.pm = ISHTP_ISH_PM_OPS, + .driver.pm = &ish_pm_ops, }; module_pci_driver(ish_driver); diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 700145b1508894f30a018aef278d15cfc458ef3a..b59b15d4caa9638dd3a601442af4bfe71bf8f736 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS @@ -478,10 +479,14 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, if (uref->field_index >= report->maxfield) goto inval; + uref->field_index = array_index_nospec(uref->field_index, + report->maxfield); field = report->field[uref->field_index]; if (uref->usage_index >= field->maxusage) goto inval; + uref->usage_index = array_index_nospec(uref->usage_index, + field->maxusage); uref->usage_code = field->usage[uref->usage_index].hid; @@ -508,6 +513,8 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, if (uref->field_index >= report->maxfield) goto inval; + uref->field_index = array_index_nospec(uref->field_index, + report->maxfield); field = report->field[uref->field_index]; @@ -761,6 +768,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (finfo.field_index >= report->maxfield) break; + finfo.field_index = array_index_nospec(finfo.field_index, + report->maxfield); field = report->field[finfo.field_index]; memset(&finfo, 0, sizeof(finfo)); @@ -801,6 +810,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (cinfo.index >= hid->maxcollection) break; + cinfo.index = array_index_nospec(cinfo.index, + hid->maxcollection); cinfo.type = hid->collection[cinfo.index].type; cinfo.usage = hid->collection[cinfo.index].usage; diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c index 1ed92d62ebef4d0f09c66c37c51f3824d8076990..53996708a1e3f63e42edf7f0522e435b1d2e3794 100644 --- a/drivers/hwmon/qpnp-adc-voltage.c +++ b/drivers/hwmon/qpnp-adc-voltage.c @@ -139,9 +139,9 @@ #define QPNP_VADC_HC1_ADC_CH_SEL_CTL 0x44 #define QPNP_VADC_HC1_DELAY_CTL 0x45 #define QPNP_VADC_HC1_DELAY_CTL_MASK 0xf -#define QPNP_VADC_MC1_EN_CTL1 0x46 +#define QPNP_VADC_HC1_EN_CTL1 0x46 #define QPNP_VADC_HC1_ADC_EN BIT(7) -#define QPNP_VADC_MC1_CONV_REQ 0x47 +#define QPNP_VADC_HC1_CONV_REQ 0x47 #define QPNP_VADC_HC1_CONV_REQ_START BIT(7) #define QPNP_VADC_HC1_VBAT_MIN_THR0 0x48 @@ -421,6 +421,32 @@ static int qpnp_vadc_hc_read_data(struct qpnp_vadc_chip *vadc, int *data) return rc; } +static int qpnp_vadc_wait_for_eoc(struct qpnp_vadc_chip *vadc) +{ + int ret; + + if (vadc->vadc_poll_eoc) { + ret = qpnp_vadc_hc_check_conversion_status(vadc); + if (ret < 0) { + pr_err("polling mode conversion failed\n"); + return ret; + } + } else { + ret = wait_for_completion_timeout( + &vadc->adc->adc_rslt_completion, + QPNP_ADC_COMPLETION_TIMEOUT); + if (!ret) { + ret = qpnp_vadc_hc_check_conversion_status(vadc); + if (ret < 0) { + pr_err("interrupt mode conversion failed\n"); + return ret; + } + pr_debug("End of conversion status set\n"); + } + } + return ret; +} + static void qpnp_vadc_hc_update_adc_dig_param(struct qpnp_vadc_chip *vadc, struct qpnp_adc_amux_properties *amux_prop, u8 *data) { @@ -439,6 +465,78 @@ static void qpnp_vadc_hc_update_adc_dig_param(struct qpnp_vadc_chip *vadc, pr_debug("VADC_DIG_PARAM value:0x%x\n", *data); } +static int qpnp_vadc_hc_pre_configure_usb_in(struct qpnp_vadc_chip *vadc, + int dt_index) +{ + int rc = 0; + u8 buf; + u8 dig_param = 0; + struct qpnp_adc_amux_properties conv; + + /* Setup dig params for USB_IN_V */ + conv.decimation = DECIMATION_TYPE2; + conv.cal_val = ADC_HC_ABS_CAL; + conv.calib_type = vadc->adc->adc_channels[dt_index].calib_type; + + qpnp_vadc_hc_update_adc_dig_param(vadc, &conv, &dig_param); + + /* Increase calib interval and wait for other conversions to complete */ + buf = QPNP_VADC_CAL_DELAY_MEAS_SLOW; + rc = regmap_bulk_write(vadc->adc->regmap, + QPNP_VADC_CAL_DELAY_CTL_1, &buf, 1); + if (rc < 0) { + pr_err("qpnp adc write cal_delay failed with %d\n", rc); + return rc; + } + msleep(20); + + /* Read GND first */ + buf = VADC_VREF_GND; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_CH_SEL_CTL, &buf, 1); + if (rc < 0) + return rc; + + buf = QPNP_VADC_HC1_ADC_EN; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_EN_CTL1, &buf, 1); + if (rc < 0) + return rc; + + if (!vadc->vadc_poll_eoc) + reinit_completion(&vadc->adc->adc_rslt_completion); + + buf = QPNP_VADC_HC1_CONV_REQ_START; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_CONV_REQ, &buf, 1); + if (rc < 0) + return rc; + + /* Pre-configure USB_IN_V request */ + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_DIG_PARAM, + &dig_param, 1); + if (rc < 0) + return rc; + + buf = VADC_USB_IN_V_DIV_16_PM5; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_ADC_CH_SEL_CTL, &buf, 1); + if (rc < 0) + return rc; + + /* Wait for GND read to complete */ + rc = qpnp_vadc_wait_for_eoc(vadc); + if (rc < 0) + return rc; + + if (!vadc->vadc_poll_eoc) + reinit_completion(&vadc->adc->adc_rslt_completion); + + /* Start USB_IN_V read */ + buf = QPNP_VADC_HC1_CONV_REQ_START; + rc = qpnp_vadc_write_reg(vadc, QPNP_VADC_HC1_CONV_REQ, &buf, 1); + if (rc < 0) + return rc; + + return 0; +} + static int qpnp_vadc_hc_configure(struct qpnp_vadc_chip *vadc, struct qpnp_adc_amux_properties *amux_prop) { @@ -494,7 +592,7 @@ int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc, { int rc = 0, scale_type, amux_prescaling, dt_index = 0, calib_type = 0; u8 val = QPNP_VADC_CAL_DELAY_MEAS_SLOW; - struct qpnp_adc_amux_properties amux_prop, conv; + struct qpnp_adc_amux_properties amux_prop; if (qpnp_vadc_is_valid(vadc)) return -EPROBE_DEFER; @@ -532,69 +630,37 @@ int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc, if (channel == VADC_USB_IN_V_DIV_16_PM5 && vadc->adc->adc_prop->is_pmic_5) { - rc = regmap_bulk_write(vadc->adc->regmap, - QPNP_VADC_CAL_DELAY_CTL_1, &val, 1); + rc = qpnp_vadc_hc_pre_configure_usb_in(vadc, dt_index); if (rc < 0) { - pr_err("qpnp adc write cal_delay failed with %d\n", rc); - return rc; - } - msleep(20); - - conv.amux_channel = VADC_VREF_GND; - conv.decimation = DECIMATION_TYPE2; - conv.mode_sel = ADC_OP_NORMAL_MODE << QPNP_VADC_OP_MODE_SHIFT; - conv.hw_settle_time = ADC_CHANNEL_HW_SETTLE_DELAY_0US; - conv.fast_avg_setup = ADC_FAST_AVG_SAMPLE_1; - conv.cal_val = ADC_HC_ABS_CAL; - - rc = qpnp_vadc_hc_configure(vadc, &conv); - if (rc) { - pr_err("qpnp_vadc configure failed with %d\n", rc); + pr_err("Configuring VADC channel failed with %d\n", rc); goto fail_unlock; } - - } - - amux_prop.decimation = + } else { + amux_prop.decimation = vadc->adc->adc_channels[dt_index].adc_decimation; - amux_prop.calib_type = vadc->adc->adc_channels[dt_index].calib_type; - amux_prop.cal_val = vadc->adc->adc_channels[dt_index].cal_val; - amux_prop.fast_avg_setup = + amux_prop.calib_type = + vadc->adc->adc_channels[dt_index].calib_type; + amux_prop.cal_val = vadc->adc->adc_channels[dt_index].cal_val; + amux_prop.fast_avg_setup = vadc->adc->adc_channels[dt_index].fast_avg_setup; - amux_prop.amux_channel = channel; - amux_prop.hw_settle_time = + amux_prop.amux_channel = channel; + amux_prop.hw_settle_time = vadc->adc->adc_channels[dt_index].hw_settle_time; - rc = qpnp_vadc_hc_configure(vadc, &amux_prop); - if (rc < 0) { - pr_err("Configuring VADC channel failed with %d\n", rc); - goto fail_unlock; - } - - if (vadc->vadc_poll_eoc) { - rc = qpnp_vadc_hc_check_conversion_status(vadc); + rc = qpnp_vadc_hc_configure(vadc, &amux_prop); if (rc < 0) { - pr_err("polling mode conversion failed\n"); + pr_err("Configuring VADC channel failed with %d\n", rc); goto fail_unlock; } - } else { - rc = wait_for_completion_timeout( - &vadc->adc->adc_rslt_completion, - QPNP_ADC_COMPLETION_TIMEOUT); - if (!rc) { - rc = qpnp_vadc_hc_check_conversion_status(vadc); - if (rc < 0) { - pr_err("interrupt mode conversion failed\n"); - goto fail_unlock; - } - pr_debug("End of conversion status set\n"); - } } - val = QPNP_VADC_CAL_DELAY_MEAS_DEFAULT; + rc = qpnp_vadc_wait_for_eoc(vadc); + if (rc < 0) + goto fail_unlock; if (channel == VADC_USB_IN_V_DIV_16_PM5 && vadc->adc->adc_prop->is_pmic_5) { + val = QPNP_VADC_CAL_DELAY_MEAS_DEFAULT; rc = regmap_bulk_write(vadc->adc->regmap, QPNP_VADC_CAL_DELAY_CTL_1, &val, 1); if (rc < 0) { diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index b8e29925190cc15415843355f7fb6be8b19c1075..f2609221aec844c447441499ae69938939e5dd34 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "stm.h" #include @@ -689,7 +690,7 @@ static void stm_device_release(struct device *dev) { struct stm_device *stm = to_stm_device(dev); - kfree(stm); + vfree(stm); } int stm_register_device(struct device *parent, struct stm_data *stm_data, @@ -706,7 +707,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, return -EINVAL; nmasters = stm_data->sw_end - stm_data->sw_start + 1; - stm = kzalloc(sizeof(*stm) + nmasters * sizeof(void *), GFP_KERNEL); + stm = vzalloc(sizeof(*stm) + nmasters * sizeof(void *)); if (!stm) return -ENOMEM; @@ -759,7 +760,7 @@ int stm_register_device(struct device *parent, struct stm_data *stm_data, /* matches device_initialize() above */ put_device(&stm->dev); err_free: - kfree(stm); + vfree(stm); return err; } diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index c712866c8abf666a1c1aa5b9a7a8f78722c64527..abe1798c515e55263e1cd4ea690937f15aa52525 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -524,8 +524,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (msgs[i].flags & I2C_M_RD) { sg_init_table(&gi2c->rx_sg, 1); - geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, msgs[i].buf, - msgs[i].len, DMA_FROM_DEVICE); + ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, + msgs[i].buf, msgs[i].len, + DMA_FROM_DEVICE); + if (ret) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "geni_se_iommu_map_buf for rx failed :%d\n", + ret); + goto geni_i2c_gsi_xfer_out; + + } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); gi2c->rx_t.dword[1] = @@ -546,7 +554,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "prep_slave_sg for rx failed\n"); gi2c->err = -ENOMEM; - goto geni_i2c_gsi_xfer_out; + goto geni_i2c_err_prep_sg; } gi2c->rx_desc->callback = gi2c_gsi_rx_cb; gi2c->rx_desc->callback_param = &gi2c->rx_cb; @@ -555,8 +563,16 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { - geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, msgs[i].buf, - msgs[i].len, DMA_TO_DEVICE); + ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, + msgs[i].buf, msgs[i].len, + DMA_TO_DEVICE); + if (ret) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "geni_se_iommu_map_buf for tx failed :%d\n", + ret); + goto geni_i2c_gsi_xfer_out; + + } gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = @@ -578,7 +594,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "prep_slave_sg for tx failed\n"); gi2c->err = -ENOMEM; - goto geni_i2c_gsi_xfer_out; + goto geni_i2c_err_prep_sg; } gi2c->tx_desc->callback = gi2c_gsi_tx_cb; gi2c->tx_desc->callback_param = &gi2c->tx_cb; @@ -589,12 +605,6 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); - if (msgs[i].flags & I2C_M_RD) - geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, - msgs[i].len, DMA_FROM_DEVICE); - else - geni_se_iommu_unmap_buf(tx_dev, &gi2c->tx_ph, - msgs[i].len, DMA_TO_DEVICE); if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, @@ -602,12 +612,21 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], gi2c->xfer_timeout, gi2c->cur->len); gi2c->err = -ETIMEDOUT; } +geni_i2c_err_prep_sg: + if (msgs[i].flags & I2C_M_RD) + geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, + msgs[i].len, DMA_FROM_DEVICE); + else + geni_se_iommu_unmap_buf(tx_dev, &gi2c->tx_ph, + msgs[i].len, DMA_TO_DEVICE); + if (gi2c->err) { dmaengine_terminate_all(gi2c->tx_c); gi2c->cfg_sent = 0; goto geni_i2c_gsi_xfer_out; } } + geni_i2c_gsi_xfer_out: if (!ret && gi2c->err) ret = gi2c->err; diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 726615e54f2a5ea4addfea0afcf528a425548a7b..c7592fe30e6e1656b05c89d5564609dc24aaddec 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -700,6 +700,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, pm_runtime_get_sync(dev); + rcar_i2c_init(priv); + ret = rcar_i2c_bus_barrier(priv); if (ret < 0) goto out; @@ -857,8 +859,6 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (ret < 0) goto out_pm_put; - rcar_i2c_init(priv); - /* Don't suspend when multi-master to keep arbitration working */ if (of_property_read_bool(dev->of_node, "multi-master")) priv->flags |= ID_P_PM_BLOCKED; diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index c5b999f0c51943f4ba79c066702cad96536310d4..e44181f9eb367ca3c4b24c0ab88e7cee8603aa99 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -19,11 +19,18 @@ struct iio_kfifo { #define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer) static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, - int bytes_per_datum, int length) + size_t bytes_per_datum, unsigned int length) { if ((length == 0) || (bytes_per_datum == 0)) return -EINVAL; + /* + * Make sure we don't overflow an unsigned int after kfifo rounds up to + * the next power of 2. + */ + if (roundup_pow_of_two(length) > UINT_MAX / bytes_per_datum) + return -EINVAL; + return __kfifo_alloc((struct __kfifo *)&buf->kf, length, bytes_per_datum, GFP_KERNEL); } @@ -64,7 +71,7 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) return 0; } -static int iio_set_length_kfifo(struct iio_buffer *r, int length) +static int iio_set_length_kfifo(struct iio_buffer *r, unsigned int length) { /* Avoid an invalid state */ if (length < 2) diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c index 7dda14e334281318e68724679e4af8656e2861e7..15d52dc88213fd8e7a492cd22bb9713bae3cab89 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c @@ -31,6 +31,10 @@ #include "inv_icm20602_iio.h" #include + +static struct regulator *reg_ldo; +static struct inv_icm20602_state *st; + /* Attribute of icm20602 device init show */ static ssize_t inv_icm20602_init_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -379,24 +383,27 @@ static const struct iio_info icm20602_info = { .validate_trigger = inv_icm20602_validate_trigger, }; -static int icm20602_ldo_work(struct inv_icm20602_state *st, bool enable) +static int icm20602_ldo_work(bool enable) { int ret = 0; + if (reg_ldo == NULL) + return MPU_FAIL; + if (enable) { - ret = regulator_set_voltage(st->reg_ldo, + ret = regulator_set_voltage(reg_ldo, ICM20602_LDO_VTG_MIN_UV, ICM20602_LDO_VTG_MAX_UV); if (ret) pr_err("Failed to request LDO voltage.\n"); - ret = regulator_enable(st->reg_ldo); + ret = regulator_enable(reg_ldo); if (ret) pr_err("Failed to enable LDO %d\n", ret); } else { - ret = regulator_disable(st->reg_ldo); + ret = regulator_disable(reg_ldo); + regulator_set_load(reg_ldo, 0); if (ret) pr_err("Failed to disable LDO %d\n", ret); - regulator_set_load(st->reg_ldo, 0); } return MPU_SUCCESS; @@ -405,14 +412,13 @@ static int icm20602_ldo_work(struct inv_icm20602_state *st, bool enable) static int icm20602_init_regulators(struct inv_icm20602_state *st) { struct regulator *reg; - reg = regulator_get(&st->client->dev, "vdd-ldo"); if (IS_ERR_OR_NULL(reg)) { pr_err("Unable to get regulator for LDO\n"); return -MPU_FAIL; } - st->reg_ldo = reg; + reg_ldo = reg; return MPU_SUCCESS; } @@ -463,7 +469,6 @@ static int of_populate_icm20602_dt(struct inv_icm20602_state *st) static int inv_icm20602_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct inv_icm20602_state *st; struct iio_dev *indio_dev; int result = MPU_SUCCESS; @@ -505,7 +510,7 @@ static int inv_icm20602_probe(struct i2c_client *client, goto out_remove_trigger; } icm20602_init_regulators(st); - icm20602_ldo_work(st, true); + icm20602_ldo_work(true); result = inv_icm20602_probe_trigger(indio_dev); if (result) { @@ -549,20 +554,19 @@ static int inv_icm20602_remove(struct i2c_client *client) static int inv_icm20602_suspend(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct inv_icm20602_state *st = iio_priv(indio_dev); + icm20602_ldo_work(false); - icm20602_stop_fifo(st); - icm20602_ldo_work(st, false); return 0; } static int inv_icm20602_resume(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); - struct inv_icm20602_state *st = iio_priv(indio_dev); + int ret; + + ret = icm20602_ldo_work(true); + if (ret == MPU_FAIL) + return 0; - icm20602_ldo_work(st, true); icm20602_detect(st); icm20602_init_device(st); icm20602_start_fifo(st); diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h index b369ae4dc0ab3e6f3dba1a4b8e09f131d58a6f93..36f8e9c130f0500bc748953747bf20c5005d4939 100644 --- a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h @@ -41,8 +41,8 @@ #define INV20602_SMD_IRQ_TRIGGER 1 #endif -#define ICM20602_LDO_VTG_MIN_UV 3300000 -#define ICM20602_LDO_VTG_MAX_UV 3300000 +#define ICM20602_LDO_VTG_MIN_UV 1800000 +#define ICM20602_LDO_VTG_MAX_UV 1800000 #define INV_ICM20602_TIME_STAMP_TOR 5 #define ICM20602_PACKAGE_SIZE 14 @@ -220,7 +220,6 @@ struct inv_icm20602_state { struct struct_icm20602_data *data_push; enum inv_devices chip_type; int gpio; - struct regulator *reg_ldo; DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); }; diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index ae04826e82fc0982496f8b560c6465e6562f819c..a32dd851e712bfa56a2a6dec0c5cbdaeaea19bc1 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -437,7 +437,7 @@ static int __ib_cache_gid_get(struct ib_device *ib_dev, u8 port, int index, return -EINVAL; if (table->data_vec[index].props & GID_TABLE_ENTRY_INVALID) - return -EAGAIN; + return -EINVAL; memcpy(gid, &table->data_vec[index].gid, sizeof(*gid)); if (attr) { diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 148b313c647195204c01f2e06b102eaa16e1077c..d30b3b90862164b96082b3b78c768622afaf2779 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -6717,7 +6717,7 @@ static void rxe_kernel_unfreeze(struct hfi1_devdata *dd) for (i = 0; i < dd->n_krcv_queues; i++) { rcvmask = HFI1_RCVCTRL_CTXT_ENB; /* HFI1_RCVCTRL_TAILUPD_[ENB|DIS] needs to be set explicitly */ - rcvmask |= HFI1_CAP_KGET_MASK(dd->rcd[i]->flags, DMA_RTAIL) ? + rcvmask |= dd->rcd[i]->rcvhdrtail_kvaddr ? HFI1_RCVCTRL_TAILUPD_ENB : HFI1_RCVCTRL_TAILUPD_DIS; hfi1_rcvctrl(dd, rcvmask, i); } @@ -8211,7 +8211,7 @@ static inline int check_packet_present(struct hfi1_ctxtdata *rcd) u32 tail; int present; - if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) + if (!rcd->rcvhdrtail_kvaddr) present = (rcd->seq_cnt == rhf_rcv_seq(rhf_to_cpu(get_rhf_addr(rcd)))); else /* is RDMA rtail */ @@ -11550,7 +11550,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt) /* reset the tail and hdr addresses, and sequence count */ write_kctxt_csr(dd, ctxt, RCV_HDR_ADDR, rcd->rcvhdrq_dma); - if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) + if (rcd->rcvhdrtail_kvaddr) write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR, rcd->rcvhdrqtailaddr_dma); rcd->seq_cnt = 1; @@ -11630,7 +11630,7 @@ void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt) rcvctrl |= RCV_CTXT_CTRL_INTR_AVAIL_SMASK; if (op & HFI1_RCVCTRL_INTRAVAIL_DIS) rcvctrl &= ~RCV_CTXT_CTRL_INTR_AVAIL_SMASK; - if (op & HFI1_RCVCTRL_TAILUPD_ENB && rcd->rcvhdrqtailaddr_dma) + if ((op & HFI1_RCVCTRL_TAILUPD_ENB) && rcd->rcvhdrtail_kvaddr) rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK; if (op & HFI1_RCVCTRL_TAILUPD_DIS) { /* See comment on RcvCtxtCtrl.TailUpd above */ diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index bb729764a7992c2dc4291cbbafabc9f2f3aa16f8..d612f9d94083eaabb2bb3c5188e6dae1d038fdb1 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -609,7 +609,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) ret = -EINVAL; goto done; } - if (flags & VM_WRITE) { + if ((flags & VM_WRITE) || !uctxt->rcvhdrtail_kvaddr) { ret = -EPERM; goto done; } diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index a3279f3d2578fd57afc8c9bcd2c9b4f295a390b0..a79d9b340cfa932a2e46b958b8be4f8fe0876534 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1631,6 +1631,7 @@ struct cc_state *get_cc_state_protected(struct hfi1_pportdata *ppd) #define HFI1_HAS_SDMA_TIMEOUT 0x8 #define HFI1_HAS_SEND_DMA 0x10 /* Supports Send DMA */ #define HFI1_FORCED_FREEZE 0x80 /* driver forced freeze mode */ +#define HFI1_SHUTDOWN 0x100 /* device is shutting down */ /* IB dword length mask in PBC (lower 11 bits); same for all chips */ #define HFI1_PBC_LENGTH_MASK ((1 << 11) - 1) diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index ae1f90ddd4e898a202177ec474a7465c7a4f02a2..9dc8cf096e2ea56dc08503687814afc4d10f502d 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -857,6 +857,10 @@ static void shutdown_device(struct hfi1_devdata *dd) unsigned pidx; int i; + if (dd->flags & HFI1_SHUTDOWN) + return; + dd->flags |= HFI1_SHUTDOWN; + for (pidx = 0; pidx < dd->num_pports; ++pidx) { ppd = dd->pport + pidx; @@ -1168,6 +1172,7 @@ void hfi1_disable_after_error(struct hfi1_devdata *dd) static void remove_one(struct pci_dev *); static int init_one(struct pci_dev *, const struct pci_device_id *); +static void shutdown_one(struct pci_dev *); #define DRIVER_LOAD_MSG "Intel " DRIVER_NAME " loaded: " #define PFX DRIVER_NAME ": " @@ -1184,6 +1189,7 @@ static struct pci_driver hfi1_pci_driver = { .name = DRIVER_NAME, .probe = init_one, .remove = remove_one, + .shutdown = shutdown_one, .id_table = hfi1_pci_tbl, .err_handler = &hfi1_pci_err_handler, }; @@ -1590,6 +1596,13 @@ static void remove_one(struct pci_dev *pdev) postinit_cleanup(dd); } +static void shutdown_one(struct pci_dev *pdev) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + + shutdown_device(dd); +} + /** * hfi1_create_rcvhdrq - create a receive header queue * @dd: the hfi1_ib device @@ -1605,7 +1618,6 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) u64 reg; if (!rcd->rcvhdrq) { - dma_addr_t dma_hdrqtail; gfp_t gfp_flags; /* @@ -1628,13 +1640,13 @@ int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) goto bail; } - if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) { + if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL) || + HFI1_CAP_UGET_MASK(rcd->flags, DMA_RTAIL)) { rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent( - &dd->pcidev->dev, PAGE_SIZE, &dma_hdrqtail, - gfp_flags); + &dd->pcidev->dev, PAGE_SIZE, + &rcd->rcvhdrqtailaddr_dma, gfp_flags); if (!rcd->rcvhdrtail_kvaddr) goto bail_free; - rcd->rcvhdrqtailaddr_dma = dma_hdrqtail; } rcd->rcvhdrq_size = amt; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 18d309e40f1b9269ec5b38f5e180c129d85b5e81..d9323d7c479c3458f6d301c4b8fc3b91862191a9 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -1897,7 +1897,6 @@ static void mlx4_ib_sqp_comp_worker(struct work_struct *work) "buf:%lld\n", wc.wr_id); break; default: - BUG_ON(1); break; } } else { diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index fc62a7ded73446b2384bc847f82f2ad23d2b094e..a19ebb19952eac7f09760a62f91a6f37e18c965f 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -645,7 +645,7 @@ static int mlx5_poll_one(struct mlx5_ib_cq *cq, } static int poll_soft_wc(struct mlx5_ib_cq *cq, int num_entries, - struct ib_wc *wc) + struct ib_wc *wc, bool is_fatal_err) { struct mlx5_ib_dev *dev = to_mdev(cq->ibcq.device); struct mlx5_ib_wc *soft_wc, *next; @@ -658,6 +658,10 @@ static int poll_soft_wc(struct mlx5_ib_cq *cq, int num_entries, mlx5_ib_dbg(dev, "polled software generated completion on CQ 0x%x\n", cq->mcq.cqn); + if (unlikely(is_fatal_err)) { + soft_wc->wc.status = IB_WC_WR_FLUSH_ERR; + soft_wc->wc.vendor_err = MLX5_CQE_SYNDROME_WR_FLUSH_ERR; + } wc[npolled++] = soft_wc->wc; list_del(&soft_wc->list); kfree(soft_wc); @@ -678,12 +682,17 @@ int mlx5_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) spin_lock_irqsave(&cq->lock, flags); if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) { - mlx5_ib_poll_sw_comp(cq, num_entries, wc, &npolled); + /* make sure no soft wqe's are waiting */ + if (unlikely(!list_empty(&cq->wc_list))) + soft_polled = poll_soft_wc(cq, num_entries, wc, true); + + mlx5_ib_poll_sw_comp(cq, num_entries - soft_polled, + wc + soft_polled, &npolled); goto out; } if (unlikely(!list_empty(&cq->wc_list))) - soft_polled = poll_soft_wc(cq, num_entries, wc); + soft_polled = poll_soft_wc(cq, num_entries, wc, false); for (npolled = 0; npolled < num_entries - soft_polled; npolled++) { if (mlx5_poll_one(cq, &cur_qp, wc + soft_polled + npolled)) diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h index a3e21a25cea5b38c1723ebbafec21be0ea1c69fa..ef092cca092ea883e72692a908c548949263e029 100644 --- a/drivers/infiniband/hw/qib/qib.h +++ b/drivers/infiniband/hw/qib/qib.h @@ -1250,6 +1250,7 @@ static inline struct qib_ibport *to_iport(struct ib_device *ibdev, u8 port) #define QIB_BADINTR 0x8000 /* severe interrupt problems */ #define QIB_DCA_ENABLED 0x10000 /* Direct Cache Access enabled */ #define QIB_HAS_QSFP 0x20000 /* device (card instance) has QSFP */ +#define QIB_SHUTDOWN 0x40000 /* device is shutting down */ /* * values for ppd->lflags (_ib_port_ related flags) @@ -1448,8 +1449,7 @@ u64 qib_sps_ints(void); /* * dma_addr wrappers - all 0's invalid for hw */ -dma_addr_t qib_map_page(struct pci_dev *, struct page *, unsigned long, - size_t, int); +int qib_map_page(struct pci_dev *d, struct page *p, dma_addr_t *daddr); const char *qib_get_unit_name(int unit); const char *qib_get_card_name(struct rvt_dev_info *rdi); struct pci_dev *qib_get_pci_dev(struct rvt_dev_info *rdi); diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 382466a90da7331e4492fab59d60bf904db36df1..cc6a92316c7cc564dbe5b6f5ca8380cd72eb7280 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -364,6 +364,8 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp, goto done; } for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) { + dma_addr_t daddr; + for (; ntids--; tid++) { if (tid == tidcnt) tid = 0; @@ -380,12 +382,14 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp, ret = -ENOMEM; break; } + ret = qib_map_page(dd->pcidev, pagep[i], &daddr); + if (ret) + break; + tidlist[i] = tid + tidoff; /* we "know" system pages and TID pages are same size */ dd->pageshadow[ctxttid + tid] = pagep[i]; - dd->physshadow[ctxttid + tid] = - qib_map_page(dd->pcidev, pagep[i], 0, PAGE_SIZE, - PCI_DMA_FROMDEVICE); + dd->physshadow[ctxttid + tid] = daddr; /* * don't need atomic or it's overhead */ diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 1730aa839a471f1610d181927fd4210070d88096..caf7c5120b0afdd7308cb11513ac1e6e92b97ff8 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -878,6 +878,10 @@ static void qib_shutdown_device(struct qib_devdata *dd) struct qib_pportdata *ppd; unsigned pidx; + if (dd->flags & QIB_SHUTDOWN) + return; + dd->flags |= QIB_SHUTDOWN; + for (pidx = 0; pidx < dd->num_pports; ++pidx) { ppd = dd->pport + pidx; @@ -1223,6 +1227,7 @@ void qib_disable_after_error(struct qib_devdata *dd) static void qib_remove_one(struct pci_dev *); static int qib_init_one(struct pci_dev *, const struct pci_device_id *); +static void qib_shutdown_one(struct pci_dev *); #define DRIVER_LOAD_MSG "Intel " QIB_DRV_NAME " loaded: " #define PFX QIB_DRV_NAME ": " @@ -1240,6 +1245,7 @@ static struct pci_driver qib_driver = { .name = QIB_DRV_NAME, .probe = qib_init_one, .remove = qib_remove_one, + .shutdown = qib_shutdown_one, .id_table = qib_pci_tbl, .err_handler = &qib_pci_err_handler, }; @@ -1591,6 +1597,13 @@ static void qib_remove_one(struct pci_dev *pdev) qib_postinit_cleanup(dd); } +static void qib_shutdown_one(struct pci_dev *pdev) +{ + struct qib_devdata *dd = pci_get_drvdata(pdev); + + qib_shutdown_device(dd); +} + /** * qib_create_rcvhdrq - create a receive header queue * @dd: the qlogic_ib device diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c index 75f08624ac052abed2347cb462990c0545c8d828..4715edff5488bb93e9bd7d3c4db167f0bf6f4f37 100644 --- a/drivers/infiniband/hw/qib/qib_user_pages.c +++ b/drivers/infiniband/hw/qib/qib_user_pages.c @@ -98,23 +98,27 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages, * * I'm sure we won't be so lucky with other iommu's, so FIXME. */ -dma_addr_t qib_map_page(struct pci_dev *hwdev, struct page *page, - unsigned long offset, size_t size, int direction) +int qib_map_page(struct pci_dev *hwdev, struct page *page, dma_addr_t *daddr) { dma_addr_t phys; - phys = pci_map_page(hwdev, page, offset, size, direction); + phys = pci_map_page(hwdev, page, 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(hwdev, phys)) + return -ENOMEM; - if (phys == 0) { - pci_unmap_page(hwdev, phys, size, direction); - phys = pci_map_page(hwdev, page, offset, size, direction); + if (!phys) { + pci_unmap_page(hwdev, phys, PAGE_SIZE, PCI_DMA_FROMDEVICE); + phys = pci_map_page(hwdev, page, 0, PAGE_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(hwdev, phys)) + return -ENOMEM; /* * FIXME: If we get 0 again, we should keep this page, * map another, then free the 0 page. */ } - - return phys; + *daddr = phys; + return 0; } /** diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index b879d21b75481f14a03529862f3c32b9bbb92144..02a5e2d7e574ddbb748efe9f3328064f4c0e2c57 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -879,15 +879,9 @@ isert_login_post_send(struct isert_conn *isert_conn, struct iser_tx_desc *tx_des } static void -isert_create_send_desc(struct isert_conn *isert_conn, - struct isert_cmd *isert_cmd, - struct iser_tx_desc *tx_desc) +__isert_create_send_desc(struct isert_device *device, + struct iser_tx_desc *tx_desc) { - struct isert_device *device = isert_conn->device; - struct ib_device *ib_dev = device->ib_device; - - ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr, - ISER_HEADERS_LEN, DMA_TO_DEVICE); memset(&tx_desc->iser_header, 0, sizeof(struct iser_ctrl)); tx_desc->iser_header.flags = ISCSI_CTRL; @@ -900,6 +894,20 @@ isert_create_send_desc(struct isert_conn *isert_conn, } } +static void +isert_create_send_desc(struct isert_conn *isert_conn, + struct isert_cmd *isert_cmd, + struct iser_tx_desc *tx_desc) +{ + struct isert_device *device = isert_conn->device; + struct ib_device *ib_dev = device->ib_device; + + ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr, + ISER_HEADERS_LEN, DMA_TO_DEVICE); + + __isert_create_send_desc(device, tx_desc); +} + static int isert_init_tx_hdrs(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc) @@ -987,7 +995,7 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, struct iser_tx_desc *tx_desc = &isert_conn->login_tx_desc; int ret; - isert_create_send_desc(isert_conn, NULL, tx_desc); + __isert_create_send_desc(device, tx_desc); memcpy(&tx_desc->iscsi_header, &login->rsp[0], sizeof(struct iscsi_hdr)); @@ -2082,7 +2090,7 @@ isert_set_sig_attrs(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs) sig_attrs->check_mask = (se_cmd->prot_checks & TARGET_DIF_CHECK_GUARD ? 0xc0 : 0) | - (se_cmd->prot_checks & TARGET_DIF_CHECK_REFTAG ? 0x30 : 0) | + (se_cmd->prot_checks & TARGET_DIF_CHECK_APPTAG ? 0x30 : 0) | (se_cmd->prot_checks & TARGET_DIF_CHECK_REFTAG ? 0x0f : 0); return 0; } diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 93c28ef127e2bd3b60c2778983f2dcd9aa8e1384..65379ed8ed35f10c36c22eb3f8a6054e23fd4302 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -487,6 +487,19 @@ static ssize_t qpnp_pon_dbc_store(struct device *dev, return size; } +static struct qpnp_pon_config * +qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) +{ + int i; + + for (i = 0; i < pon->num_pon_config; i++) { + if (pon_type == pon->pon_cfg[i].pon_type) + return &pon->pon_cfg[i]; + } + + return NULL; +} + static DEVICE_ATTR(debounce_us, 0664, qpnp_pon_dbc_show, qpnp_pon_dbc_store); #define PON_TWM_ENTRY_PBS_BIT BIT(0) @@ -496,6 +509,7 @@ static int qpnp_pon_reset_config(struct qpnp_pon *pon, int rc; bool disable = false; u16 rst_en_reg; + struct qpnp_pon_config *cfg; /* Ignore the PS_HOLD reset config if TWM ENTRY is enabled */ if (pon->support_twm_config && pon->twm_state == PMIC_TWM_ENABLE) { @@ -506,6 +520,18 @@ static int qpnp_pon_reset_config(struct qpnp_pon *pon, rc); return rc; } + + cfg = qpnp_get_cfg(pon, PON_KPDPWR); + if (cfg) { + /* configure KPDPWR_S2 to Hard reset */ + rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, + QPNP_PON_S2_CNTL_TYPE_MASK, + PON_POWER_OFF_HARD_RESET); + if (rc < 0) + pr_err("Unable to config KPDPWR_N S2 for hard-reset rc=%d\n", + rc); + } + pr_crit("PMIC configured for TWM entry\n"); return 0; } @@ -901,19 +927,6 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) return 0; } -static struct qpnp_pon_config * -qpnp_get_cfg(struct qpnp_pon *pon, u32 pon_type) -{ - int i; - - for (i = 0; i < pon->num_pon_config; i++) { - if (pon_type == pon->pon_cfg[i].pon_type) - return &pon->pon_cfg[i]; - } - - return NULL; -} - static int qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type) { diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c index 26cee2ee7508e943175c7f51b6148723ee4ea1cb..34508b2069c821b354c40ca2c876656925bbca6d 100644 --- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c @@ -963,6 +963,8 @@ static ssize_t stmvl53l0x_show_meter(struct device *dev, struct vl_data *data = dev_get_drvdata(dev); struct VL_RangingMeasurementData_t Measure; + if (data->enable_ps_sensor == 0) + return -ENODEV; papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); return snprintf(buf, 7, "%d\n", Measure.RangeMilliMeter); } diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index c0ec26118732879f7674f68bd0458b3d27602f61..83dd0ce3ad2a57683fea27842e67d6b3ebe19ca2 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -27,6 +27,8 @@ #define ETP_DISABLE_POWER 0x0001 #define ETP_PRESSURE_OFFSET 25 +#define ETP_CALIBRATE_MAX_LEN 3 + /* IAP Firmware handling */ #define ETP_PRODUCT_ID_FORMAT_STRING "%d.0" #define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin" diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 3851d5715772f8894698f22166a98d65e16db616..97f6e05cffce43818cfae131836146b8f35c7abe 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -595,7 +595,7 @@ static ssize_t calibrate_store(struct device *dev, int tries = 20; int retval; int error; - u8 val[3]; + u8 val[ETP_CALIBRATE_MAX_LEN]; retval = mutex_lock_interruptible(&data->sysfs_mutex); if (retval) @@ -1249,6 +1249,8 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN060B", 0 }, { "ELAN060C", 0 }, { "ELAN0611", 0 }, + { "ELAN0612", 0 }, + { "ELAN0618", 0 }, { "ELAN1000", 0 }, { } }; diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index e23b2495d52e1558f2b6dc8ff7128550f0e9dae0..d21bd55f3c42ab4a16bd618eb788d0987aa2f3fb 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -56,7 +56,7 @@ static int elan_smbus_initialize(struct i2c_client *client) { u8 check[ETP_SMBUS_HELLOPACKET_LEN] = { 0x55, 0x55, 0x55, 0x55, 0x55 }; - u8 values[ETP_SMBUS_HELLOPACKET_LEN] = { 0, 0, 0, 0, 0 }; + u8 values[I2C_SMBUS_BLOCK_MAX] = {0}; int len, error; /* Get hello packet */ @@ -117,12 +117,16 @@ static int elan_smbus_calibrate(struct i2c_client *client) static int elan_smbus_calibrate_result(struct i2c_client *client, u8 *val) { int error; + u8 buf[I2C_SMBUS_BLOCK_MAX] = {0}; + + BUILD_BUG_ON(ETP_CALIBRATE_MAX_LEN > sizeof(buf)); error = i2c_smbus_read_block_data(client, - ETP_SMBUS_CALIBRATE_QUERY, val); + ETP_SMBUS_CALIBRATE_QUERY, buf); if (error < 0) return error; + memcpy(val, buf, ETP_CALIBRATE_MAX_LEN); return 0; } @@ -130,7 +134,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client, bool max_baseline, u8 *value) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, max_baseline ? @@ -149,7 +153,7 @@ static int elan_smbus_get_version(struct i2c_client *client, bool iap, u8 *version) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_IAP_VERSION_CMD : @@ -169,7 +173,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, u8 *ic_type, u8 *version) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_SM_VERSION_CMD, val); @@ -186,7 +190,7 @@ static int elan_smbus_get_sm_version(struct i2c_client *client, static int elan_smbus_get_product_id(struct i2c_client *client, u16 *id) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_UNIQUEID_CMD, val); @@ -203,7 +207,7 @@ static int elan_smbus_get_checksum(struct i2c_client *client, bool iap, u16 *csum) { int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, iap ? ETP_SMBUS_FW_CHECKSUM_CMD : @@ -224,7 +228,7 @@ static int elan_smbus_get_max(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RANGE_CMD, val); if (ret != 3) { @@ -244,7 +248,7 @@ static int elan_smbus_get_resolution(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_RESOLUTION_CMD, val); if (ret != 3) { @@ -265,7 +269,7 @@ static int elan_smbus_get_num_traces(struct i2c_client *client, { int ret; int error; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; ret = i2c_smbus_read_block_data(client, ETP_SMBUS_XY_TRACENUM_CMD, val); if (ret != 3) { @@ -292,7 +296,7 @@ static int elan_smbus_iap_get_mode(struct i2c_client *client, { int error; u16 constant; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; error = i2c_smbus_read_block_data(client, ETP_SMBUS_IAP_CTRL_CMD, val); if (error < 0) { @@ -343,7 +347,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client) int len; int error; enum tp_mode mode; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; u8 cmd[4] = {0x0F, 0x78, 0x00, 0x06}; u16 password; @@ -417,7 +421,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, struct device *dev = &client->dev; int error; u16 result; - u8 val[3]; + u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; /* * Due to the limitation of smbus protocol limiting @@ -470,6 +474,8 @@ static int elan_smbus_get_report(struct i2c_client *client, u8 *report) { int len; + BUILD_BUG_ON(I2C_SMBUS_BLOCK_MAX > ETP_SMBUS_REPORT_LEN); + len = i2c_smbus_read_block_data(client, ETP_SMBUS_PACKET_QUERY, &report[ETP_SMBUS_REPORT_OFFSET]); diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index c519c0b09568e952388c0df4485455821314cb7e..4e77adbfa8355ae4ed540b099f6ad144d7f0e399 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -800,7 +800,7 @@ static int elantech_packet_check_v4(struct psmouse *psmouse) else if (ic_version == 7 && etd->samples[1] == 0x2A) sanity_check = ((packet[3] & 0x1c) == 0x10); else - sanity_check = ((packet[0] & 0x0c) == 0x04 && + sanity_check = ((packet[0] & 0x08) == 0x00 && (packet[3] & 0x1c) == 0x10); if (!sanity_check) @@ -1173,6 +1173,12 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = { { } }; +static const char * const middle_button_pnp_ids[] = { + "LEN2131", /* ThinkPad P52 w/ NFC */ + "LEN2132", /* ThinkPad P52 */ + NULL +}; + /* * Set the appropriate event bits for the input subsystem */ @@ -1192,7 +1198,8 @@ static int elantech_set_input_params(struct psmouse *psmouse) __clear_bit(EV_REL, dev->evbit); __set_bit(BTN_LEFT, dev->keybit); - if (dmi_check_system(elantech_dmi_has_middle_button)) + if (dmi_check_system(elantech_dmi_has_middle_button) || + psmouse_matches_pnp_id(psmouse, middle_button_pnp_ids)) __set_bit(BTN_MIDDLE, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6c4156a5fe67837bca9c422e2547603890513c58..a259ef356dcad42763315aba6d45635627a09c80 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1279,6 +1279,18 @@ config FT_SECURE_TOUCH If unsure, say N. +config TOUCHSCREEN_GT9XX_v28 + bool "Goodix touchpanel GT9xx_v28 series" + depends on I2C + help + Say Y here if you have a Goodix GT9xx_v28 touchscreen. + Gt9xx controllers are multi touch controllers which can + report 5 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/gt9xx_v2.8/Kconfig" + config TOUCHSCREEN_HIMAX_CHIPSET bool "Himax touchpanel CHIPSET" depends on I2C @@ -1287,8 +1299,18 @@ config TOUCHSCREEN_HIMAX_CHIPSET HIMAX controllers are multi touch controllers which can report 10 touches at a time. - If unsure, say N. + If unsure, say N. source "drivers/input/touchscreen/hxchipset/Kconfig" +config TOUCHSCREEN_EKTF3XXX_CHIPSET + bool "Elan EKTF3XXX touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Elan CHIPSET touchscreen. + ELAN controllers are multi touch controllers which can + report 10 touches at a time. + + If unusre, say N. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index a5952cab1e752d6eff114a92a2c35dc5248d8876..2579346cf53e05db92e2680eabb5c72c296220ba 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -104,4 +104,6 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ +obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx_v2.8/ obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ +obj-$(CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET) += ektf3xxx/ diff --git a/drivers/input/touchscreen/ektf3xxx/Makefile b/drivers/input/touchscreen/ektf3xxx/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..715b8918442c576039e35465d7239f641f8d05f5 --- /dev/null +++ b/drivers/input/touchscreen/ektf3xxx/Makefile @@ -0,0 +1,3 @@ +# Makefile for the Elan touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_EKTF3XXX_CHIPSET) += elan_cros_i2c.o diff --git a/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c b/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c new file mode 100644 index 0000000000000000000000000000000000000000..71a30f2719d5cb4cd7a1bfaebf56ff7d965bf88d --- /dev/null +++ b/drivers/input/touchscreen/ektf3xxx/elan_cros_i2c.c @@ -0,0 +1,1521 @@ +/* + * Elan Microelectronics touch panels with I2C interface + * + * Copyright (C) 2014 Elan Microelectronics Corporation. + * Chuming Zhang + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Device, Driver information */ +#define DEVICE_NAME "elants_i2c" +#define DRV_VERSION "1.0.9" + +/* Convert from rows or columns into resolution */ +#define ELAN_TS_RESOLUTION(n, m) (((n) - 1) * (m)) +#define ELAN_VTG_MAX_UV 3300000 + +/* FW header data */ +#define HEADER_SIZE 4 +#define FW_HDR_TYPE 0 +#define FW_HDR_COUNT 1 +#define FW_HDR_LENGTH 2 + +/* Buffer mode Queue Header information */ +#define QUEUE_HEADER_SINGLE 0x62 +#define QUEUE_HEADER_NORMAL 0X63 +#define QUEUE_HEADER_WAIT 0x64 + +/* Command header definition */ +#define CMD_HEADER_WRITE 0x54 +#define CMD_HEADER_READ 0x53 +#define CMD_HEADER_6B_READ 0x5B +#define CMD_HEADER_RESP 0x52 +#define CMD_HEADER_6B_RESP 0x9B +#define CMD_HEADER_HELLO 0x55 +#define CMD_HEADER_REK 0x66 + +/* FW position data */ +#define PACKET_SIZE 55 +#define MAX_CONTACT_NUM 10 +#define FW_POS_HEADER 0 +#define FW_POS_STATE 1 +#define FW_POS_TOTAL 2 +#define FW_POS_XY 3 +#define FW_POS_CHECKSUM 34 +#define FW_POS_WIDTH 35 +#define FW_POS_PRESSURE 45 + +#define HEADER_REPORT_10_FINGER 0x62 + +/* Header (4 bytes) plus 3 fill 10-finger packets */ +#define MAX_PACKET_SIZE 169 + +#define BOOT_TIME_DELAY_MS 50 + +/* FW read command, 0x53 0x?? 0x0, 0x01 */ +#define E_ELAN_INFO_FW_VER 0x00 +#define E_ELAN_INFO_BC_VER 0x10 +#define E_ELAN_INFO_TEST_VER 0xE0 +#define E_ELAN_INFO_FW_ID 0xF0 +#define E_INFO_OSR 0xD6 +#define E_INFO_PHY_SCAN 0xD7 +#define E_INFO_PHY_DRIVER 0xD8 + +#define MAX_RETRIES 3 +#define MAX_FW_UPDATE_RETRIES 30 + +#define ELAN_FW_PAGESIZE 132 + +/* calibration timeout definition */ +#define ELAN_CALI_TIMEOUT_MSEC 12000 + +#define ELAN_POWERON_DELAY_USEC 500 +#define ELAN_RESET_DELAY_MSEC 20 + +/* define print buf size*/ +#define ELAN_PRINT_SIZE 1024 + +enum elants_state { + ELAN_STATE_NORMAL, + ELAN_WAIT_QUEUE_HEADER, + ELAN_WAIT_RECALIBRATION, +}; + +enum elants_iap_mode { + ELAN_IAP_OPERATIONAL, + ELAN_IAP_RECOVERY, +}; + +/* struct elants_data - represents state of Elan touchscreen device */ +struct elants_data { + struct i2c_client *client; + struct input_dev *input; + + struct regulator *vdd; + struct regulator *vccio; + struct gpio_desc *reset_gpio; + + u16 fw_version; + u8 test_version; + u8 solution_version; + u8 bc_version; + u8 iap_version; + u16 hw_version; + unsigned int x_res; /* resolution in units/mm */ + unsigned int y_res; + unsigned int x_max; + unsigned int y_max; + + enum elants_state state; + enum elants_iap_mode iap_mode; + + /* Guards against concurrent access to the device via sysfs */ + struct mutex sysfs_mutex; + + u8 cmd_resp[HEADER_SIZE]; + struct completion cmd_done; + + u8 buf[MAX_PACKET_SIZE]; + + bool wake_irq_enabled; + bool keep_power_in_suspend; + struct workqueue_struct *elan_ic_update; + struct delayed_work delay_work; +}; + +static int elants_i2c_send(struct i2c_client *client, + const void *data, size_t size) +{ + int ret; + + ret = i2c_master_send(client, data, size); + if (ret == size) + return 0; + + if (ret >= 0) + ret = -EIO; + + dev_err(&client->dev, "%s failed (%*ph): %d\n", + __func__, (int)size, data, ret); + + return ret; +} + +static int elants_i2c_read(struct i2c_client *client, void *data, size_t size) +{ + int ret; + + ret = i2c_master_recv(client, data, size); + if (ret == size) + return 0; + + if (ret >= 0) + ret = -EIO; + + dev_err(&client->dev, "%s failed: %d\n", __func__, ret); + + return ret; +} + +static int elants_i2c_execute_command(struct i2c_client *client, + const u8 *cmd, size_t cmd_size, + u8 *resp, size_t resp_size) +{ + struct i2c_msg msgs[2]; + int ret; + u8 expected_response; + + switch (cmd[0]) { + case CMD_HEADER_READ: + expected_response = CMD_HEADER_RESP; + break; + + case CMD_HEADER_6B_READ: + expected_response = CMD_HEADER_6B_RESP; + break; + + default: + dev_err(&client->dev, "%s: invalid command %*ph\n", + __func__, (int)cmd_size, cmd); + return -EINVAL; + } + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags & I2C_M_TEN; + msgs[0].len = cmd_size; + msgs[0].buf = (u8 *)cmd; + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags & I2C_M_TEN; + msgs[1].flags |= I2C_M_RD; + msgs[1].len = resp_size; + msgs[1].buf = resp; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + + if (ret != ARRAY_SIZE(msgs) || resp[FW_HDR_TYPE] != expected_response) + return -EIO; + + return 0; +} + +static int elants_i2c_calibrate(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int ret, error; + static const u8 w_flashkey[] = { 0x54, 0xC0, 0xE1, 0x5A }; + static const u8 rek[] = { 0x54, 0x29, 0x00, 0x01 }; + static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 }; + + disable_irq(client->irq); + + ts->state = ELAN_WAIT_RECALIBRATION; + reinit_completion(&ts->cmd_done); + + elants_i2c_send(client, w_flashkey, sizeof(w_flashkey)); + elants_i2c_send(client, rek, sizeof(rek)); + + enable_irq(client->irq); + + ret = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC)); + + ts->state = ELAN_STATE_NORMAL; + + if (ret <= 0) { + error = ret < 0 ? ret : -ETIMEDOUT; + dev_err(&client->dev, + "error while waiting for calibration to complete: %d\n", + error); + return error; + } + + if (memcmp(rek_resp, ts->cmd_resp, sizeof(rek_resp))) { + dev_err(&client->dev, + "unexpected calibration response: %*ph\n", + (int)sizeof(ts->cmd_resp), ts->cmd_resp); + return -EINVAL; + } + + return 0; +} + +static int elants_i2c_sw_reset(struct i2c_client *client) +{ + const u8 soft_rst_cmd[] = { 0x77, 0x77, 0x77, 0x77 }; + int error; + + error = elants_i2c_send(client, soft_rst_cmd, + sizeof(soft_rst_cmd)); + if (error) { + dev_err(&client->dev, "software reset failed: %d\n", error); + return error; + } + + /* + * We should wait at least 10 msec (but no more than 40) before + * sending fastboot or IAP command to the device. + */ + msleep(30); + + return 0; +} + +static u16 elants_i2c_parse_version(u8 *buf) +{ + return get_unaligned_be32(buf) >> 4; +} + +static int elants_i2c_query_hw_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_ID, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + ts->hw_version = elants_i2c_parse_version(resp); + if (ts->hw_version != 0xffff) + return 0; + } + dev_dbg(&client->dev, "read fw id error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + if (error) { + dev_err(&client->dev, + "Failed to read fw id: %d\n", error); + return error; + } + dev_err(&client->dev, "Invalid fw id: %#04x\n", ts->hw_version); + return -EINVAL; +} + + +static int elants_i2c_query_fw_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_FW_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + ts->fw_version = elants_i2c_parse_version(resp); + if (ts->fw_version != 0x0000 && + ts->fw_version != 0xffff) + return 0; + } + + dev_dbg(&client->dev, "read fw version error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, + "Failed to read fw version or fw version is invalid\n"); + + return -EINVAL; +} + +static int elants_i2c_query_test_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, retry_cnt; + u16 version; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_TEST_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (!error) { + version = elants_i2c_parse_version(resp); + ts->test_version = version >> 8; + ts->solution_version = version & 0xff; + + return 0; + } + + dev_dbg(&client->dev, + "read test version error rc=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + } + + dev_err(&client->dev, "Failed to read test version\n"); + + return -EINVAL; +} + +static int elants_i2c_query_bc_version(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + const u8 cmd[] = { CMD_HEADER_READ, E_ELAN_INFO_BC_VER, 0x00, 0x01 }; + u8 resp[HEADER_SIZE]; + u16 version; + int error; + + error = elants_i2c_execute_command(client, cmd, sizeof(cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, + "read BC version error=%d, buf=%*phC\n", + error, (int)sizeof(resp), resp); + return error; + } + + version = elants_i2c_parse_version(resp); + ts->bc_version = version >> 8; + ts->iap_version = version & 0xff; + + return 0; +} + +static int elants_i2c_query_ts_info(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error; + u8 resp[17]; + u16 phy_x, phy_y, rows, cols, osr; + const u8 get_resolution_cmd[] = { + CMD_HEADER_6B_READ, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + const u8 get_osr_cmd[] = { + CMD_HEADER_READ, E_INFO_OSR, 0x00, 0x01 + }; + const u8 get_physical_scan_cmd[] = { + CMD_HEADER_READ, E_INFO_PHY_SCAN, 0x00, 0x01 + }; + const u8 get_physical_drive_cmd[] = { + CMD_HEADER_READ, E_INFO_PHY_DRIVER, 0x00, 0x01 + }; + + /* Get trace number */ + error = elants_i2c_execute_command(client, + get_resolution_cmd, + sizeof(get_resolution_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get resolution command failed: %d\n", + error); + return error; + } + + rows = resp[2] + resp[6] + resp[10]; + cols = resp[3] + resp[7] + resp[11]; + + /* Process mm_to_pixel information */ + error = elants_i2c_execute_command(client, + get_osr_cmd, sizeof(get_osr_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get osr command failed: %d\n", + error); + return error; + } + + osr = resp[3]; + + error = elants_i2c_execute_command(client, + get_physical_scan_cmd, + sizeof(get_physical_scan_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get physical scan command failed: %d\n", + error); + return error; + } + + phy_x = get_unaligned_be16(&resp[2]); + + error = elants_i2c_execute_command(client, + get_physical_drive_cmd, + sizeof(get_physical_drive_cmd), + resp, sizeof(resp)); + if (error) { + dev_err(&client->dev, "get physical drive command failed: %d\n", + error); + return error; + } + + phy_y = get_unaligned_be16(&resp[2]); + + dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y); + + if (rows == 0 || cols == 0 || osr == 0) { + dev_warn(&client->dev, + "invalid trace number data: %d, %d, %d\n", + rows, cols, osr); + } else { + /* translate trace number to TS resolution */ + ts->y_max = ELAN_TS_RESOLUTION(rows, osr); + ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); + ts->x_max = ELAN_TS_RESOLUTION(cols, osr); + ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); + } + + return 0; +} + +static int elants_i2c_fastboot(struct i2c_client *client) +{ + const u8 boot_cmd[] = { 0x4D, 0x61, 0x69, 0x6E }; + int error; + + error = elants_i2c_send(client, boot_cmd, sizeof(boot_cmd)); + if (error) { + dev_err(&client->dev, "boot failed: %d\n", error); + return error; + } + + dev_dbg(&client->dev, "boot success -- 0x%x\n", client->addr); + return 0; +} + +static int elants_i2c_initialize(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + int error, error2, retry_cnt; + const u8 hello_packet[] = { 0x55, 0x55, 0x55, 0x55 }; + const u8 recov_packet[] = { 0x55, 0x55, 0x80, 0x80 }; + u8 buf[HEADER_SIZE]; + + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_sw_reset(client); + if (error) { + /* Continue initializing if it's the last try */ + if (retry_cnt < MAX_RETRIES - 1) + continue; + } + + error = elants_i2c_fastboot(client); + if (error) { + /* Continue initializing if it's the last try */ + if (retry_cnt < MAX_RETRIES - 1) + continue; + } + + /* Wait for Hello packet */ + msleep(BOOT_TIME_DELAY_MS); + + error = elants_i2c_read(client, buf, sizeof(buf)); + if (error) { + dev_err(&client->dev, + "failed to read 'hello' packet: %d\n", error); + continue; + } else if (!memcmp(buf, hello_packet, sizeof(hello_packet))) { + ts->iap_mode = ELAN_IAP_OPERATIONAL; + break; + } else if (!memcmp(buf, recov_packet, sizeof(recov_packet))) { + /* + * Setting error code will mark device + * in recovery mode below. + */ + error = -EIO; + break; + } + error = -EINVAL; + dev_err(&client->dev, + "invalid 'hello' packet: %*ph\n", + (int)sizeof(buf), buf); + } + + error2 = elants_i2c_query_hw_version(ts); + if (!error) + error = error2; + if (!error) + error = elants_i2c_query_fw_version(ts); + if (!error) + error = elants_i2c_query_test_version(ts); + if (!error) + error = elants_i2c_query_bc_version(ts); + if (!error) + error = elants_i2c_query_ts_info(ts); + if (error) + ts->iap_mode = ELAN_IAP_RECOVERY; + return 0; +} + +/* + * Firmware update interface. + */ + +static int elants_i2c_fw_write_page(struct i2c_client *client, + const void *page, int page_num) +{ + const u8 ack_ok[] = { 0xaa, 0xaa }; + u8 buf[2]; + int retry; + int error; + int curIndex = 0; + const u8 *szBuff; + int byte_count; + + for (retry = 0; retry < MAX_FW_UPDATE_RETRIES; retry++) { + for (byte_count = 1; byte_count <= 5; byte_count++) { + if (byte_count != 5) { + szBuff = page + curIndex; + curIndex = curIndex + 32; + error = elants_i2c_send(client, szBuff, 32); + } else { + szBuff = page + curIndex; + curIndex = curIndex + 4; + error = elants_i2c_send(client, szBuff, 4); + } + + if (error) { + curIndex = 0; + continue; + } + } + + if (error) { + dev_err(&client->dev, + "IAP Write Page failed: %d\n", error); + continue; + } + + if (page_num == 1) + msleep(600); + else + msleep(50); + error = elants_i2c_read(client, buf, 2); + if (error) { + dev_err(&client->dev, + "IAP Ack read failed: %d\n", error); + return error; + } + + if (!memcmp(buf, ack_ok, sizeof(ack_ok))) + return 0; + + error = -EIO; + dev_err(&client->dev, + "IAP Get Ack Error [%02x:%02x]\n", + buf[0], buf[1]); + } + + return error; +} + +static int elants_i2c_do_update_firmware(struct i2c_client *client, + const struct firmware *fw, + bool force) +{ + const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 }; + const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 }; + const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc }; + const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01}; + u8 buf[HEADER_SIZE]; + u16 send_id; + int page, n_fw_pages; + int error; + + /* Recovery mode detection! */ + if (force) { + dev_dbg(&client->dev, "Recovery mode procedure\n"); + error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2)); + } else { + /* Start IAP Procedure */ + dev_dbg(&client->dev, "Normal IAP procedure\n"); + /* Close idle mode */ + error = elants_i2c_send(client, close_idle, sizeof(close_idle)); + if (error) + dev_err(&client->dev, "Failed close idle: %d\n", error); + msleep(60); + elants_i2c_sw_reset(client); + msleep(20); + error = elants_i2c_send(client, enter_iap, sizeof(enter_iap)); + } + + if (error) { + dev_err(&client->dev, "failed to enter IAP mode: %d\n", error); + return error; + } + + msleep(20); + + /* check IAP state */ + error = elants_i2c_read(client, buf, 4); + if (error) { + dev_err(&client->dev, + "failed to read IAP acknowledgment: %d\n", + error); + return error; + } + + if (memcmp(buf, iap_ack, sizeof(iap_ack))) { + dev_err(&client->dev, + "failed to enter IAP: %*ph (expected %*ph)\n", + (int)sizeof(buf), buf, (int)sizeof(iap_ack), iap_ack); + return -EIO; + } + + dev_info(&client->dev, "successfully entered IAP mode"); + + send_id = client->addr; + error = elants_i2c_send(client, &send_id, 1); + if (error) { + dev_err(&client->dev, "sending dummy byte failed: %d\n", + error); + return error; + } + + /* Clear the last page of Master */ + error = elants_i2c_send(client, fw->data, ELAN_FW_PAGESIZE); + if (error) { + dev_err(&client->dev, "clearing of the last page failed: %d\n", + error); + return error; + } + + error = elants_i2c_read(client, buf, 2); + if (error) { + dev_err(&client->dev, + "failed to read ACK for clearing the last page: %d\n", + error); + return error; + } + + n_fw_pages = fw->size / ELAN_FW_PAGESIZE; + dev_dbg(&client->dev, "IAP Pages = %d\n", n_fw_pages); + + for (page = 0; page < n_fw_pages; page++) { + error = elants_i2c_fw_write_page(client, + fw->data + page * ELAN_FW_PAGESIZE, + page); + if (error) { + dev_err(&client->dev, + "failed to write FW page %d: %d\n", + page, error); + return error; + } + } + + /* Old iap needs to wait 200ms for WDT and rest is for hello packets */ + msleep(300); + + dev_info(&client->dev, "firmware update completed\n"); + return 0; +} + +static int elants_i2c_fw_update(struct elants_data *ts) +{ + struct i2c_client *client = ts->client; + const struct firmware *fw; + char *fw_name; + int error; + + fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); + if (!fw_name) + return -ENOMEM; + + dev_info(&client->dev, "requesting fw name = %s\n", fw_name); + error = request_firmware(&fw, fw_name, &client->dev); + kfree(fw_name); + if (error) { + dev_err(&client->dev, "failed to request firmware: %d\n", + error); + return error; + } + + if (fw->size % ELAN_FW_PAGESIZE) { + dev_err(&client->dev, "invalid firmware length: %zu\n", + fw->size); + error = -EINVAL; + goto out; + } + + disable_irq(client->irq); + + error = elants_i2c_do_update_firmware(client, fw, + ts->iap_mode == ELAN_IAP_RECOVERY); + if (error) { + dev_err(&client->dev, "firmware update failed: %d\n", error); + ts->iap_mode = ELAN_IAP_RECOVERY; + goto out_enable_irq; + } + + error = elants_i2c_initialize(ts); + if (error) { + dev_err(&client->dev, + "failed to initialize device after firmware update: %d\n", + error); + ts->iap_mode = ELAN_IAP_RECOVERY; + goto out_enable_irq; + } + + ts->iap_mode = ELAN_IAP_OPERATIONAL; + +out_enable_irq: + ts->state = ELAN_STATE_NORMAL; + enable_irq(client->irq); + msleep(100); + + if (!error) + elants_i2c_calibrate(ts); +out: + release_firmware(fw); + return error; +} + +static void elants_i2c_auto_update(struct work_struct *work) +{ + struct elants_data *ts = container_of(work, + struct elants_data, delay_work.work); + struct i2c_client *client = ts->client; + const struct firmware *fw; + char *fw_name; + int error; + u8 *fw_data; + u16 new_fw_version; + u16 new_hw_version; + + if (ts->fw_version == 0x0000 || + ts->fw_version == 0xffff) { + dev_err(&client->dev, "invalid firmware version: %04x\n", + ts->fw_version); + return; + } + + fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version); + if (!fw_name) + return; + + dev_info(&client->dev, "requesting fw name = %s\n", fw_name); + error = request_firmware(&fw, fw_name, &client->dev); + kfree(fw_name); + if (error) { + dev_err(&client->dev, "failed to request firmware: %d\n", + error); + return; + } + + if (fw->size % ELAN_FW_PAGESIZE) { + dev_err(&client->dev, "invalid firmware length: %zu\n", + fw->size); + error = -EINVAL; + goto out; + } + + fw_data = (u8 *)fw->data; + + new_hw_version = fw_data[0xE2CF] << 8 | fw_data[0xE2CE]; + new_fw_version = fw_data[0xDEC3] << 8 | fw_data[0xDEC2]; + dev_dbg(&client->dev, "hw version=0x%x, new hw version=0x%x\n", + ts->hw_version, new_hw_version); + dev_dbg(&client->dev, "fw version=0x%x, new fw version=0x%x\n", + ts->fw_version, new_fw_version); + if ((ts->hw_version == new_hw_version) && + ((ts->fw_version & 0xff) < (new_fw_version & 0xff))) { + dev_dbg(&ts->client->dev, "start auto update\n"); + release_firmware(fw); + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return; + + error = elants_i2c_fw_update(ts); + dev_dbg(&client->dev, "firmware update result: %d\n", error); + + mutex_unlock(&ts->sysfs_mutex); + return; + } + +out: + release_firmware(fw); +} + + + +/* + * Event reporting. + */ + +static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) +{ + struct input_dev *input = ts->input; + unsigned int n_fingers; + u16 finger_state; + int i; + + n_fingers = buf[FW_POS_STATE + 1] & 0x0f; + finger_state = ((buf[FW_POS_STATE + 1] & 0x30) << 4) | + buf[FW_POS_STATE]; + + dev_dbg(&ts->client->dev, + "n_fingers: %u, state: %04x\n", n_fingers, finger_state); + + for (i = 0; i < MAX_CONTACT_NUM && n_fingers; i++) { + if (finger_state & 1) { + unsigned int x, y, p, w; + u8 *pos; + + pos = &buf[FW_POS_XY + i * 3]; + x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; + y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; + p = buf[FW_POS_PRESSURE + i]; + w = buf[FW_POS_WIDTH + i]; + + dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", + i, x, y, p, w); + + input_mt_slot(input, i); + input_mt_report_slot_state(input, MT_TOOL_FINGER, true); + input_event(input, EV_ABS, ABS_MT_POSITION_X, x); + input_event(input, EV_ABS, ABS_MT_POSITION_Y, y); + /* input_event(input, EV_ABS, ABS_MT_PRESSURE, p);*/ + input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, w); + + n_fingers--; + } + + finger_state >>= 1; + } + + input_mt_sync_frame(input); + input_sync(input); +} + +static u8 elants_i2c_calculate_checksum(u8 *buf) +{ + u8 checksum = 0; + u8 i; + + for (i = 0; i < FW_POS_CHECKSUM; i++) + checksum += buf[i]; + + return checksum; +} + +static void elants_i2c_event(struct elants_data *ts, u8 *buf) +{ + u8 checksum = elants_i2c_calculate_checksum(buf); + + if (unlikely(buf[FW_POS_CHECKSUM] != checksum)) + dev_warn(&ts->client->dev, + "%s: invalid checksum for packet %02x: %02x vs. %02x\n", + __func__, buf[FW_POS_HEADER], + checksum, buf[FW_POS_CHECKSUM]); + else if (unlikely(buf[FW_POS_HEADER] != HEADER_REPORT_10_FINGER)) + dev_warn(&ts->client->dev, + "%s: unknown packet type: %02x\n", + __func__, buf[FW_POS_HEADER]); + else + elants_i2c_mt_event(ts, buf); +} + +static irqreturn_t elants_i2c_irq(int irq, void *_dev) +{ + const u8 wait_packet[] = { 0x64, 0x64, 0x64, 0x64 }; + struct elants_data *ts = _dev; + struct i2c_client *client = ts->client; + int report_count, report_len; + int i; + int len; + + len = i2c_master_recv(client, ts->buf, sizeof(ts->buf)); + if (len < 0) { + dev_err(&client->dev, "%s: failed to read data: %d\n", + __func__, len); + goto out; + } + + dev_dbg(&client->dev, "%s: packet %*ph\n", + __func__, HEADER_SIZE, ts->buf); + + + switch (ts->state) { + case ELAN_WAIT_RECALIBRATION: + if (ts->buf[FW_HDR_TYPE] == CMD_HEADER_REK) { + memcpy(ts->cmd_resp, ts->buf, sizeof(ts->cmd_resp)); + complete(&ts->cmd_done); + ts->state = ELAN_STATE_NORMAL; + } + break; + + case ELAN_WAIT_QUEUE_HEADER: + if (ts->buf[FW_HDR_TYPE] != QUEUE_HEADER_NORMAL) + break; + + ts->state = ELAN_STATE_NORMAL; + /* fall through */ + + case ELAN_STATE_NORMAL: + + switch (ts->buf[FW_HDR_TYPE]) { + case CMD_HEADER_HELLO: + case CMD_HEADER_RESP: + case CMD_HEADER_REK: + break; + + case QUEUE_HEADER_WAIT: + if (memcmp(ts->buf, wait_packet, sizeof(wait_packet))) { + dev_err(&client->dev, + "invalid wait packet %*ph\n", + HEADER_SIZE, ts->buf); + } else { + ts->state = ELAN_WAIT_QUEUE_HEADER; + udelay(30); + } + break; + + case QUEUE_HEADER_SINGLE: + elants_i2c_event(ts, &ts->buf[FW_HDR_TYPE]); + break; + + case QUEUE_HEADER_NORMAL: + report_count = ts->buf[FW_HDR_COUNT]; + if (report_count == 0 || report_count > 3) { + dev_err(&client->dev, + "bad report count: %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + + report_len = ts->buf[FW_HDR_LENGTH] / report_count; + if (report_len != PACKET_SIZE) { + dev_err(&client->dev, + "mismatching report length: %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + + for (i = 0; i < report_count; i++) { + u8 *buf = ts->buf + HEADER_SIZE + + i * PACKET_SIZE; + elants_i2c_event(ts, buf); + } + break; + + default: + dev_err(&client->dev, "unknown packet %*ph\n", + HEADER_SIZE, ts->buf); + break; + } + break; + } + +out: + return IRQ_HANDLED; +} + +/* + * sysfs interface + */ +static ssize_t calibrate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + int error; + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return error; + + error = elants_i2c_calibrate(ts); + + mutex_unlock(&ts->sysfs_mutex); + return error ?: count; +} + +static ssize_t write_update_fw(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + int error; + + error = mutex_lock_interruptible(&ts->sysfs_mutex); + if (error) + return error; + + error = elants_i2c_fw_update(ts); + dev_dbg(dev, "firmware update result: %d\n", error); + + mutex_unlock(&ts->sysfs_mutex); + return error ?: count; +} + +static ssize_t show_iap_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + + return snprintf(buf, ELAN_PRINT_SIZE, "%s\n", + ts->iap_mode == ELAN_IAP_OPERATIONAL ? + "Normal" : "Recovery"); +} + +static DEVICE_ATTR(calibrate, 0200, NULL, calibrate_store); +static DEVICE_ATTR(iap_mode, 0444, show_iap_mode, NULL); +static DEVICE_ATTR(update_fw, 0200, NULL, write_update_fw); + +struct elants_version_attribute { + struct device_attribute dattr; + size_t field_offset; + size_t field_size; +}; + +#define __ELANTS_FIELD_SIZE(_field) \ + sizeof(((struct elants_data *)NULL)->_field) +#define __ELANTS_VERIFY_SIZE(_field) \ + (BUILD_BUG_ON_ZERO(__ELANTS_FIELD_SIZE(_field) > 2) + \ + __ELANTS_FIELD_SIZE(_field)) +#define ELANTS_VERSION_ATTR(_field) \ + struct elants_version_attribute elants_ver_attr_##_field = { \ + .dattr = __ATTR(_field, 0444, \ + elants_version_attribute_show, NULL), \ + .field_offset = offsetof(struct elants_data, _field), \ + .field_size = __ELANTS_VERIFY_SIZE(_field), \ + } + +static ssize_t elants_version_attribute_show(struct device *dev, + struct device_attribute *dattr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + struct elants_version_attribute *attr = + container_of(dattr, struct elants_version_attribute, dattr); + u8 *field = (u8 *)((char *)ts + attr->field_offset); + unsigned int fmt_size; + unsigned int val; + + if (attr->field_size == 1) { + val = *field; + fmt_size = 2; /* 2 HEX digits */ + } else { + val = *(u16 *)field; + fmt_size = 4; /* 4 HEX digits */ + } + + return snprintf(buf, ELAN_PRINT_SIZE, "%0*x\n", fmt_size, val); +} + +static ELANTS_VERSION_ATTR(fw_version); +static ELANTS_VERSION_ATTR(hw_version); +static ELANTS_VERSION_ATTR(test_version); +static ELANTS_VERSION_ATTR(solution_version); +static ELANTS_VERSION_ATTR(bc_version); +static ELANTS_VERSION_ATTR(iap_version); + +static struct attribute *elants_attributes[] = { + &dev_attr_calibrate.attr, + &dev_attr_update_fw.attr, + &dev_attr_iap_mode.attr, + + &elants_ver_attr_fw_version.dattr.attr, + &elants_ver_attr_hw_version.dattr.attr, + &elants_ver_attr_test_version.dattr.attr, + &elants_ver_attr_solution_version.dattr.attr, + &elants_ver_attr_bc_version.dattr.attr, + &elants_ver_attr_iap_version.dattr.attr, + NULL +}; + +static struct attribute_group elants_attribute_group = { + .attrs = elants_attributes, +}; + +static void elants_i2c_remove_sysfs_group(void *_data) +{ + struct elants_data *ts = _data; + + sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group); +} + +static int elants_i2c_power_on(struct elants_data *ts) +{ + int error; + + /* + * If we do not have reset gpio assume platform firmware + * controls regulators and does power them on for us. + */ + if (IS_ERR_OR_NULL(ts->reset_gpio)) + return 0; + + gpiod_set_value_cansleep(ts->reset_gpio, 1); + + if (regulator_count_voltages(ts->vdd) > 0) { + error = regulator_set_voltage(ts->vdd, + ELAN_VTG_MAX_UV, ELAN_VTG_MAX_UV); + if (error) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vdd ret=%d\n", + error); + goto release_reset_gpio; + } + } + + error = regulator_enable(ts->vdd); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vdd regulator: %d\n", + error); + goto release_reset_gpio; + } + + error = regulator_enable(ts->vccio); + if (error) { + dev_err(&ts->client->dev, + "failed to enable vccio regulator: %d\n", + error); + regulator_disable(ts->vdd); + goto release_reset_gpio; + } + + /* + * We need to wait a bit after powering on controller before + * we are allowed to release reset GPIO. + */ + udelay(ELAN_POWERON_DELAY_USEC); + +release_reset_gpio: + gpiod_set_value_cansleep(ts->reset_gpio, 0); + if (error) + return error; + + msleep(ELAN_RESET_DELAY_MSEC); + + return 0; +} + +static void elants_i2c_power_off(void *_data) +{ + struct elants_data *ts = _data; + + if (!IS_ERR_OR_NULL(ts->reset_gpio)) { + /* + * Activate reset gpio to prevent leakage through the + * pin once we shut off power to the controller. + */ + gpiod_set_value_cansleep(ts->reset_gpio, 1); + regulator_disable(ts->vccio); + regulator_disable(ts->vdd); + } +} + +static int elants_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + union i2c_smbus_data dummy; + struct elants_data *ts; + unsigned long irqflags; + int error; + unsigned long delay = 3*HZ; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, + "%s: i2c check functionality error\n", DEVICE_NAME); + return -ENXIO; + } + + ts = devm_kzalloc(&client->dev, sizeof(struct elants_data), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + mutex_init(&ts->sysfs_mutex); + init_completion(&ts->cmd_done); + + ts->client = client; + i2c_set_clientdata(client, ts); + + ts->vdd = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(ts->vdd)) { + error = PTR_ERR(ts->vdd); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vdd' regulator: %d\n", + error); + return error; + } + + ts->vccio = devm_regulator_get(&client->dev, "vccio"); + if (IS_ERR(ts->vccio)) { + error = PTR_ERR(ts->vccio); + if (error != -EPROBE_DEFER) + dev_err(&client->dev, + "Failed to get 'vccio' regulator: %d\n", + error); + return error; + } + + ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + + if (error == -EPROBE_DEFER) + return error; + + if (error != -ENOENT) { + dev_err(&client->dev, + "failed to get reset gpio: %d\n", + error); + return error; + } + + ts->keep_power_in_suspend = true; + } + error = elants_i2c_power_on(ts); + if (error) + return error; + + error = devm_add_action(&client->dev, elants_i2c_power_off, ts); + if (error) { + dev_err(&client->dev, + "failed to install power off action: %d\n", error); + elants_i2c_power_off(ts); + return error; + } + + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(client->adapter, client->addr, 0, + I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0) { + dev_err(&client->dev, "nothing at this address\n"); + return -ENXIO; + } + + error = elants_i2c_initialize(ts); + if (error) { + dev_err(&client->dev, "failed to initialize: %d\n", error); + return error; + } + + INIT_DELAYED_WORK(&ts->delay_work, elants_i2c_auto_update); + ts->elan_ic_update = create_singlethread_workqueue("elan_ic_update"); + queue_delayed_work(ts->elan_ic_update, &ts->delay_work, delay); + + ts->input = devm_input_allocate_device(&client->dev); + if (!ts->input) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input->name = "Elan Touchscreen"; + ts->input->id.bustype = BUS_I2C; + + __set_bit(BTN_TOUCH, ts->input->keybit); + __set_bit(EV_ABS, ts->input->evbit); + __set_bit(EV_KEY, ts->input->evbit); + + /* Single touch input params setup */ +/* input_set_abs_params(ts->input, ABS_X, 0, ts->x_max, 0, 0); + input_set_abs_params(ts->input, ABS_Y, 0, ts->y_max, 0, 0); + input_set_abs_params(ts->input, ABS_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(ts->input, ABS_X, ts->x_res); + input_abs_set_res(ts->input, ABS_Y, ts->y_res); +*/ + + /* Multitouch input params setup */ + error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(&client->dev, + "failed to initialize MT slots: %d\n", error); + return error; + } + + input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, 0, 0); + input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, 0, 0); + input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); +/* input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);*/ + input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); + input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); + + input_set_drvdata(ts->input, ts); + + error = input_register_device(ts->input); + if (error) { + dev_err(&client->dev, + "unable to register input device: %d\n", error); + return error; + } + + /* + * Systems using device tree should set up interrupt via DTS, + * the rest will use the default falling edge interrupts. + */ + irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; + + error = devm_request_threaded_irq(&client->dev, client->irq, + NULL, elants_i2c_irq, + irqflags | IRQF_ONESHOT, + client->name, ts); + if (error) { + dev_err(&client->dev, "Failed to register interrupt\n"); + return error; + } + + /* + * Systems using device tree should set up wakeup via DTS, + * the rest will configure device as wakeup source by default. + */ + if (!client->dev.of_node) + device_init_wakeup(&client->dev, true); + + error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group); + if (error) { + dev_err(&client->dev, "failed to create sysfs attributes: %d\n", + error); + return error; + } + + error = devm_add_action(&client->dev, + elants_i2c_remove_sysfs_group, ts); + if (error) { + elants_i2c_remove_sysfs_group(ts); + dev_err(&client->dev, + "Failed to add sysfs cleanup action: %d\n", + error); + return error; + } + + return 0; +} + +static int __maybe_unused elants_i2c_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + const u8 set_sleep_cmd[] = { 0x54, 0x50, 0x00, 0x01 }; + int retry_cnt; + int error; + + /* Command not support in IAP recovery mode */ + if (ts->iap_mode != ELAN_IAP_OPERATIONAL) + return -EBUSY; + + disable_irq(client->irq); + + if (device_may_wakeup(dev)) { + /* + * The device will automatically enter idle mode + * that has reduced power consumption. + */ + ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); + } else if (ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_sleep_cmd, + sizeof(set_sleep_cmd)); + if (!error) + break; + + dev_err(&client->dev, + "suspend command failed: %d\n", error); + } + } else { + elants_i2c_power_off(ts); + } + + return 0; +} + +static int __maybe_unused elants_i2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct elants_data *ts = i2c_get_clientdata(client); + const u8 set_active_cmd[] = { 0x54, 0x58, 0x00, 0x01 }; + int retry_cnt; + int error; + + if (device_may_wakeup(dev)) { + if (ts->wake_irq_enabled) + disable_irq_wake(client->irq); + elants_i2c_sw_reset(client); + } else if (ts->keep_power_in_suspend) { + for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) { + error = elants_i2c_send(client, set_active_cmd, + sizeof(set_active_cmd)); + if (!error) + break; + + dev_err(&client->dev, + "resume command failed: %d\n", error); + } + } else { + elants_i2c_power_on(ts); + elants_i2c_initialize(ts); + } + + ts->state = ELAN_STATE_NORMAL; + enable_irq(client->irq); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops, + elants_i2c_suspend, elants_i2c_resume); + +static const struct i2c_device_id elants_i2c_id[] = { + { DEVICE_NAME, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, elants_i2c_id); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id elants_acpi_id[] = { + { "ELAN0001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, elants_acpi_id); +#endif + +#ifdef CONFIG_OF +static const struct of_device_id elants_of_match[] = { + { .compatible = "elan,ekth3500" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, elants_of_match); +#endif + +static struct i2c_driver elants_i2c_driver = { + .probe = elants_i2c_probe, + .id_table = elants_i2c_id, + .driver = { + .name = DEVICE_NAME, + .pm = &elants_i2c_pm_ops, + .acpi_match_table = ACPI_PTR(elants_acpi_id), + .of_match_table = of_match_ptr(elants_of_match), + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; +module_i2c_driver(elants_i2c_driver); + +MODULE_AUTHOR("Chuming Zhang "); +MODULE_DESCRIPTION("Elan I2c Touchscreen driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c index b3d7322f42cacbb41ca6ee582b5d484f400766c3..7639c9f119987a69d5d2d019838824f44305c336 100644 --- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c +++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c @@ -514,11 +514,11 @@ static int fts_input_dev_report_b(struct ts_event *event, #endif } else { uppoint++; - input_mt_report_slot_state(data->input_dev, - MT_TOOL_FINGER, false); #if FTS_REPORT_PRESSURE_EN input_report_abs(data->input_dev, ABS_MT_PRESSURE, 0); #endif + input_mt_report_slot_state(data->input_dev, + MT_TOOL_FINGER, false); data->touchs &= ~BIT(event->au8_finger_id[i]); FTS_DEBUG("[B]P%d UP!", event->au8_finger_id[i]); } diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 5907fddcc966ca54faf4c4cb537fe6f19238a2e4..c599b5a2373bf76f5eb65d1e826d04dfe37dff32 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -858,6 +858,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id); #ifdef CONFIG_ACPI static const struct acpi_device_id goodix_acpi_match[] = { { "GDIX1001", 0 }, + { "GDIX1002", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, goodix_acpi_match); diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Kconfig b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..7046cc9011a57712fd94c168951da20e40c1227b --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/Kconfig @@ -0,0 +1,36 @@ +# +# Goodix GT9xx Touchscreen driver +# +config TOUCHSCREEN_GT9XX_v28 + bool "Goodix touchpanel GT9xx series" + depends on I2C + help + Enable this for support Goodix GT9xx_v28 driver. + + Say Y here if you have a Goodix GT9xx touchscreen + controller. + + If unsure, say N. + +config TOUCHSCREEN_GT9XX_UPDATE + tristate "Goodix GT9xx touch controller auto update support" + depends on TOUCHSCREEN_GT9XX_v28 + help + Enable this for support firmware update. + + Say Y here if you want update touch controller + firmware. + + If unsure, say N. + +config TOUCHSCREEN_GT9XX_TOOL + tristate "Goodix GT9xx Tools for debuging" + depends on TOUCHSCREEN_GT9XX_v28 + help + This implement interface support for Goodix GT9xx + touchscreen debug. + + Say Y here if you want to have a Android app debug interface + to your system. + + If unsure, say N. diff --git a/drivers/input/touchscreen/gt9xx_v2.8/Makefile b/drivers/input/touchscreen/gt9xx_v2.8/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..6c1c4042ecfa2dfff427fae7aee0738d7d1e3011 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the Goodix gt9xx touchscreen driver. +# +#subdir-ccflags-y += -DDEBUG +obj-$(CONFIG_TOUCHSCREEN_GT9XX_v28) += gt9xx.o +obj-$(CONFIG_TOUCHSCREEN_GT9XX_UPDATE) += gt9xx_update.o +obj-$(CONFIG_TOUCHSCREEN_GT9XX_TOOL) += goodix_tool.o diff --git a/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c new file mode 100644 index 0000000000000000000000000000000000000000..7db5ae25488bc7a400b3844183874a1875fc0dd9 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/goodix_tool.c @@ -0,0 +1,529 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT 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 "gt9xx.h" + +#define DATA_LENGTH_UINT 512 +#define CMD_HEAD_LENGTH (sizeof(struct st_cmd_head) - sizeof(u8 *)) +static char procname[20] = {0}; + +#pragma pack(1) +struct st_cmd_head { + u8 wr; /*write read flag 0:R 1:W 2:PID 3:*/ + u8 flag; /*0:no need flag/int 1: need flag 2:need int*/ + u8 flag_addr[2]; /*flag address*/ + u8 flag_val; /*flag val*/ + u8 flag_relation; /*flag_val:flag 0:not equal 1:equal 2:> 3:<*/ + u16 circle; /*polling cycle*/ + u8 times; /*plling times*/ + u8 retry; /*I2C retry times*/ + u16 delay; /*delay before read or after write*/ + u16 data_len; /*data length*/ + u8 addr_len; /*address length*/ + u8 addr[2]; /*address*/ + u8 res[3]; /*reserved*/ + u8 *data; }; /*data pointer*/ +#pragma pack() +struct st_cmd_head cmd_head; + +static struct i2c_client *gt_client; +static struct proc_dir_entry *goodix_proc_entry; + +static ssize_t goodix_tool_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t goodix_tool_write(struct file *, const char __user *, + size_t, loff_t *); +static const struct file_operations gtp_proc_ops = { + .owner = THIS_MODULE, + .read = goodix_tool_read, + .write = goodix_tool_write, +}; + +/* static s32 goodix_tool_write(struct file *filp, + * const char __user *buff, unsigned long len, void *data); + */ +/*static s32 goodix_tool_read( char *page, char + **start, off_t off, int count, int *eof, void *data ); + */ +static s32 (*tool_i2c_read)(u8 *, u16); +static s32 (*tool_i2c_write)(u8 *, u16); + +static s32 DATA_LENGTH = (s32)0; +static s8 IC_TYPE[16] = "GT9XX"; + +static void tool_set_proc_name(char *procname) +{ + snprintf(procname, 20, "gmnode"); /* modify for moto */ +} + +static s32 tool_i2c_read_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + for (i = 0; i < cmd_head.retry; i++) { + ret = gtp_i2c_read(ts->client, buf, len + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + return ret; +} + +static s32 tool_i2c_write_no_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + s32 i = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + for (i = 0; i < cmd_head.retry; i++) { + ret = gtp_i2c_write(ts->client, buf, len); + if (ret > 0) + break; + } + + return ret; +} + +static s32 tool_i2c_read_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_read_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static s32 tool_i2c_write_with_extra(u8 *buf, u16 len) +{ + s32 ret = -1; + u8 pre[2] = {0x0f, 0xff}; + u8 end[2] = {0x80, 0x00}; + + tool_i2c_write_no_extra(pre, 2); + ret = tool_i2c_write_no_extra(buf, len); + tool_i2c_write_no_extra(end, 2); + + return ret; +} + +static void register_i2c_func(void) +{ + /* if (!strcmp(IC_TYPE, "GT818", 5) + * || !strcmp(IC_TYPE, "GT816", 5) + * || !strcmp(IC_TYPE, "GT811", 5) + * || !strcmp(IC_TYPE, "GT818F", 6) + * || !strcmp(IC_TYPE, "GT827", 5) + * || !strcmp(IC_TYPE,"GT828", 5) + * || !strcmp(IC_TYPE, "GT813", 5)) + */ + if (strcmp(IC_TYPE, "GT8110") && + strcmp(IC_TYPE, "GT8105") && + strcmp(IC_TYPE, "GT801") && + strcmp(IC_TYPE, "GT800") && + strcmp(IC_TYPE, "GT801PLUS") && + strcmp(IC_TYPE, "GT811") && + strcmp(IC_TYPE, "GTxxx") && + strcmp(IC_TYPE, "GT9XX")) { + tool_i2c_read = tool_i2c_read_with_extra; + tool_i2c_write = tool_i2c_write_with_extra; + dev_dbg(>_client->dev, "I2C function: with pre and end cmd!"); + } else { + tool_i2c_read = tool_i2c_read_no_extra; + tool_i2c_write = tool_i2c_write_no_extra; + dev_info(>_client->dev, "I2C function: without pre and end cmd!"); + } +} + +static void unregister_i2c_func(void) +{ + tool_i2c_read = NULL; + tool_i2c_write = NULL; + dev_info(>_client->dev, "I2C function: unregister i2c transfer function!"); +} + +s32 init_wr_node(struct i2c_client *client) +{ + s32 i; + + gt_client = client; + memset(&cmd_head, 0, sizeof(cmd_head)); + cmd_head.data = NULL; + + i = 6; + while ((!cmd_head.data) && i) { + cmd_head.data = kzalloc(i * DATA_LENGTH_UINT, GFP_KERNEL); + if (cmd_head.data) + break; + i--; + } + if (i) { + DATA_LENGTH = i * DATA_LENGTH_UINT - GTP_ADDR_LENGTH; + dev_info(>_client->dev, + "Alloc memory size:%d.", DATA_LENGTH); + } else { + dev_err(>_client->dev, "Apply for memory failed."); + return FAIL; + } + + cmd_head.addr_len = 2; + cmd_head.retry = 5; + + register_i2c_func(); + + tool_set_proc_name(procname); + goodix_proc_entry = proc_create(procname, 0664, NULL, >p_proc_ops); + if (!goodix_proc_entry) { + dev_err(>_client->dev, "Couldn't create proc entry!"); + return FAIL; + } + + dev_info(>_client->dev, "Create proc entry success!"); + return SUCCESS; +} + +void uninit_wr_node(void) +{ + kfree(cmd_head.data); + cmd_head.data = NULL; + unregister_i2c_func(); + remove_proc_entry(procname, NULL); +} + +static u8 relation(u8 src, u8 dst, u8 rlt) +{ + u8 ret = 0; + + switch (rlt) { + case 0: + ret = (src != dst) ? true : false; + break; + + case 1: + ret = (src == dst) ? true : false; + dev_dbg(>_client->dev, + "equal:src:0x%02x dst:0x%02x ret:%d.", + src, dst, (s32)ret); + break; + + case 2: + ret = (src > dst) ? true : false; + break; + + case 3: + ret = (src < dst) ? true : false; + break; + + case 4: + ret = (src & dst) ? true : false; + break; + + case 5: + ret = (!(src | dst)) ? true : false; + break; + + default: + ret = false; + break; + } + + return ret; +} + +/******************************************************* + * Function: + * Comfirm function. + * Input: + * None. + * Output: + * Return write length. + ********************************************************/ +static u8 comfirm(void) +{ + s32 i = 0; + u8 buf[32]; + + memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len); + + for (i = 0; i < cmd_head.times; i++) { + if (tool_i2c_read(buf, 1) <= 0) { + dev_err(>_client->dev, "Read flag data failed!"); + return FAIL; + } + if (true == relation(buf[GTP_ADDR_LENGTH], + cmd_head.flag_val, cmd_head.flag_relation)) { + dev_dbg(>_client->dev, "value at flag addr:0x%02x.", + buf[GTP_ADDR_LENGTH]); + dev_dbg(>_client->dev, "flag value:0x%02x.", + cmd_head.flag_val); + break; + } + + msleep(cmd_head.circle); + } + + if (i >= cmd_head.times) { + dev_err(>_client->dev, "Can't get the continue flag!"); + return FAIL; + } + + return SUCCESS; +} + +ssize_t goodix_tool_write(struct file *filp, const char __user *buff, + size_t len, loff_t *off) +{ + s32 ret = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(gt_client); + + ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + + dev_dbg(>_client->dev, "[Operation]wr: %02X", cmd_head.wr); + dev_dbg(>_client->dev, + "[Flag]flag: %02X,addr: %02X%02X,value: %02X,relation: %02X", + cmd_head.flag, cmd_head.flag_addr[0], + cmd_head.flag_addr[1], cmd_head.flag_val, + cmd_head.flag_relation); + dev_dbg(>_client->dev, + "[Retry]circle: %d,times: %d,retry: %d, delay: %d", + (s32)cmd_head.circle, + (s32)cmd_head.times, (s32)cmd_head.retry, + (s32)cmd_head.delay); + + if (cmd_head.wr == 1) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + memcpy(&cmd_head.data[GTP_ADDR_LENGTH - cmd_head.addr_len], + cmd_head.addr, cmd_head.addr_len); + + GTP_DEBUG_ARRAY(cmd_head.data, cmd_head.data_len + + cmd_head.addr_len); + + if (cmd_head.flag == 1) { + if (comfirm() == FAIL) { + dev_err(>_client->dev, + "[WRITE]Comfirm fail!"); + return -EPERM; + } + } else if (cmd_head.flag == 2) { + /*Need interrupt!*/ + } + if (tool_i2c_write(&cmd_head.data[GTP_ADDR_LENGTH - + cmd_head.addr_len], cmd_head.data_len + + cmd_head.addr_len) <= 0) { + dev_err(>_client->dev, "[WRITE]Write data failed!"); + return -EPERM; + } + + GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH - + cmd_head.addr_len], + cmd_head.data_len + cmd_head.addr_len); + if (cmd_head.delay) + msleep(cmd_head.delay); + } else if (cmd_head.wr == 3) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[0], &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_err(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len); + + register_i2c_func(); + } else if (cmd_head.wr == 5) { + /*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/ + } else if (cmd_head.wr == 7) {/*disable irq!*/ + gtp_work_control_enable(i2c_get_clientdata(gt_client), false); + + if (ts->pdata->esd_protect) + gtp_esd_off(ts); + } else if (cmd_head.wr == 9) {/*enable irq!*/ + gtp_work_control_enable(i2c_get_clientdata(gt_client), true); + + if (ts->pdata->esd_protect) + gtp_esd_on(ts); + } else if (cmd_head.wr == 17) { + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_dbg(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + if (cmd_head.data[GTP_ADDR_LENGTH]) { + dev_info(>_client->dev, "gtp enter rawdiff."); + set_bit(RAW_DATA_MODE, &ts->flags); + } else { + clear_bit(RAW_DATA_MODE, &ts->flags); + dev_info(>_client->dev, "gtp leave rawdiff."); + } + } else if (cmd_head.wr == 19) { + /* add new command: reset guitar */ + gtp_reset_guitar(gt_client, 20); + } +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + else if (cmd_head.wr == 11) {/*Enter update mode!*/ + if (gup_enter_update_mode(gt_client) == FAIL) + return -EPERM; + } else if (cmd_head.wr == 13) {/*Leave update mode!*/ + gup_leave_update_mode(gt_client); + } else if (cmd_head.wr == 15) {/*Update firmware!*/ + show_len = 0; + total_len = 0; + if (cmd_head.data_len > DATA_LENGTH) { + dev_err(>_client->dev, + "Tool write failed data too long"); + return -EPERM; + } + memset(cmd_head.data, 0, DATA_LENGTH); + ret = copy_from_user(cmd_head.data, + &buff[CMD_HEAD_LENGTH], + cmd_head.data_len); + if (ret) { + dev_dbg(>_client->dev, "copy_from_user failed."); + return -EPERM; + } + + if (gup_update_proc((void *)cmd_head.data) == FAIL) + return -EPERM; + } +#endif + + return len; +} + +/******************************************************* + * Function: + * Goodix tool read function. + * Input: + * standard proc read function param. + * Output: + * Return read length. + ********************************************************/ +ssize_t goodix_tool_read(struct file *file, char __user *page, + size_t size, loff_t *ppos) +{ + s32 ret = 0; + + if (*ppos) { + /* ADB call again + * dev_dbg(>_client->dev, "[HEAD]wr: %d", cmd_head.wr); + * dev_dbg(>_client->dev, + * "[PARAM]size: %d, *ppos: %d", size, (int)*ppos); + * dev_dbg(>_client->dev, + * "[TOOL_READ]ADB call again, return it."); + */ + *ppos = 0; + return 0; + } + + if (cmd_head.wr % 2) { + return -EPERM; + } else if (!cmd_head.wr) { + u16 len, data_len, loc, addr; + + if (cmd_head.flag == 1) { + if (comfirm() == FAIL) { + dev_err(>_client->dev, "[READ]Comfirm fail!"); + return -EPERM; + } + } else if (cmd_head.flag == 2) { + /*Need interrupt!*/ + } + + if (cmd_head.delay) + msleep(cmd_head.delay); + + data_len = cmd_head.data_len; + addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1]; + loc = 0; + + while (data_len > 0) { + len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len; + cmd_head.data[0] = (addr >> 8) & 0xFF; + cmd_head.data[1] = (addr & 0xFF); + if (tool_i2c_read(cmd_head.data, len) <= 0) { + dev_err(>_client->dev, "[READ]Read data failed!"); + return -EPERM; + } + ret = simple_read_from_buffer(&page[loc], size, ppos, + &cmd_head.data[GTP_ADDR_LENGTH], len); + if (ret < 0) + return ret; + loc += len; + addr += len; + data_len -= len; + } + return cmd_head.data_len; + } else if (cmd_head.wr == 2) { + ret = simple_read_from_buffer(page, size, ppos, + IC_TYPE, sizeof(IC_TYPE)); + return ret; + } +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + else if (cmd_head.wr == 4) { + u8 progress_buf[4]; + + progress_buf[0] = show_len >> 8; + progress_buf[1] = show_len & 0xff; + progress_buf[2] = total_len >> 8; + progress_buf[3] = total_len & 0xff; + + ret = simple_read_from_buffer(page, size, ppos, + progress_buf, 4); + return ret; + } +#endif + else if (cmd_head.wr == 6) { + /*Read error code!*/ + } else if (cmd_head.wr == 8) { /*Read driver version*/ + ret = simple_read_from_buffer(page, size, ppos, + GTP_DRIVER_VERSION, + strlen(GTP_DRIVER_VERSION)); + return ret; + } + + return -EPERM; +} diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c new file mode 100644 index 0000000000000000000000000000000000000000..03328d040539665cf25c97e5e8fb4217fbc9ef6b --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.c @@ -0,0 +1,2678 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include +#include +#include +#include +#include "gt9xx.h" + +#define GOODIX_VTG_MIN_UV 2600000 +#define GOODIX_VTG_MAX_UV 3300000 +#define GOODIX_I2C_VTG_MIN_UV 1800000 +#define GOODIX_I2C_VTG_MAX_UV 1800000 + +#define DELAY_FOR_DISCHARGING 35 +#define GOODIX_COORDS_ARR_SIZE 4 +#define PROP_NAME_SIZE 24 +#define I2C_MAX_TRANSFER_SIZE 255 +#define GTP_PEN_BUTTON1 BTN_STYLUS +#define GTP_PEN_BUTTON2 BTN_STYLUS2 + +static const char *goodix_ts_name = "goodix-ts"; +static const char *goodix_input_phys = "input/ts"; +struct i2c_client *i2c_connect_client; +static struct proc_dir_entry *gtp_config_proc; + +enum doze { + DOZE_DISABLED = 0, + DOZE_ENABLED = 1, + DOZE_WAKEUP = 2, +}; + +static enum doze doze_status = DOZE_DISABLED; + +static int gtp_i2c_test(struct i2c_client *client); +static int gtp_enter_doze(struct goodix_ts_data *ts); + +static int gtp_unregister_powermanager(struct goodix_ts_data *ts); +static int gtp_register_powermanager(struct goodix_ts_data *ts); + +static int gtp_esd_init(struct goodix_ts_data *ts); +static void gtp_esd_check_func(struct work_struct *); +static int gtp_init_ext_watchdog(struct i2c_client *client); + +/* + * return: 2 - ok, < 0 - i2c transfer error + */ +int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len) +{ + unsigned int transfer_length = 0; + unsigned int pos = 0, address = (buf[0] << 8) + buf[1]; + unsigned char get_buf[64], addr_buf[2]; + int retry, r = 2; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = !I2C_M_RD, + .buf = &addr_buf[0], + .len = GTP_ADDR_LENGTH, + }, { + .addr = client->addr, + .flags = I2C_M_RD, + } + }; + + len -= GTP_ADDR_LENGTH; + if (likely(len < sizeof(get_buf))) { + /* code optimize, use stack memory */ + msgs[1].buf = &get_buf[0]; + } else { + msgs[1].buf = kzalloc(len > I2C_MAX_TRANSFER_SIZE + ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); + if (!msgs[1].buf) + return -ENOMEM; + } + + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE)) + transfer_length = I2C_MAX_TRANSFER_SIZE; + else + transfer_length = len - pos; + msgs[0].buf[0] = (address >> 8) & 0xFF; + msgs[0].buf[1] = address & 0xFF; + msgs[1].len = transfer_length; + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, + msgs, 2) == 2)) { + memcpy(&buf[2 + pos], msgs[1].buf, + transfer_length); + pos += transfer_length; + address += transfer_length; + break; + } + dev_dbg(&client->dev, "I2c read retry[%d]:0x%x\n", + retry + 1, address); + usleep_range(2000, 2100); + } + if (unlikely(retry == RETRY_MAX_TIMES)) { + dev_err(&client->dev, + "I2c read failed,dev:%02x,reg:%04x,size:%u\n", + client->addr, address, len); + r = -EAGAIN; + goto read_exit; + } + } +read_exit: + if (len >= sizeof(get_buf)) + kfree(msgs[1].buf); + return r; +} + +/******************************************************* + * Function: + * Write data to the i2c slave device. + * Input: + * client: i2c device. + * buf[0~1]: write start address. + * buf[2~len-1]: data buffer + * len: GTP_ADDR_LENGTH + write bytes count + * Output: + * numbers of i2c_msgs to transfer: + * 1: succeed, otherwise: failed + *********************************************************/ +int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len) + +{ + unsigned int pos = 0, transfer_length = 0; + unsigned int address = (buf[0] << 8) + buf[1]; + unsigned char put_buf[64]; + int retry, r = 1; + struct i2c_msg msg = { + .addr = client->addr, + .flags = !I2C_M_RD, + }; + + if (likely(len < sizeof(put_buf))) { + /* code optimize,use stack memory*/ + msg.buf = &put_buf[0]; + } else { + msg.buf = kmalloc(len > I2C_MAX_TRANSFER_SIZE + ? I2C_MAX_TRANSFER_SIZE : len, GFP_KERNEL); + if (!msg.buf) + return -ENOMEM; + } + + len -= GTP_ADDR_LENGTH; + while (pos != len) { + if (unlikely(len - pos > I2C_MAX_TRANSFER_SIZE + - GTP_ADDR_LENGTH)) + transfer_length = I2C_MAX_TRANSFER_SIZE + - GTP_ADDR_LENGTH; + else + transfer_length = len - pos; + msg.buf[0] = (unsigned char)((address >> 8) & 0xFF); + msg.buf[1] = (unsigned char)(address & 0xFF); + msg.len = transfer_length + 2; + memcpy(&msg.buf[2], &buf[2 + pos], transfer_length); + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + if (likely(i2c_transfer(client->adapter, + &msg, 1) == 1)) { + pos += transfer_length; + address += transfer_length; + break; + } + dev_dbg(&client->dev, "I2C write retry[%d]\n", + retry + 1); + usleep_range(2000, 2100); + } + if (unlikely(retry == RETRY_MAX_TIMES)) { + dev_err(&client->dev, + "I2c write failed,dev:%02x,reg:%04x,size:%u\n", + client->addr, address, len); + r = -EAGAIN; + goto write_exit; + } + } +write_exit: + if (len + GTP_ADDR_LENGTH >= sizeof(put_buf)) + kfree(msg.buf); + return r; +} + +/******************************************************* + * Function: + * i2c read twice, compare the results + * Input: + * client: i2c device + * addr: operate address + * rxbuf: read data to store, if compare successful + * len: bytes to read + * Output: + * FAIL: read failed + * SUCCESS: read successful + *********************************************************/ +s32 gtp_i2c_read_dbl_check(struct i2c_client *client, + u16 addr, u8 *rxbuf, int len) +{ + u8 buf[16] = {0}; + u8 confirm_buf[16] = {0}; + u8 retry = 0; + + if (len + 2 > sizeof(buf)) { + dev_warn(&client->dev, + "%s, only support length less then %zu\n", + __func__, sizeof(buf) - 2); + return FAIL; + } + while (retry++ < 3) { + memset(buf, 0xAA, 16); + buf[0] = (u8)(addr >> 8); + buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, buf, len + 2); + + memset(confirm_buf, 0xAB, 16); + confirm_buf[0] = (u8)(addr >> 8); + confirm_buf[1] = (u8)(addr & 0xFF); + gtp_i2c_read(client, confirm_buf, len + 2); + + if (!memcmp(buf, confirm_buf, len + 2)) { + memcpy(rxbuf, confirm_buf + 2, len); + return SUCCESS; + } + } + dev_err(&client->dev, + "I2C read 0x%04X, %d bytes, double check failed!\n", + addr, len); + + return FAIL; +} + +/******************************************************* + * Function: + * Send config. + * Input: + * client: i2c device. + * Output: + * result of i2c write operation. + * 1: succeed, otherwise + * 0: Not executed + * < 0: failed + *********************************************************/ +s32 gtp_send_cfg(struct i2c_client *client) +{ + s32 ret, i; + u8 check_sum; + s32 retry = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + struct goodix_config_data *cfg = &ts->pdata->config; + + if (!cfg->length || !ts->pdata->driver_send_cfg) { + dev_info(&ts->client->dev, + "No config data or error occurred in panel_init\n"); + return 0; + } + + check_sum = 0; + for (i = GTP_ADDR_LENGTH; i < cfg->length; i++) + check_sum += cfg->data[i]; + cfg->data[cfg->length] = (~check_sum) + 1; + + dev_info(&ts->client->dev, "Driver send config\n"); + for (retry = 0; retry < RETRY_MAX_TIMES; retry++) { + ret = gtp_i2c_write(client, cfg->data, + GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH); + if (ret > 0) + break; + } + + return ret; +} + +/******************************************************* + * Function: + * Control enable or disable of work thread. + * Input: + * ts: goodix i2c_client private data + * enable: enable var. + *********************************************************/ +void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable) +{ + if (enable) { + set_bit(REPORT_THREAD_ENABLED, &ts->flags); + dev_dbg(&ts->client->dev, "Input report thread enabled!\n"); + } else { + clear_bit(REPORT_THREAD_ENABLED, &ts->flags); + dev_dbg(&ts->client->dev, "Input report thread disabled!\n"); + } +} + +static int gtp_gesture_handler(struct goodix_ts_data *ts) +{ + u8 doze_buf[3] = {GTP_REG_DOZE_BUF >> 8, GTP_REG_DOZE_BUF & 0xFF}; + int ret; + + ret = gtp_i2c_read(ts->client, doze_buf, 3); + if (ret < 0) { + dev_err(&ts->client->dev, "Failed read doze buf"); + return -EINVAL; + } + + dev_dbg(&ts->client->dev, "0x814B = 0x%02X", doze_buf[2]); + if ((doze_buf[2] == 'a') || (doze_buf[2] == 'b') || + (doze_buf[2] == 'c') || (doze_buf[2] == 'd') || + (doze_buf[2] == 'e') || (doze_buf[2] == 'g') || + (doze_buf[2] == 'h') || (doze_buf[2] == 'm') || + (doze_buf[2] == 'o') || (doze_buf[2] == 'q') || + (doze_buf[2] == 's') || (doze_buf[2] == 'v') || + (doze_buf[2] == 'w') || (doze_buf[2] == 'y') || + (doze_buf[2] == 'z') || (doze_buf[2] == 0x5E) || + (doze_buf[2] == 0xAA) || (doze_buf[2] == 0xAB) || + (doze_buf[2] == 0xBA) || (doze_buf[2] == 0xBB) || + (doze_buf[2] == 0xCC)) { + doze_status = DOZE_WAKEUP; + input_report_key(ts->input_dev, KEY_POWER, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, KEY_POWER, 0); + input_sync(ts->input_dev); + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + } else { + /* clear 0x814B */ + doze_buf[2] = 0x00; + gtp_i2c_write(ts->client, doze_buf, 3); + gtp_enter_doze(ts); + } + return 0; +} + +/* + * return touch state register value + * pen event id fixed with 9 and set tool type TOOL_PEN + * + */ +static u8 gtp_get_points(struct goodix_ts_data *ts, + struct goodix_point_t *points, + u8 *key_value) +{ + int ret; + int i; + u8 *coor_data = NULL; + u8 finger_state = 0; + u8 touch_num = 0; + u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8, + GTP_READ_COOR_ADDR & 0xFF, 0 }; + u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH_ID + 1] = { + GTP_READ_COOR_ADDR >> 8, GTP_READ_COOR_ADDR & 0xFF }; + + ret = gtp_i2c_read(ts->client, point_data, 12); + if (ret < 0) { + dev_err(&ts->client->dev, + "I2C transfer error. errno:%d\n ", ret); + return 0; + } + finger_state = point_data[GTP_ADDR_LENGTH]; + if (finger_state == 0x00) + return 0; + + touch_num = finger_state & 0x0f; + if ((finger_state & MASK_BIT_8) == 0 || + touch_num > ts->pdata->max_touch_id) { + dev_err(&ts->client->dev, + "Invalid touch state: 0x%x", finger_state); + finger_state = 0; + goto exit_get_point; + } + + if (touch_num > 1) { + u8 buf[8 * GTP_MAX_TOUCH_ID] = { + (GTP_READ_COOR_ADDR + 10) >> 8, + (GTP_READ_COOR_ADDR + 10) & 0xff }; + + ret = gtp_i2c_read(ts->client, buf, 2 + 8 * (touch_num - 1)); + if (ret < 0) { + dev_err(&ts->client->dev, "I2C error. %d\n", ret); + finger_state = 0; + goto exit_get_point; + } + memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1)); + } + + /* panel have touch key */ + /* 0x20_UPKEY 0X10_DOWNKEY 0X40_ALLKEYDOWN */ + *key_value = point_data[3 + 8 * touch_num]; + + memset(points, 0, sizeof(*points) * GTP_MAX_TOUCH_ID); + for (i = 0; i < touch_num; i++) { + coor_data = &point_data[i * 8 + 3]; + points[i].id = coor_data[0]; + points[i].x = coor_data[1] | (coor_data[2] << 8); + points[i].y = coor_data[3] | (coor_data[4] << 8); + points[i].w = coor_data[5] | (coor_data[6] << 8); + /* if pen hover points[].p must set to zero */ + points[i].p = coor_data[5] | (coor_data[6] << 8); + + if (ts->pdata->swap_x2y) + GTP_SWAP(points[i].x, points[i].y); + + dev_dbg(&ts->client->dev, "[%d][%d %d %d]\n", + points[i].id, points[i].x, points[i].y, points[i].p); + + /* pen device coordinate */ + if (points[i].id & 0x80) { + points[i].tool_type = GTP_TOOL_PEN; + points[i].id = 10; + if (ts->pdata->pen_suppress_finger) { + points[0] = points[i]; + memset(++points, 0, sizeof(*points) * + (GTP_MAX_TOUCH_ID - 1)); + finger_state &= 0xf0; + finger_state |= 0x01; + break; + } + } else { + points[i].tool_type = GTP_TOOL_FINGER; + } + } + +exit_get_point: + if (!test_bit(RAW_DATA_MODE, &ts->flags)) { + ret = gtp_i2c_write(ts->client, end_cmd, 3); + if (ret < 0) + dev_info(&ts->client->dev, "I2C write end_cmd error!"); + } + return finger_state; +} + +static void gtp_type_a_report(struct goodix_ts_data *ts, u8 touch_num, + struct goodix_point_t *points) +{ + int i; + u16 cur_touch = 0; + static u16 pre_touch; + static u8 pre_pen_id; + + if (touch_num) + input_report_key(ts->input_dev, BTN_TOUCH, 1); + + for (i = 0; i < ts->pdata->max_touch_id; i++) { + if (touch_num && i == points->id) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, points->id); + + if (points->tool_type == GTP_TOOL_PEN) { + input_report_key(ts->input_dev, + BTN_TOOL_PEN, true); + pre_pen_id = points->id; + } else { + input_report_key(ts->input_dev, + BTN_TOOL_FINGER, true); + } + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + points->x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + points->y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + points->w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + points->p); + input_mt_sync(ts->input_dev); + + cur_touch |= 0x01 << points->id; + points++; + } else if (pre_touch & 0x01 << i) { + if (pre_pen_id == i) { + input_report_key(ts->input_dev, + BTN_TOOL_PEN, false); +/* valid id will < 10, so id to 0xff to indicate a invalid state */ + pre_pen_id = 0xff; + } else { + input_report_key(ts->input_dev, + BTN_TOOL_FINGER, false); + } + } + } + + pre_touch = cur_touch; + if (!pre_touch) { + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + } + input_sync(ts->input_dev); +} + +static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num, + struct goodix_point_t *points) +{ + int i; + u16 cur_touch = 0; + static u16 pre_touch; + static u8 pre_pen_id; + + for (i = 0; i < ts->pdata->max_touch_id; i++) { + if (touch_num && i == points->id) { + input_mt_slot(ts->input_dev, points->id); + + if (points->tool_type == GTP_TOOL_PEN) { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_PEN, true); + pre_pen_id = points->id; + } else { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, true); + } + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + points->x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + points->y); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + points->w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + points->p); + + cur_touch |= 0x01 << points->id; + points++; + } else if (pre_touch & 0x01 << i) { + input_mt_slot(ts->input_dev, i); + if (pre_pen_id == i) { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_PEN, false); + /* valid id will < 10, so set id to 0xff to + * indicate a invalid state + */ + pre_pen_id = 0xff; + } else { + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, false); + } + } + } + + pre_touch = cur_touch; + /* report BTN_TOUCH event */ + input_mt_sync_frame(ts->input_dev); + input_sync(ts->input_dev); +} + +/******************************************************* + * Function: + * Goodix touchscreen sensor report function + * Input: + * ts: goodix tp private data + * Output: + * None. + *********************************************************/ +static void gtp_work_func(struct goodix_ts_data *ts) +{ + u8 point_state = 0; + u8 key_value = 0; + s32 i = 0; + s32 ret = -1; + static u8 pre_key; + struct goodix_point_t points[GTP_MAX_TOUCH_ID]; + + if (test_bit(PANEL_RESETTING, &ts->flags)) + return; + if (!test_bit(REPORT_THREAD_ENABLED, &ts->flags)) + return; + + /* gesture event */ + if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { + ret = gtp_gesture_handler(ts); + if (ret) + dev_err(&ts->client->dev, + "Failed handler gesture event %d\n", ret); + return; + } + + point_state = gtp_get_points(ts, points, &key_value); + if (!point_state) { + dev_dbg(&ts->client->dev, "Invalid finger points\n"); + return; + } + + /* touch key event */ + if (key_value & 0xf0 || pre_key & 0xf0) { + /* pen button */ + switch (key_value) { + case 0x40: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); + break; + case 0x10: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 1); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); + dev_dbg(&ts->client->dev, "pen button1 down\n"); + break; + case 0x20: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 1); + break; + default: + input_report_key(ts->input_dev, GTP_PEN_BUTTON1, 0); + input_report_key(ts->input_dev, GTP_PEN_BUTTON2, 0); + dev_dbg(&ts->client->dev, "button1 up\n"); + break; + } + input_sync(ts->input_dev); + pre_key = key_value; + } else if (key_value & 0x0f || pre_key & 0x0f) { + /* panel key */ + for (i = 0; i < ts->pdata->key_nums; i++) { + if ((pre_key | key_value) & (0x01 << i)) + input_report_key(ts->input_dev, + ts->pdata->key_map[i], + key_value & (0x01 << i)); + } + input_sync(ts->input_dev); + pre_key = key_value; + } + + if (!ts->pdata->type_a_report) + gtp_mt_slot_report(ts, point_state & 0x0f, points); + else + gtp_type_a_report(ts, point_state & 0x0f, points); +} + +/******************************************************* + * Function: + * Timer interrupt service routine for polling mode. + * Input: + * timer: timer struct pointer + * Output: + * Timer work mode. + * HRTIMER_NORESTART: + * no restart mode + *********************************************************/ +static enum hrtimer_restart gtp_timer_handler(struct hrtimer *timer) +{ + struct goodix_ts_data *ts = + container_of(timer, struct goodix_ts_data, timer); + + gtp_work_func(ts); + hrtimer_start(&ts->timer, ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), + HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +static irqreturn_t gtp_irq_handler(int irq, void *dev_id) +{ + struct goodix_ts_data *ts = dev_id; + + gtp_work_func(ts); + return IRQ_HANDLED; +} + +void gtp_int_output(struct goodix_ts_data *ts, int level) +{ + if (!ts->pdata->int_sync) + return; + + if (level == 0) { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_out_low); + else if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_output(ts->pdata->irq_gpio, 0); + else + dev_err(&ts->client->dev, + "Failed set int pin output low\n"); + } else { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_out_high); + else if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_output(ts->pdata->irq_gpio, 1); + else + dev_err(&ts->client->dev, + "Failed set int pin output high\n"); + } +} + +void gtp_int_sync(struct goodix_ts_data *ts, s32 ms) +{ + if (!ts->pdata->int_sync) + return; + + if (ts->pinctrl.pinctrl) { + gtp_int_output(ts, 0); + msleep(ms); + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_input); + } else if (gpio_is_valid(ts->pdata->irq_gpio)) { + gpio_direction_output(ts->pdata->irq_gpio, 0); + msleep(ms); + gpio_direction_input(ts->pdata->irq_gpio); + } else { + dev_err(&ts->client->dev, "Failed sync int pin\n"); + } +} + +void gtp_rst_output(struct goodix_ts_data *ts, int level) +{ + if (level == 0) { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.rst_out_low); + else if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_direction_output(ts->pdata->rst_gpio, 0); + else + dev_err(&ts->client->dev, + "Failed set rst pin output low\n"); + } else { + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.rst_out_high); + else if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_direction_output(ts->pdata->rst_gpio, 1); + else + dev_err(&ts->client->dev, + "Failed set rst pin output high\n"); + } +} + +void gtp_rst_input(struct goodix_ts_data *ts) +{ + if (ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.rst_input); + else if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_direction_input(ts->pdata->rst_gpio); + else + dev_err(&ts->client->dev, + "Failed set rst pin input\n"); +} + +/******************************************************* + * Function: + * Reset chip. Control the reset pin and int-pin(if + * defined), + * Input: + * client: i2c device. + * ms: reset time in millisecond + * Output: + * None. + *******************************************************/ +void gtp_reset_guitar(struct i2c_client *client, s32 ms) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + dev_info(&client->dev, "Guitar reset"); + set_bit(PANEL_RESETTING, &ts->flags); + if (!gpio_is_valid(ts->pdata->rst_gpio)) { + dev_warn(&client->dev, "reset failed no valid reset gpio"); + return; + } + + gtp_rst_output(ts, 0); + usleep_range(ms * 1000, ms * 1000 + 100); /* T2: > 10ms */ + + gtp_int_output(ts, client->addr == 0x14); + + usleep_range(2000, 3000); /* T3: > 100us (2ms)*/ + gtp_rst_output(ts, 1); + + usleep_range(6000, 7000); /* T4: > 5ms */ + gtp_rst_input(ts); + + gtp_int_sync(ts, 50); + if (ts->pdata->esd_protect) + gtp_init_ext_watchdog(client); + + clear_bit(PANEL_RESETTING, &ts->flags); +} + +/******************************************************* + * Function: + * Enter doze mode for sliding wakeup. + * Input: + * ts: goodix tp private data + * Output: + * 1: succeed, otherwise failed + *******************************************************/ +static int gtp_enter_doze(struct goodix_ts_data *ts) +{ + int ret = -1; + int retry = 0; + u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), + (u8)GTP_REG_COMMAND, 8 }; + + /* resend doze command + * if (test_and_set_bit(DOZE_MODE, &ts->flags)) { + * dev_info(&ts->client->dev, "Already in doze mode\n"); + * return SUCCESS; + * } + */ + set_bit(DOZE_MODE, &ts->flags); + dev_dbg(&ts->client->dev, "Entering gesture mode."); + while (retry++ < 5) { + i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8); + i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret < 0) { + dev_dbg(&ts->client->dev, + "failed to set doze flag into 0x8046, %d\n", + retry); + continue; + } + i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8); + i2c_control_buf[1] = (u8)GTP_REG_COMMAND; + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + dev_dbg(&ts->client->dev, "Gesture mode enabled\n"); + return ret; + } + usleep_range(10000, 11000); + } + + dev_err(&ts->client->dev, "Failed enter doze mode\n"); + clear_bit(DOZE_MODE, &ts->flags); + return ret; +} + +static s8 gtp_enter_sleep(struct goodix_ts_data *ts) +{ + s8 ret = -1; + s8 retry = 0; + u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8), + (u8)GTP_REG_COMMAND, 5 }; + + gtp_int_output(ts, 0); + usleep_range(5000, 6000); + + while (retry++ < 5) { + ret = gtp_i2c_write(ts->client, i2c_control_buf, 3); + if (ret > 0) { + dev_info(&ts->client->dev, "Enter sleep mode\n"); + + return ret; + } + usleep_range(10000, 11000); + } + dev_err(&ts->client->dev, "Failed send sleep cmd\n"); + + return ret; +} + +static int gtp_wakeup_sleep(struct goodix_ts_data *ts) +{ + u8 retry = 0; + int ret = -1; + + while (retry++ < 10) { + gtp_int_output(ts, 1); + usleep_range(5000, 6000); + + ret = gtp_i2c_test(ts->client); + if (!ret) { + dev_dbg(&ts->client->dev, "Success wakeup sleep\n"); + + gtp_int_sync(ts, 25); + if (ts->pdata->esd_protect) + gtp_init_ext_watchdog(ts->client); + + return ret; + } + gtp_reset_guitar(ts->client, 20); + } + + dev_err(&ts->client->dev, "Failed wakeup from sleep mode\n"); + return -EINVAL; +} + +static int gtp_find_valid_cfg_data(struct goodix_ts_data *ts) +{ + int ret = -1; + u8 sensor_id = 0; + struct goodix_config_data *cfg = &ts->pdata->config; + + /* if defined CONFIG_OF, parse config data from dtsi + * else parse config data form header file. + */ + cfg->length = 0; + +#ifndef CONFIG_OF + u8 cfg_info_group0[] = CTP_CFG_GROUP0; + u8 cfg_info_group1[] = CTP_CFG_GROUP1; + u8 cfg_info_group2[] = CTP_CFG_GROUP2; + u8 cfg_info_group3[] = CTP_CFG_GROUP3; + u8 cfg_info_group4[] = CTP_CFG_GROUP4; + u8 cfg_info_group5[] = CTP_CFG_GROUP5; + + u8 *send_cfg_buf[] = { cfg_info_group0, cfg_info_group1, + cfg_info_group2, cfg_info_group3, + cfg_info_group4, cfg_info_group5 }; + u8 cfg_info_len[] = { CFG_GROUP_LEN(cfg_info_group0), + CFG_GROUP_LEN(cfg_info_group1), + CFG_GROUP_LEN(cfg_info_group2), + CFG_GROUP_LEN(cfg_info_group3), + CFG_GROUP_LEN(cfg_info_group4), + CFG_GROUP_LEN(cfg_info_group5)}; + + dev_dbg(&ts->client->dev, + "Config Groups\' Lengths: %d, %d, %d, %d, %d, %d", + cfg_info_len[0], cfg_info_len[1], cfg_info_len[2], + cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]); +#endif + + /* read sensor id */ + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID, + &sensor_id, 1); + if (ret != SUCCESS || sensor_id >= 0x06) { + dev_err(&ts->client->dev, + "Failed get valid sensor_id(0x%02X), No Config Sent\n", + sensor_id); + return -EINVAL; + } + + dev_dbg(&ts->client->dev, "Sensor_ID: %d", sensor_id); + /* parse config data */ +#ifdef CONFIG_OF + dev_dbg(&ts->client->dev, "Get config data from device tree\n"); + ret = gtp_parse_dt_cfg(&ts->client->dev, + &cfg->data[GTP_ADDR_LENGTH], + &cfg->length, sensor_id); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to parse config data form device tree\n"); + cfg->length = 0; + return -EPERM; + } +#else + dev_dbg(&ts->client->dev, "Get config data from header file\n"); + if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && + (!cfg_info_len[3]) && (!cfg_info_len[4]) && + (!cfg_info_len[5])) { + sensor_id = 0; + } + cfg->length = cfg_info_len[sensor_id]; + memset(&cfg->data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH); + memcpy(&cfg->data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id], + cfg->length); +#endif + + if (cfg->length < GTP_CONFIG_MIN_LENGTH) { + dev_err(&ts->client->dev, + "Failed get valid config data with sensor id %d\n", + sensor_id); + cfg->length = 0; + return -EPERM; + } + + dev_info(&ts->client->dev, "Config group%d used,length: %d\n", + sensor_id, cfg->length); + + return 0; +} + +/******************************************************* + * Function: + * Get valid config data from dts or .h file. + * Read firmware version info and judge firmware + * working state + * Input: + * ts: goodix private data + * Output: + * Executive outcomes. + * 0: succeed, otherwise: failed + *******************************************************/ +static s32 gtp_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = -1; + u8 opr_buf[16] = {0}; + u8 drv_cfg_version = 0; + u8 flash_cfg_version = 0; + struct goodix_config_data *cfg = &ts->pdata->config; + + if (!ts->pdata->driver_send_cfg) { + dev_info(&ts->client->dev, "Driver set not send config\n"); + cfg->length = GTP_CONFIG_MAX_LENGTH; + ret = gtp_i2c_read(ts->client, + cfg->data, cfg->length + + GTP_ADDR_LENGTH); + if (ret < 0) + dev_err(&ts->client->dev, "Read origin Config Failed\n"); + + return 0; + } + + gtp_find_valid_cfg_data(ts); + + /* check firmware */ + ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1); + if (ret == SUCCESS) { + if (opr_buf[0] != 0xBE) { + set_bit(FW_ERROR, &ts->flags); + dev_err(&ts->client->dev, + "Firmware error, no config sent!\n"); + return -EINVAL; + } + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + dev_dbg(&ts->client->dev, + "Config Version: %d; IC Config Version: %d\n", + cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); + flash_cfg_version = opr_buf[0]; + drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; + + if (flash_cfg_version < 120 && + flash_cfg_version > drv_cfg_version) + cfg->data[GTP_ADDR_LENGTH] = 0x00; + } else { + dev_err(&ts->client->dev, + "Failed to get ic config version!No config sent\n"); + return -EPERM; + } + + ret = gtp_send_cfg(ts->client); + if (ret < 0) + dev_err(&ts->client->dev, "Send config error\n"); + else + usleep_range(10000, 11000); /* 10 ms */ + + /* restore config version */ + cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; + + return 0; +} + +static ssize_t gtp_config_read_proc(struct file *file, char __user *page, + size_t size, loff_t *ppos) +{ + int i, ret; + char *ptr; + size_t data_len = 0; + char temp_data[GTP_CONFIG_MAX_LENGTH + 2] = { + (u8)(GTP_REG_CONFIG_DATA >> 8), + (u8)GTP_REG_CONFIG_DATA }; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + struct goodix_config_data *cfg = &ts->pdata->config; + + ptr = kzalloc(4096, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + data_len += snprintf(ptr + data_len, 4096 - data_len, + "====init value====\n"); + for (i = 0 ; i < GTP_CONFIG_MAX_LENGTH ; i++) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "0x%02X ", cfg->data[i + 2]); + + if (i % 8 == 7) + data_len += snprintf(ptr + data_len, + 4096 - data_len, "\n"); + } + data_len += snprintf(ptr + data_len, 4096 - data_len, "\n"); + + data_len += snprintf(ptr + data_len, 4096 - data_len, + "====real value====\n"); + ret = gtp_i2c_read(i2c_connect_client, temp_data, + GTP_CONFIG_MAX_LENGTH + 2); + if (ret < 0) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "Failed read real config data\n"); + } else { + for (i = 0; i < GTP_CONFIG_MAX_LENGTH; i++) { + data_len += snprintf(ptr + data_len, 4096 - data_len, + "0x%02X ", temp_data[i + 2]); + + if (i % 8 == 7) + data_len += snprintf(ptr + data_len, + 4096 - data_len, "\n"); + } + } + + data_len = simple_read_from_buffer(page, size, ppos, ptr, data_len); + kfree(ptr); + ptr = NULL; + return data_len; +} + +int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf) +{ + int i, ret; + int cfg_len = 0; + long val; + char temp_buf[5]; + + for (i = 0; i < src_len;) { + if (src_buf[i] == ' ' || src_buf[i] == '\r' || + src_buf[i] == '\n') { + i++; + continue; + } + + temp_buf[0] = src_buf[i]; + temp_buf[1] = src_buf[i + 1]; + temp_buf[2] = src_buf[i + 2]; + temp_buf[3] = src_buf[i + 3]; + temp_buf[4] = '\0'; + if (!kstrtol(temp_buf, 16, &val)) { + if (cfg_len < GTP_CONFIG_MAX_LENGTH) { + dst_buf[cfg_len++] = val & 0xFF; + i += 5; + } else { + ret = -2; + goto convert_failed; + } + } else { + ret = -3; + goto convert_failed; + } + } + return cfg_len; + +convert_failed: + return ret; +} + +static ssize_t gtp_config_write_proc(struct file *filp, + const char __user *buffer, + size_t count, loff_t *off) +{ + u8 *temp_buf; + u8 *file_config; + int file_cfg_len; + s32 ret = 0, i; + struct goodix_ts_data *ts = i2c_get_clientdata(i2c_connect_client); + + dev_dbg(&ts->client->dev, "write count %zu\n", count); + + if (count > PAGE_SIZE) { + dev_err(&ts->client->dev, "config to long %zu\n", count); + return -EFAULT; + } + + temp_buf = kzalloc(count, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + + file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + kfree(temp_buf); + return -ENOMEM; + } + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + + if (copy_from_user(temp_buf, buffer, count)) { + dev_err(&ts->client->dev, "Failed copy from user\n"); + ret = -EFAULT; + goto send_cfg_err; + } + + file_cfg_len = gtp_ascii_to_array(temp_buf, (int)count, + &file_config[GTP_ADDR_LENGTH]); + if (file_cfg_len < 0) { + dev_err(&ts->client->dev, "failed covert ascii to hex"); + ret = -EFAULT; + goto send_cfg_err; + } + + GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); + + i = 0; + while (i++ < 5) { + ret = gtp_i2c_write(ts->client, file_config, file_cfg_len + 2); + if (ret > 0) { + dev_info(&ts->client->dev, "Send config SUCCESS."); + break; + } + dev_err(&ts->client->dev, "Send config i2c error."); + ret = -EFAULT; + goto send_cfg_err; + } + + ret = count; +send_cfg_err: + kfree(temp_buf); + kfree(file_config); + return ret; +} + +static const struct file_operations config_proc_ops = { + .owner = THIS_MODULE, + .read = gtp_config_read_proc, + .write = gtp_config_write_proc, +}; + +static ssize_t gtp_workmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + size_t data_len = 0; + struct goodix_ts_data *data = dev_get_drvdata(dev); + + if (test_bit(DOZE_MODE, &data->flags)) + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "doze_mode"); + else if (test_bit(SLEEP_MODE, &data->flags)) + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "sleep_mode"); + else + data_len = scnprintf(buf, PAGE_SIZE, "%s\n", + "normal_mode"); + + return data_len; +} +static DEVICE_ATTR(workmode, 0444, gtp_workmode_show, NULL); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE +#define FW_NAME_MAX_LEN 80 +static ssize_t gtp_dofwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct goodix_ts_data *ts = dev_get_drvdata(dev); + char update_file_name[FW_NAME_MAX_LEN]; + int retval; + + if (count > FW_NAME_MAX_LEN) { + dev_info(&ts->client->dev, "FW filename is too long\n"); + retval = -EINVAL; + goto exit; + } + + strlcpy(update_file_name, buf, count); + + ts->force_update = true; + retval = gup_update_proc(update_file_name); + if (retval == FAIL) + dev_err(&ts->client->dev, "Fail to update GTP firmware.\n"); + else + dev_info(&ts->client->dev, "Update success\n"); + + return count; + +exit: + return retval; +} +static DEVICE_ATTR(dofwupdate, 0664, NULL, gtp_dofwupdate_store); +#endif + +static ssize_t gtp_productinfo_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + struct goodix_fw_info *fw_info = &data->fw_info; + + return scnprintf(buf, PAGE_SIZE, "GT%s_%x_%d\n", + fw_info->pid, fw_info->version, fw_info->sensor_id); +} +static DEVICE_ATTR(productinfo, 0444, gtp_productinfo_show, NULL); + +static ssize_t gtp_drv_irq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long value = 0; + int err = 0; + struct goodix_ts_data *data = dev_get_drvdata(dev); + + err = kstrtoul(buf, 10, &value); + if (err < 0) { + dev_err(dev, "Failed to convert value\n"); + return -EINVAL; + } + + switch (value) { + case 0: + /* Disable irq */ + gtp_work_control_enable(data, false); + break; + case 1: + /* Enable irq */ + gtp_work_control_enable(data, true); + break; + default: + dev_err(dev, "Invalid value\n"); + return -EINVAL; + } + + return count; +} + +static ssize_t gtp_drv_irq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%s\n", + test_bit(REPORT_THREAD_ENABLED, &data->flags) + ? "enabled" : "disabled"); +} +static DEVICE_ATTR(drv_irq, 0664, gtp_drv_irq_show, gtp_drv_irq_store); + +static ssize_t gtp_reset_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct goodix_ts_data *data = dev_get_drvdata(dev); + + if ('1' != buf[0]) { + dev_err(dev, "Invalid argument for reset\n"); + return -EINVAL; + } + + gtp_reset_guitar(data->client, 20); + + return count; +} +static DEVICE_ATTR(reset, 0220, NULL, gtp_reset_store); + +static struct attribute *gtp_attrs[] = { + &dev_attr_workmode.attr, + &dev_attr_productinfo.attr, + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + &dev_attr_dofwupdate.attr, +#endif + + &dev_attr_drv_irq.attr, + &dev_attr_reset.attr, + NULL +}; + +static const struct attribute_group gtp_attr_group = { + .attrs = gtp_attrs, +}; + +static int gtp_create_file(struct goodix_ts_data *ts) +{ + int ret; + struct i2c_client *client = ts->client; + + /* Create proc file system */ + gtp_config_proc = NULL; + gtp_config_proc = proc_create(GT91XX_CONFIG_PROC_FILE, 0664, + NULL, &config_proc_ops); + if (!gtp_config_proc) + dev_err(&client->dev, "create_proc_entry %s failed\n", + GT91XX_CONFIG_PROC_FILE); + else + dev_info(&client->dev, "create proc entry %s success\n", + GT91XX_CONFIG_PROC_FILE); + + ret = sysfs_create_group(&client->dev.kobj, >p_attr_group); + if (ret) { + dev_err(&client->dev, "Failure create sysfs group %d\n", ret); + /*TODO: debug change */ + goto exit_free_config_proc; + } + return 0; + +exit_free_config_proc: + remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); + return -ENODEV; +} + +s32 gtp_get_fw_info(struct i2c_client *client, struct goodix_fw_info *fw_info) +{ + s32 ret = -1; + u8 buf[8] = {GTP_REG_VERSION >> 8, GTP_REG_VERSION & 0xff}; + + ret = gtp_i2c_read(client, buf, sizeof(buf)); + if (ret < 0) { + dev_err(&client->dev, "Failed read fw_info\n"); + return ret; + } + + /* product id */ + memset(fw_info, 0, sizeof(*fw_info)); + + if (buf[5] == 0x00) { + memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 3); + dev_info(&client->dev, "IC Version: %c%c%c_%02X%02X\n", + buf[2], buf[3], buf[4], buf[7], buf[6]); + } else { + memcpy(fw_info->pid, buf + GTP_ADDR_LENGTH, 4); + dev_info(&client->dev, "IC Version: %c%c%c%c_%02X%02X\n", + buf[2], buf[3], buf[4], buf[5], buf[7], buf[6]); + } + + /* current firmware version */ + fw_info->version = (buf[7] << 8) | buf[6]; + + /* read sensor id */ + fw_info->sensor_id = 0xff; + ret = gtp_i2c_read_dbl_check(client, GTP_REG_SENSOR_ID, + &fw_info->sensor_id, 1); + if (ret != SUCCESS || fw_info->sensor_id >= 0x06) { + dev_err(&client->dev, + "Failed get valid sensor_id(0x%02X), No Config Sent\n", + fw_info->sensor_id); + + fw_info->sensor_id = 0xff; + } + + return ret; +} + +static int gtp_i2c_test(struct i2c_client *client) +{ + u8 test[3] = {GTP_REG_CONFIG_DATA >> 8, GTP_REG_CONFIG_DATA & 0xff}; + u8 retry = 0; + int ret = -1; + + while (retry++ < 3) { + ret = gtp_i2c_read(client, test, 3); + if (ret == 2) + return 0; + + dev_err(&client->dev, "GTP i2c test failed time %d\n", retry); + usleep_range(10000, 11000); /* 10 ms */ + } + + return -EAGAIN; +} + +static int gtp_pinctrl_init(struct goodix_ts_data *ts) +{ + struct goodix_pinctrl *pinctrl = &ts->pinctrl; + + pinctrl->pinctrl = devm_pinctrl_get(&ts->client->dev); + if (IS_ERR_OR_NULL(pinctrl->pinctrl)) { + dev_info(&ts->client->dev, "No pinctrl found\n"); + pinctrl->pinctrl = NULL; + return 0; + } + + /* INT pinctrl */ + pinctrl->int_default = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_default"); + if (IS_ERR_OR_NULL(pinctrl->int_default)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:INT default state\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_output_high"); + if (IS_ERR_OR_NULL(pinctrl->int_out_high)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:INT output_high\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_output_low"); + if (IS_ERR_OR_NULL(pinctrl->int_out_low)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:INT output_low\n"); + goto exit_pinctrl_init; + } + + pinctrl->int_input = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_int_input"); + if (IS_ERR_OR_NULL(pinctrl->int_input)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:int-input\n"); + goto exit_pinctrl_init; + } + dev_info(&ts->client->dev, "Success init INT pinctrl\n"); + + /* RST pinctrl */ + pinctrl->rst_default = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_default"); + if (IS_ERR_OR_NULL(pinctrl->rst_default)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:RST default state\n"); + goto exit_pinctrl_init; + } + + pinctrl->rst_out_high = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_output_high"); + if (IS_ERR_OR_NULL(pinctrl->rst_out_high)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:RST output_high\n"); + goto exit_pinctrl_init; + } + + pinctrl->rst_out_low = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_output_low"); + if (IS_ERR_OR_NULL(pinctrl->rst_out_low)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:RST output_low\n"); + goto exit_pinctrl_init; + } + + pinctrl->rst_input = pinctrl_lookup_state(pinctrl->pinctrl, + "gdix_ts_rst_input"); + if (IS_ERR_OR_NULL(pinctrl->rst_input)) { + dev_info(&ts->client->dev, + "Failed get pinctrl state:rst-input\n"); + goto exit_pinctrl_init; + } + dev_info(&ts->client->dev, "Success init RST pinctrl\n"); + + return 0; +exit_pinctrl_init: + devm_pinctrl_put(pinctrl->pinctrl); + pinctrl->pinctrl = NULL; + pinctrl->int_default = NULL; + pinctrl->int_out_high = NULL; + pinctrl->int_out_low = NULL; + pinctrl->int_input = NULL; + pinctrl->rst_default = NULL; + pinctrl->rst_out_high = NULL; + pinctrl->rst_out_low = NULL; + pinctrl->rst_input = NULL; + return -EINVAL; +} + +static void gtp_pinctrl_deinit(struct goodix_ts_data *ts) +{ + if (ts->pinctrl.pinctrl) + devm_pinctrl_put(ts->pinctrl.pinctrl); +} + +static int gtp_request_io_port(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (gpio_is_valid(ts->pdata->irq_gpio)) { + ret = gpio_request(ts->pdata->irq_gpio, "goodix_ts_int"); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request GPIO:%d, ERRNO:%d\n", + (s32)ts->pdata->irq_gpio, ret); + return -ENODEV; + } + + gpio_direction_input(ts->pdata->irq_gpio); + dev_info(&ts->client->dev, "Success request irq-gpio\n"); + } + + if (gpio_is_valid(ts->pdata->rst_gpio)) { + ret = gpio_request(ts->pdata->rst_gpio, "goodix_ts_rst"); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request GPIO:%d, ERRNO:%d\n", + (s32)ts->pdata->rst_gpio, ret); + + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + return -ENODEV; + } + + gpio_direction_input(ts->pdata->rst_gpio); + dev_info(&ts->client->dev, "Success request rst-gpio\n"); + } + + return 0; +} + +/******************************************************* + * Function: + * Request interrupt if define irq pin, else use hrtimer + * as interrupt source + * Input: + * ts: private data. + * Output: + * Executive outcomes. + * 0: succeed, -1: failed. + *******************************************************/ +static int gtp_request_irq(struct goodix_ts_data *ts) +{ + int ret = -1; + + /* use irq */ + if (gpio_is_valid(ts->pdata->irq_gpio) || ts->client->irq > 0) { + if (gpio_is_valid(ts->pdata->irq_gpio)) + ts->client->irq = gpio_to_irq(ts->pdata->irq_gpio); + + dev_info(&ts->client->dev, "INT num %d, trigger type:%d\n", + ts->client->irq, ts->pdata->irq_flags); + ret = request_threaded_irq(ts->client->irq, NULL, + gtp_irq_handler, + ts->pdata->irq_flags | IRQF_ONESHOT, + ts->client->name, + ts); + if (ret < 0) { + dev_err(&ts->client->dev, + "Failed to request irq %d\n", ts->client->irq); + return ret; + } + } else { /* use hrtimer */ + dev_info(&ts->client->dev, "No hardware irq, use hrtimer\n"); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = gtp_timer_handler; + hrtimer_start(&ts->timer, + ktime_set(0, (GTP_POLL_TIME + 6) * 1000000), + HRTIMER_MODE_REL); + set_bit(HRTIMER_USED, &ts->flags); + ret = 0; + } + return ret; +} + +static s8 gtp_request_input_dev(struct goodix_ts_data *ts) +{ + s8 ret = -1; + u8 index = 0; + + ts->input_dev = input_allocate_device(); + if (!ts->input_dev) { + dev_err(&ts->client->dev, "Failed to allocate input device\n"); + return -ENOMEM; + } + + ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) + | BIT_MASK(EV_ABS); + if (!ts->pdata->type_a_report) { + input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT); + dev_info(&ts->client->dev, "Use slot report protocol\n"); + } else { + __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + __set_bit(BTN_TOUCH, ts->input_dev->keybit); + dev_info(&ts->client->dev, "Use type A report protocol\n"); + } + + input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1); + input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2); + + /* touch key register */ + for (index = 0; index < ts->pdata->key_nums; index++) + input_set_capability(ts->input_dev, EV_KEY, + ts->pdata->key_map[index]); + + if (ts->pdata->slide_wakeup) + input_set_capability(ts->input_dev, EV_KEY, KEY_POWER); + + if (ts->pdata->swap_x2y) + GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, + ts->pdata->abs_size_x, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, + ts->pdata->abs_size_y, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, + ts->pdata->max_touch_width, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, + ts->pdata->max_touch_pressure, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, + ts->pdata->max_touch_id, 0, 0); + if (!ts->pdata->type_a_report) { + input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); + } else { + __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); + } + + ts->input_dev->name = goodix_ts_name; + ts->input_dev->phys = goodix_input_phys; + ts->input_dev->id.bustype = BUS_I2C; + ts->input_dev->id.vendor = 0xDEAD; + ts->input_dev->id.product = 0xBEEF; + ts->input_dev->id.version = 10427; + + ret = input_register_device(ts->input_dev); + if (ret) { + dev_err(&ts->client->dev, "Register %s input device failed\n", + ts->input_dev->name); + input_free_device(ts->input_dev); + return -ENODEV; + } + + return 0; +} + +/* + * Devices Tree support + */ +#ifdef CONFIG_OF +static void gtp_parse_dt_coords(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + int ret; + + ret = of_property_read_u32(np, "touchscreen-max-id", + &pdata->max_touch_id); + if (ret || pdata->max_touch_id > GTP_MAX_TOUCH_ID) { + dev_info(dev, "Unset touchscreen-max-id, use default\n"); + pdata->max_touch_id = GTP_MAX_TOUCH_ID; + } + + ret = of_property_read_u32(np, "touchscreen-size-x", + &pdata->abs_size_x); + if (ret) { + dev_info(dev, "Unset touchscreen-size-x, use default\n"); + pdata->abs_size_x = GTP_DEFAULT_MAX_X; + } + + ret = of_property_read_u32(np, "touchscreen-size-y", + &pdata->abs_size_y); + if (ret) { + dev_info(dev, "Unset touchscreen-size-y, use default\n"); + pdata->abs_size_y = GTP_DEFAULT_MAX_Y; + } + + ret = of_property_read_u32(np, "touchscreen-max-w", + &pdata->max_touch_width); + if (ret) { + dev_info(dev, "Unset touchscreen-max-w, use default\n"); + pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; + } + + ret = of_property_read_u32(np, "touchscreen-max-p", + &pdata->max_touch_pressure); + if (ret) { + dev_info(dev, "Unset touchscreen-max-p, use default\n"); + pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; + } + dev_info(dev, "touch input parameters is [id x y w p]<%d %d %d %d %d>\n", + pdata->max_touch_id, pdata->abs_size_x, pdata->abs_size_y, + pdata->max_touch_width, pdata->max_touch_pressure); +} + +static int gtp_parse_dt(struct device *dev, + struct goodix_ts_platform_data *pdata) +{ + int ret; + u32 key_nums; + struct property *prop; + u32 key_map[MAX_KEY_NUMS]; + struct device_node *np = dev->of_node; + + gtp_parse_dt_coords(dev, pdata); + + ret = of_property_read_u32(np, "irq-flags", + &pdata->irq_flags); + if (ret) { + dev_info(dev, + "Failed get int-trigger-type from dts,set default\n"); + pdata->irq_flags = GTP_DEFAULT_INT_TRIGGER; + } + of_property_read_u32(np, "goodix,int-sync", &pdata->int_sync); + if (pdata->int_sync) + dev_info(dev, "int-sync enabled\n"); + + of_property_read_u32(np, "goodix,driver-send-cfg", + &pdata->driver_send_cfg); + if (pdata->driver_send_cfg) + dev_info(dev, "driver-send-cfg enabled\n"); + + of_property_read_u32(np, "goodix,swap-x2y", &pdata->swap_x2y); + if (pdata->swap_x2y) + dev_info(dev, "swap-x2y enabled\n"); + + of_property_read_u32(np, "goodix,slide-wakeup", &pdata->slide_wakeup); + if (pdata->slide_wakeup) + dev_info(dev, "slide-wakeup enabled\n"); + + of_property_read_u32(np, "goodix,auto-update", &pdata->auto_update); + if (pdata->auto_update) + dev_info(dev, "auto-update enabled\n"); + + of_property_read_u32(np, "goodix,auto-update-cfg", + &pdata->auto_update_cfg); + if (pdata->auto_update_cfg) + dev_info(dev, "auto-update-cfg enabled\n"); + + of_property_read_u32(np, "goodix,esd-protect", &pdata->esd_protect); + if (pdata->esd_protect) + dev_info(dev, "esd-protect enabled\n"); + + of_property_read_u32(np, "goodix,type-a-report", + &pdata->type_a_report); + if (pdata->type_a_report) + dev_info(dev, "type-a-report enabled\n"); + + of_property_read_u32(np, "goodix,resume-in-workqueue", + &pdata->resume_in_workqueue); + if (pdata->resume_in_workqueue) + dev_info(dev, "resume-in-workqueue enabled\n"); + + of_property_read_u32(np, "goodix,power-off-sleep", + &pdata->power_off_sleep); + if (pdata->power_off_sleep) + dev_info(dev, "power-off-sleep enabled\n"); + + of_property_read_u32(np, "goodix,pen-suppress-finger", + &pdata->pen_suppress_finger); + if (pdata->pen_suppress_finger) + dev_info(dev, "pen-suppress-finger enabled\n"); + + prop = of_find_property(np, "touchscreen-key-map", NULL); + if (prop) { + key_nums = prop->length / sizeof(key_map[0]); + key_nums = key_nums > MAX_KEY_NUMS ? MAX_KEY_NUMS : key_nums; + + dev_dbg(dev, "key nums %d\n", key_nums); + ret = of_property_read_u32_array(np, + "touchscreen-key-map", key_map, + key_nums); + if (ret) { + dev_err(dev, "Unable to read key codes\n"); + pdata->key_nums = 0; + memset(pdata->key_map, 0, + MAX_KEY_NUMS * sizeof(pdata->key_map[0])); + } + pdata->key_nums = key_nums; + memcpy(pdata->key_map, key_map, + key_nums * sizeof(pdata->key_map[0])); + dev_info(dev, "key-map is [%x %x %x %x]\n", + pdata->key_map[0], pdata->key_map[1], + pdata->key_map[2], pdata->key_map[3]); + } + + pdata->irq_gpio = of_get_named_gpio(np, "irq-gpios", 0); + if (!gpio_is_valid(pdata->irq_gpio)) + dev_err(dev, "No valid irq gpio"); + + pdata->rst_gpio = of_get_named_gpio(np, "reset-gpios", 0); + if (!gpio_is_valid(pdata->rst_gpio)) + dev_err(dev, "No valid rst gpio"); + + return 0; +} + +/******************************************************* + * Function: + * parse config data from devices tree. + * Input: + * dev: device that this driver attached. + * cfg: pointer of the config array. + * cfg_len: pointer of the config length. + * sid: sensor id. + * Output: + * Executive outcomes. + * 0-succeed, -1-faileds. + *******************************************************/ +int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid) +{ + struct device_node *np = dev->of_node; + struct property *prop; + char cfg_name[18]; + int ret; + + snprintf(cfg_name, sizeof(cfg_name), "goodix,cfg-group%d", sid); + prop = of_find_property(np, cfg_name, cfg_len); + if (!prop || !prop->value || *cfg_len == 0 || + *cfg_len > GTP_CONFIG_MAX_LENGTH) { + *cfg_len = 0; + ret = -EPERM;/* failed */ + } else { + memcpy(cfg, prop->value, *cfg_len); + ret = 0; + } + + return ret; +} + +#endif + +static int gtp_power_on(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (ts->vdd_ana) { + ret = regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV, + GOODIX_VTG_MAX_UV); + if (ret) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vdd ret=%d\n", + ret); + goto err_set_vtg_vdd_ana; + } + ret = regulator_enable(ts->vdd_ana); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd enable failed ret=%d\n", + ret); + goto err_enable_vdd_ana; + } + } + + if (ts->vcc_i2c) { + ret = regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV, + GOODIX_I2C_VTG_MAX_UV); + if (ret) { + dev_err(&ts->client->dev, + "Regulator set_vtg failed vcc_i2c ret=%d\n", + ret); + goto err_set_vtg_vcc_i2c; + } + ret = regulator_enable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c enable failed ret=%d\n", + ret); + goto err_enable_vcc_i2c; + } + } + clear_bit(POWER_OFF_MODE, &ts->flags); + return 0; + +err_enable_vcc_i2c: + if (ts->vcc_i2c) + regulator_set_voltage(ts->vcc_i2c, 0, GOODIX_I2C_VTG_MAX_UV); +err_set_vtg_vcc_i2c: + if (ts->vdd_ana) + regulator_disable(ts->vdd_ana); +err_enable_vdd_ana: + if (ts->vdd_ana) + regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV); +err_set_vtg_vdd_ana: + set_bit(POWER_OFF_MODE, &ts->flags); + return ret; +} + +static int gtp_power_off(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (ts->vcc_i2c) { + set_bit(POWER_OFF_MODE, &ts->flags); + ret = regulator_set_voltage(ts->vcc_i2c, 0, + GOODIX_I2C_VTG_MAX_UV); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c set_vtg failed ret=%d\n", + ret); + goto err_set_vtg_vcc_i2c; + } + ret = regulator_disable(ts->vcc_i2c); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vcc_i2c disable failed ret=%d\n", + ret); + goto err_disable_vcc_i2c; + } + dev_info(&ts->client->dev, + "Regulator vcc_i2c disabled\n"); + } + + if (ts->vdd_ana) { + set_bit(POWER_OFF_MODE, &ts->flags); + ret = regulator_set_voltage(ts->vdd_ana, 0, GOODIX_VTG_MAX_UV); + if (ret < 0) { + dev_err(&ts->client->dev, + "Regulator vdd set_vtg failed ret=%d\n", + ret); + goto err_set_vtg_vdd_ana; + } + ret = regulator_disable(ts->vdd_ana); + if (ret) { + dev_err(&ts->client->dev, + "Regulator vdd disable failed ret=%d\n", + ret); + goto err_disable_vdd_ana; + } + dev_info(&ts->client->dev, + "Regulator vdd_ana disabled\n"); + } + return ret; + +err_disable_vdd_ana: + if (ts->vdd_ana) + regulator_set_voltage(ts->vdd_ana, GOODIX_VTG_MIN_UV, + GOODIX_VTG_MAX_UV); +err_set_vtg_vdd_ana: + if (ts->vcc_i2c) + ret = regulator_enable(ts->vcc_i2c); +err_disable_vcc_i2c: + if (ts->vcc_i2c) + regulator_set_voltage(ts->vcc_i2c, GOODIX_I2C_VTG_MIN_UV, + GOODIX_I2C_VTG_MAX_UV); +err_set_vtg_vcc_i2c: + clear_bit(POWER_OFF_MODE, &ts->flags); + return ret; +} + +static int gtp_power_init(struct goodix_ts_data *ts) +{ + int ret; + + ts->vdd_ana = regulator_get(&ts->client->dev, "vdd_ana"); + if (IS_ERR(ts->vdd_ana)) { + ts->vdd_ana = NULL; + ret = PTR_ERR(ts->vdd_ana); + dev_info(&ts->client->dev, + "Regulator get failed vdd ret=%d\n", ret); + } + + ts->vcc_i2c = regulator_get(&ts->client->dev, "vcc_i2c"); + if (IS_ERR(ts->vcc_i2c)) { + ts->vcc_i2c = NULL; + ret = PTR_ERR(ts->vcc_i2c); + dev_info(&ts->client->dev, + "Regulator get failed vcc_i2c ret=%d\n", ret); + } + return 0; +} + +static int gtp_power_deinit(struct goodix_ts_data *ts) +{ + if (ts->vdd_ana) + regulator_put(ts->vdd_ana); + if (ts->vcc_i2c) + regulator_put(ts->vcc_i2c); + + return 0; +} + +static void gtp_shutdown(struct i2c_client *client) +{ + struct goodix_ts_data *data = i2c_get_clientdata(client); + + if (!data->init_done) + return; + + gtp_work_control_enable(data, false); + gtp_power_off(data); +} + +static int gtp_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int ret = -1; + struct goodix_ts_data *ts; + struct goodix_ts_platform_data *pdata; + + /* do NOT remove these logs */ + dev_info(&client->dev, "GTP Driver Version: %s\n", GTP_DRIVER_VERSION); + dev_info(&client->dev, "GTP I2C Address: 0x%02x\n", client->addr); + + i2c_connect_client = client; + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Failed check I2C functionality"); + return -ENODEV; + } + + ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + devm_kfree(&client->dev, ts); + return -EINVAL; + } + + ts->init_done = false; + +#ifdef CONFIG_OF + if (client->dev.of_node) { + ret = gtp_parse_dt(&client->dev, pdata); + if (ret) { + dev_err(&client->dev, "Failed parse dts\n"); + goto exit_free_client_data; + } + } +#else + /* set parameters at here if you platform doesn't DTS */ + pdata->rst_gpio = GTP_RST_PORT; + pdata->irq_gpio = GTP_INT_PORT; + pdata->slide_wakeup = false; + pdata->auto_update = true; + pdata->auto_update_cfg = false; + pdata->type_a_report = false; + pdata->esd_protect = false; + pdata->max_touch_id = GTP_MAX_TOUCH_ID; + pdata->abs_size_x = GTP_DEFAULT_MAX_X; + pdata->abs_size_y = GTP_DEFAULT_MAX_Y; + pdata->max_touch_width = GTP_DEFAULT_MAX_WIDTH; + pdata->max_touch_pressure = GTP_DEFAULT_MAX_PRESSURE; +#endif + + ts->client = client; + ts->pdata = pdata; + + i2c_set_clientdata(client, ts); + + ret = gtp_power_init(ts); + if (ret) { + dev_err(&client->dev, "Failed get regulator\n"); + ret = -EINVAL; + goto exit_free_client_data; + } + + ret = gtp_pinctrl_init(ts); + if (ret < 0) { + /* if define pinctrl must define the following state + * to let int-pin work normally: default, int_output_high, + * int_output_low, int_input + */ + dev_err(&client->dev, "Failed get wanted pinctrl state\n"); + goto exit_deinit_power; + } + + ret = gtp_request_io_port(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed request IO port\n"); + goto exit_pinctrl; + } + + /*wait for discharging power, which from i2c pull-up flow backward*/ + gtp_rst_output(ts, 0); + msleep(DELAY_FOR_DISCHARGING); + + ret = gtp_power_on(ts); + if (ret) { + dev_err(&client->dev, "Failed power on device\n"); + ret = -EINVAL; + goto exit_free_io_port; + } + + gtp_reset_guitar(ts->client, 20); + + ret = gtp_i2c_test(client); + if (ret) { + dev_err(&client->dev, "Failed communicate with IC use I2C\n"); + goto exit_power_off; + } + + dev_info(&client->dev, "I2C Addr is %x\n", client->addr); + + ret = gtp_get_fw_info(client, &ts->fw_info); + if (ret < 0) { + dev_err(&client->dev, "Failed read FW version\n"); + goto exit_power_off; + } + + pdata->config.data[0] = GTP_REG_CONFIG_DATA >> 8; + pdata->config.data[1] = GTP_REG_CONFIG_DATA & 0xff; + ret = gtp_init_panel(ts); + if (ret < 0) + dev_info(&client->dev, "Panel un-initialize\n"); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE + if (ts->pdata->auto_update) { + ret = gup_init_update_proc(ts); + if (ret < 0) + dev_err(&client->dev, "Failed create update thread\n"); + } +#endif + + ret = gtp_request_input_dev(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed request input device\n"); + goto exit_power_off; + } + + mutex_init(&ts->lock); + + ret = gtp_request_irq(ts); + if (ret < 0) { + dev_err(&client->dev, "Failed create work thread"); + goto exit_unreg_input_dev; + } + gtp_work_control_enable(ts, false); + if (ts->pdata->slide_wakeup) { + dev_info(&client->dev, "slide wakeup enabled\n"); + ret = enable_irq_wake(client->irq); + if (ret < 0) + dev_err(&client->dev, "Failed set irq wake\n"); + } + + gtp_register_powermanager(ts); + + ret = gtp_create_file(ts); + if (ret) { + dev_info(&client->dev, "Failed create attributes file"); + goto exit_powermanager; + } + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL + init_wr_node(client);/*TODO judge return value */ +#endif + + gtp_esd_init(ts); + gtp_esd_on(ts); + /* probe init finished */ + ts->init_done = true; + gtp_work_control_enable(ts, true); + + return 0; + +exit_powermanager: + gtp_unregister_powermanager(ts); +exit_unreg_input_dev: + input_unregister_device(ts->input_dev); +exit_power_off: + gtp_power_off(ts); +exit_free_io_port: + if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_free(ts->pdata->rst_gpio); + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); +exit_pinctrl: + gtp_pinctrl_deinit(ts); +exit_deinit_power: + gtp_power_deinit(ts); +exit_free_client_data: + devm_kfree(&client->dev, pdata); + devm_kfree(&client->dev, ts); + i2c_set_clientdata(client, NULL); + + return ret; +} + +static int gtp_drv_remove(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + gtp_work_control_enable(ts, false); + gtp_unregister_powermanager(ts); + + remove_proc_entry(GT91XX_CONFIG_PROC_FILE, gtp_config_proc); + + sysfs_remove_group(&client->dev.kobj, >p_attr_group); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL + uninit_wr_node(); +#endif + + if (ts->pdata->esd_protect) + gtp_esd_off(ts); + + /* TODO: how to judge a irq numbers validity */ + if (ts->client->irq) + free_irq(client->irq, ts); + else + hrtimer_cancel(&ts->timer); + + if (gpio_is_valid(ts->pdata->rst_gpio)) + gpio_free(ts->pdata->rst_gpio); + + if (gpio_is_valid(ts->pdata->irq_gpio)) + gpio_free(ts->pdata->irq_gpio); + + gtp_power_off(ts); + gtp_power_deinit(ts); + gtp_pinctrl_deinit(ts); + dev_info(&client->dev, "goodix ts driver removed"); + i2c_set_clientdata(client, NULL); + input_unregister_device(ts->input_dev); + mutex_destroy(&ts->lock); + + devm_kfree(&client->dev, ts->pdata); + devm_kfree(&client->dev, ts); + + return 0; +} + +static void gtp_suspend(struct goodix_ts_data *ts) +{ + int ret = -1; + + if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_warn(&ts->client->dev, + "Fw upgrade in progress, can't go to suspend\n"); + return; + } + + if (test_and_set_bit(SLEEP_MODE, &ts->flags)) { + dev_info(&ts->client->dev, "Already in suspend state\n"); + return; + } + + dev_dbg(&ts->client->dev, "Try enter suspend mode\n"); + + gtp_esd_off(ts); + gtp_work_control_enable(ts, false); + if (ts->pdata->slide_wakeup) { + ret = gtp_enter_doze(ts); + gtp_work_control_enable(ts, true); + } else if (ts->pdata->power_off_sleep) { + /*TODO: power off routine */ + gtp_power_off(ts); + ret = SUCCESS; + } else { + ret = gtp_enter_sleep(ts); + } + + if (ret < 0) + dev_err(&ts->client->dev, "Failed enter suspend\n"); + + /* to avoid waking up while not sleeping */ + /* delay 48 + 10ms to ensure reliability */ + msleep(GTP_58_DLY_MS); +} + +static int gtp_gesture_wakeup(struct goodix_ts_data *ts) +{ + int ret; + int retry = 10; + + do { + gtp_reset_guitar(ts->client, 10); + ret = gtp_i2c_test(ts->client); + if (!ret) + break; + } while (--retry); + + if (!retry) + ret = -EIO; + + clear_bit(DOZE_MODE, &ts->flags); + return ret; +} + +static void gtp_resume(struct goodix_ts_data *ts) +{ + int ret = 0; + + if (test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_info(&ts->client->dev, + "Fw upgrade in progress, can't do resume\n"); + return; + } + + if (!test_bit(SLEEP_MODE, &ts->flags)) { + dev_dbg(&ts->client->dev, "Already in awake state\n"); + return; + } + + dev_info(&ts->client->dev, "Try resume from sleep mode\n"); + + gtp_work_control_enable(ts, false); + + if (ts->pdata->slide_wakeup && test_bit(DOZE_MODE, &ts->flags)) { + ret = gtp_gesture_wakeup(ts); + if (ret) + dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); + } else if (ts->pdata->power_off_sleep) { + ret = gtp_power_on(ts); + if (ret) { + dev_warn(&ts->client->dev, "Failed wake up from gesture mode\n"); + } else { + gtp_reset_guitar(ts->client, 20); + ret = gtp_i2c_test(ts->client); + if (ret) + dev_warn(&ts->client->dev, + "I2C communicate failed after power on\n"); + } + } else { + ret = gtp_wakeup_sleep(ts); + if (ret) + dev_warn(&ts->client->dev, + "Failed wakeup from sleep mode\n"); + } + + if (ret) + dev_warn(&ts->client->dev, "Later resume failed\n"); + else + gtp_esd_on(ts); + + clear_bit(SLEEP_MODE, &ts->flags); + gtp_work_control_enable(ts, true); +} + +#if defined(CONFIG_FB) +static void fb_notify_resume_work(struct work_struct *work) +{ + struct goodix_ts_data *ts = + container_of(work, struct goodix_ts_data, fb_notify_work); + dev_info(&ts->client->dev, "try resume in workqueue\n"); + gtp_resume(ts); +} + +/* frame buffer notifier block control the suspend/resume procedure */ +static int gtp_fb_notifier_callback(struct notifier_block *noti, + unsigned long event, void *data) +{ + struct fb_event *ev_data = data; + struct goodix_ts_data *ts = container_of(noti, + struct goodix_ts_data, notifier); + int *blank; + + if (ev_data && ev_data->data && event == FB_EVENT_BLANK && ts) { + blank = ev_data->data; + if (*blank == FB_BLANK_UNBLANK || + *blank == FB_BLANK_NORMAL) { + dev_dbg(&ts->client->dev, "ts_resume"); + if (ts->pdata->resume_in_workqueue) + schedule_work(&ts->fb_notify_work); + else + gtp_resume(ts); + } else if (*blank == FB_BLANK_POWERDOWN) { + dev_dbg(&ts->client->dev, "ts_suspend"); + if (ts->pdata->resume_in_workqueue) + flush_work(&ts->fb_notify_work); + gtp_suspend(ts); + } + } + + return 0; +} + +#elif defined(CONFIG_PM) +static int gtp_pm_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts) { + dev_dbg(&ts->client->dev, "Suspend by i2c pm."); + gtp_suspend(ts); + } + + return 0; +} + +static int gtp_pm_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts) { + dev_dbg(&ts->client->dev, "Resume by i2c pm."); + gtp_resume(ts); + } + + return 0; +} + +static const struct dev_pm_ops gtp_pm_ops = { + .suspend = gtp_pm_suspend, + .resume = gtp_pm_resume, +}; + +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void gtp_early_suspend(struct early_suspend *h) +{ + struct goodix_ts_data *ts = container_of(h, + struct goodix_ts_data, early_suspend); + + if (ts) { + dev_dbg(&ts->client->dev, "Suspend by earlysuspend module."); + gtp_suspend(ts); + } +} + +static void gtp_late_resume(struct early_suspend *h) +{ + struct goodix_ts_data *ts = container_of(h, + struct goodix_ts_data, early_suspend); + + if (ts) { + dev_dbg(&ts->client->dev, "Resume by earlysuspend module."); + gtp_resume(ts); + } +} +#endif + +static int gtp_register_powermanager(struct goodix_ts_data *ts) +{ + int ret; +#if defined(CONFIG_FB) + INIT_WORK(&ts->fb_notify_work, fb_notify_resume_work); + ts->notifier.notifier_call = gtp_fb_notifier_callback; + ret = fb_register_client(&ts->notifier); + if (ret) + dev_err(&ts->client->dev, + "Unable to register fb_notifier: %d\n", ret); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1; + ts->early_suspend.suspend = goodix_ts_early_suspend; + ts->early_suspend.resume = goodix_ts_late_resume; + register_early_suspend(&ts->early_suspend); +#endif + + return ret; +} + +static int gtp_unregister_powermanager(struct goodix_ts_data *ts) +{ +#if defined(CONFIG_FB) + fb_unregister_client(&ts->notifier); +#elif defined(CONFIG_HAS_EARLYSUSPEND) + unregister_early_suspend(&ts->early_suspend); +#endif + + return 0; +} + +/******************************************************* + * Function: + * Initialize external watchdog for esd protect + * Input: + * client: i2c device. + * Output: + * result of i2c write operation. + * 0: succeed, otherwise: failed + ********************************************************/ +static int gtp_init_ext_watchdog(struct i2c_client *client) +{ + int ret; + u8 opr_buffer[3] = { (u8)(GTP_REG_ESD_CHECK >> 8), + (u8)GTP_REG_ESD_CHECK, + (u8)GTP_ESD_CHECK_VALUE }; + + dev_dbg(&client->dev, "[Esd]Init external watchdog\n"); + ret = gtp_i2c_write(client, opr_buffer, 3); + if (ret == 1) + return 0; + + dev_err(&client->dev, "Failed init ext watchdog\n"); + return -EINVAL; +} + +static void gtp_esd_check_func(struct work_struct *work) +{ + s32 i; + s32 ret = -1; + u8 esd_buf[5] = { (u8)(GTP_REG_COMMAND >> 8), (u8)GTP_REG_COMMAND }; + struct delayed_work *dwork = to_delayed_work(work); + struct goodix_ts_esd *ts_esd = container_of(dwork, struct goodix_ts_esd, + delayed_work); + struct goodix_ts_data *ts = container_of(ts_esd, struct goodix_ts_data, + ts_esd); + + if (test_bit(SLEEP_MODE, &ts->flags) || + test_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_dbg(&ts->client->dev, + "Esd cancled by power_suspend or fw_update!"); + return; + } + + if (ts_esd->esd_on == false) + return; + + for (i = 0; i < 3; i++) { + ret = gtp_i2c_read(ts->client, esd_buf, 4); + if (ret < 0) + continue; + + dev_dbg(&ts->client->dev, + "[Esd]0x8040 = 0x%02X, 0x8041 = 0x%02X", + esd_buf[2], esd_buf[3]); + if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || + esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { + gtp_i2c_read(ts->client, esd_buf, 4); + if (ret < 0) + continue; + + if (esd_buf[2] == (u8)GTP_ESD_CHECK_VALUE || + esd_buf[3] != (u8)GTP_ESD_CHECK_VALUE) { + i = 3; + break; + } + } else { + /* IC works normally, Write 0x8040 0xAA, feed the dog */ + esd_buf[2] = (u8)GTP_ESD_CHECK_VALUE; + gtp_i2c_write(ts->client, esd_buf, 3); + break; + } + } + if (i >= 3) { + dev_err(&ts->client->dev, "IC working abnormally! Reset IC\n"); + esd_buf[0] = 0x42; + esd_buf[1] = 0x26; + esd_buf[2] = 0x01; + esd_buf[3] = 0x01; + esd_buf[4] = 0x01; + gtp_i2c_write(ts->client, esd_buf, 5); + /* TODO: Is power off really need? */ + msleep(GTP_50_DLY_MS); + gtp_power_off(ts); + msleep(GTP_20_DLY_MS); + gtp_power_on(ts); + msleep(GTP_20_DLY_MS); + + gtp_reset_guitar(ts->client, 50); + msleep(GTP_50_DLY_MS); + gtp_send_cfg(ts->client); + } + + if (ts_esd->esd_on == true && !test_bit(SLEEP_MODE, &ts->flags)) { + schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); + dev_dbg(&ts->client->dev, "ESD work rescheduled\n"); + } +} + +static int gtp_esd_init(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + INIT_DELAYED_WORK(&ts_esd->delayed_work, gtp_esd_check_func); + mutex_init(&ts_esd->mutex); + ts_esd->esd_on = false; + + return 0; +} + +void gtp_esd_on(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + if (!ts->pdata->esd_protect) + return; + mutex_lock(&ts_esd->mutex); + if (ts_esd->esd_on == false) { + ts_esd->esd_on = true; + schedule_delayed_work(&ts_esd->delayed_work, 2 * HZ); + dev_info(&ts->client->dev, "ESD on"); + } + mutex_unlock(&ts_esd->mutex); +} + +void gtp_esd_off(struct goodix_ts_data *ts) +{ + struct goodix_ts_esd *ts_esd = &ts->ts_esd; + + if (!ts->pdata->esd_protect) + return; + mutex_lock(&ts_esd->mutex); + if (ts_esd->esd_on == true) { + ts_esd->esd_on = false; + cancel_delayed_work_sync(&ts_esd->delayed_work); + dev_info(&ts->client->dev, "ESD off"); + } + mutex_unlock(&ts_esd->mutex); +} + +#ifdef CONFIG_OF +static const struct of_device_id gtp_match_table[] = { + {.compatible = "goodix,gt9xx",}, + { }, +}; +#endif + +static const struct i2c_device_id gtp_device_id[] = { + { GTP_I2C_NAME, 0 }, + { } +}; + +static struct i2c_driver goodix_ts_driver = { + .probe = gtp_probe, + .remove = gtp_drv_remove, + .id_table = gtp_device_id, + .shutdown = gtp_shutdown, + .driver = { + .name = GTP_I2C_NAME, + .owner = THIS_MODULE, +#ifdef CONFIG_OF + .of_match_table = gtp_match_table, +#endif +#if !defined(CONFIG_FB) && defined(CONFIG_PM) + .pm = >p_pm_ops, +#endif + }, +}; + +static int __init gtp_init(void) +{ + s32 ret; + + pr_info("Gt9xx driver installing..\n"); + ret = i2c_add_driver(&goodix_ts_driver); + + return ret; +} + +static void __exit gtp_exit(void) +{ + pr_info("Gt9xx driver exited\n"); + i2c_del_driver(&goodix_ts_driver); +} + +module_init(gtp_init); +module_exit(gtp_exit); + +MODULE_DESCRIPTION("GT9 serials touch controller Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h new file mode 100644 index 0000000000000000000000000000000000000000..78fa3382487d3c5c73289dae8f0e677efe594881 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx.h @@ -0,0 +1,375 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * Version: 2.8.0.2 + * Release Date: 2017/12/14 + */ + +#ifndef _GOODIX_GT9XX_H_ +#define _GOODIX_GT9XX_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_OF +#include +#endif +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include + +#define GTP_TOOL_PEN 1 +#define GTP_TOOL_FINGER 2 + +#define MAX_KEY_NUMS 4 +#define GTP_CONFIG_MAX_LENGTH 240 +#define GTP_ADDR_LENGTH 2 + +/***************************PART1:ON/OFF define*******************************/ +#define GTP_DEBUG_ON 1 +#define GTP_DEBUG_ARRAY_ON 0 +#define GTP_DEBUG_FUNC_ON 0 + +struct goodix_point_t { + int id; + int x; + int y; + int w; + int p; + int tool_type; +}; + +struct goodix_config_data { + int length; + u8 data[GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH]; +}; + +struct goodix_ts_platform_data { + int irq_gpio; + int rst_gpio; + u32 irq_flags; + u32 abs_size_x; + u32 abs_size_y; + u32 max_touch_id; + u32 max_touch_width; + u32 max_touch_pressure; + u32 key_map[MAX_KEY_NUMS]; + u32 key_nums; + u32 int_sync; + u32 driver_send_cfg; + u32 swap_x2y; + u32 slide_wakeup; + u32 auto_update; + u32 auto_update_cfg; + u32 esd_protect; + u32 type_a_report; + u32 power_off_sleep; + u32 resume_in_workqueue; + u32 pen_suppress_finger; + struct goodix_config_data config; +}; + +struct goodix_ts_esd { + struct delayed_work delayed_work; + struct mutex mutex; + bool esd_on; +}; + +enum { + REPORT_THREAD_ENABLED = 0, + HRTIMER_USED, + FW_ERROR, + + DOZE_MODE, + SLEEP_MODE, + POWER_OFF_MODE, + RAW_DATA_MODE, + + FW_UPDATE_RUNNING, + PANEL_RESETTING +}; + +struct goodix_pinctrl { + struct pinctrl *pinctrl; + struct pinctrl_state *int_default; + struct pinctrl_state *int_out_high; + struct pinctrl_state *int_out_low; + struct pinctrl_state *int_input; + struct pinctrl_state *rst_default; + struct pinctrl_state *rst_out_high; + struct pinctrl_state *rst_out_low; + struct pinctrl_state *rst_input; +}; + +struct goodix_fw_info { + u8 pid[6]; + u16 version; + u8 sensor_id; +}; + +struct goodix_ts_data { + unsigned long flags; /* This member record the device status */ + + struct goodix_ts_esd ts_esd; + struct i2c_client *client; + struct input_dev *input_dev; + struct input_dev *pen_dev; + struct goodix_ts_platform_data *pdata; + /* use pinctrl control int-pin output low or high */ + struct goodix_pinctrl pinctrl; + struct hrtimer timer; + struct mutex lock; + struct notifier_block ps_notif; + struct regulator *vdd_ana; + struct regulator *vcc_i2c; +#if defined(CONFIG_FB) + struct notifier_block notifier; + struct work_struct fb_notify_work; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + struct goodix_fw_info fw_info; + bool force_update; + bool init_done; +}; + +/************************* PART2:TODO define *******************************/ +/* STEP_1(REQUIRED): Define Configuration Information Group(s) + * Sensor_ID Map: + * sensor_opt1 sensor_opt2 Sensor_ID + * GND GND 0 + * VDDIO GND 1 + * NC GND 2 + * GND NC/300K 3 + * VDDIO NC/300K 4 + * NC NC/300K 5 + */ +/* TODO: define your own default or for Sensor_ID == 0 config here. + * The predefined one is just a sample config, + * which is not suitable for your tp in most cases. + */ +#define CTP_CFG_GROUP0 {\ + 0x41, 0xD0, 0x02, 0x00, 0x05, 0x0A, 0x34, \ + 0x00, 0x01, 0x08, 0x28, 0x05, 0x50, 0x32, \ + 0x03, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x17, 0x19, 0x1E, 0x14, 0x8C, \ + 0x2D, 0x0E, 0x3C, 0x3E, 0x82, 0x0A, 0x82, \ + 0x0A, 0x00, 0x99, 0x33, 0x1D, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x2B, 0x19, 0x64, 0x94, 0xC0, 0x02, \ + 0x08, 0x00, 0x00, 0x04, 0xF2, 0x1C, 0x00, \ + 0xB9, 0x26, 0x00, 0x93, 0x32, 0x00, 0x77, \ + 0x42, 0x00, 0x62, 0x57, 0x00, 0x62, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0xFF, 0x65, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x19, 0x46, 0x00, 0x00, 0x00, 0x00, 0x32, \ + 0x1C, 0x1A, 0x18, 0x16, 0x14, 0x12, 0x10, \ + 0x0E, 0x0C, 0x0A, 0x08, 0x06, 0x04, 0x02, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x02, 0x04, 0x06, 0x08, \ + 0x0A, 0x0C, 0x0F, 0x10, 0x12, 0x13, 0x14, \ + 0x18, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, \ + 0x22, 0x24, 0x26, 0x28, 0x29, 0x2A, 0xFF, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0xB8, 0x01\ +} + +/* TODO: define your config for Sensor_ID == 1 here, if needed */ +#define CTP_CFG_GROUP1 {\ +} + +/* TODO: define your config for Sensor_ID == 2 here, if needed */ +#define CTP_CFG_GROUP2 {\ +} + +/* TODO: define your config for Sensor_ID == 3 here, if needed */ +#define CTP_CFG_GROUP3 {\ +} +/* TODO: define your config for Sensor_ID == 4 here, if needed */ +#define CTP_CFG_GROUP4 {\ +} + +/* TODO: define your config for Sensor_ID == 5 here, if needed */ +#define CTP_CFG_GROUP5 {\ +} + +/* STEP_2(REQUIRED): Customize your I/O ports & I/O operations */ +#define GTP_RST_PORT 64 /* EXYNOS4_GPX2(0) */ +#define GTP_INT_PORT 65 /* EXYNOS4_GPX2(1) */ + +#define GTP_GPIO_AS_INPUT(pin) (gpio_direction_input(pin)) +#define GTP_GPIO_AS_INT(pin) (GTP_GPIO_AS_INPUT(pin)) +#define GTP_GPIO_GET_VALUE(pin) gpio_get_value(pin) +#define GTP_GPIO_OUTPUT(pin, level) gpio_direction_output(pin, level) +#define GTP_GPIO_REQUEST(pin, label) gpio_request(pin, label) +#define GTP_GPIO_FREE(pin) gpio_free(pin) + +/* STEP_3(optional): Specify your special config info if needed */ +#define GTP_DEFAULT_MAX_X 720 /* default coordinate max values */ +#define GTP_DEFAULT_MAX_Y 1080 +#define GTP_DEFAULT_MAX_WIDTH 1024 +#define GTP_DEFAULT_MAX_PRESSURE 1024 +#define GTP_DEFAULT_INT_TRIGGER 1 /* 1 rising, 2 falling */ +#define GTP_MAX_TOUCH_ID 16 + +/* STEP_4(optional): If keys are available and reported as keys, + * config your key info here + */ +#define GTP_KEY_TAB {KEY_MENU, KEY_HOME, KEY_BACK, KEY_HOMEPAGE, \ + KEY_F1, KEY_F2, KEY_F3} + +/**************************PART3:OTHER define*******************************/ +#define GTP_DRIVER_VERSION "V2.8.0.2<2017/12/14>" +#define GTP_I2C_NAME "goodix-ts" +#define GT91XX_CONFIG_PROC_FILE "gt9xx_config" +#define GTP_POLL_TIME 10 +#define GTP_CONFIG_MIN_LENGTH 186 +#define GTP_ESD_CHECK_VALUE 0xAA +#define RETRY_MAX_TIMES 5 +#define PEN_TRACK_ID 9 +#define MASK_BIT_8 0x80 +#define FAIL 0 +#define SUCCESS 1 + +/* Registers define */ +#define GTP_REG_COMMAND 0x8040 +#define GTP_REG_ESD_CHECK 0x8041 +#define GTP_REG_COMMAND_CHECK 0x8046 +#define GTP_REG_CONFIG_DATA 0x8047 +#define GTP_REG_VERSION 0x8140 +#define GTP_REG_SENSOR_ID 0x814A +#define GTP_REG_DOZE_BUF 0x814B +#define GTP_READ_COOR_ADDR 0x814E + +/* Sleep time define */ +#define GTP_1_DLY_MS 1 +#define GTP_2_DLY_MS 2 +#define GTP_10_DLY_MS 10 +#define GTP_20_DLY_MS 20 +#define GTP_50_DLY_MS 50 +#define GTP_58_DLY_MS 58 +#define GTP_100_DLY_MS 100 +#define GTP_500_DLY_MS 500 +#define GTP_1000_DLY_MS 1000 +#define GTP_3000_DLY_MS 3000 + +#define RESOLUTION_LOC 3 +#define TRIGGER_LOC 8 + +#define CFG_GROUP_LEN(p_cfg_grp) ARRAY_SIZE(p_cfg_grp) +/* Log define */ +#define GTP_DEBUG(fmt, arg...) \ +do { \ + if (GTP_DEBUG_ON) {\ + pr_info("<<-GTP-DEBUG->> [%d]"fmt"\n", __LINE__, ##arg);\ + } \ +} while (0) +#define GTP_DEBUG_ARRAY(array, num) \ +do { \ + s32 i;\ + u8 *a = array;\ + if (GTP_DEBUG_ARRAY_ON) {\ + pr_warn("<<-GTP-DEBUG-ARRAY->>\n");\ + for (i = 0; i < (num); i++) {\ + pr_warn("%02x ", (a)[i]);\ + if ((i + 1) % 10 == 0) {\ + pr_warn("\n");\ + } \ + } \ + pr_warn("\n");\ + } \ +} while (0) +#define GTP_DEBUG_FUNC() \ +do {\ + if (GTP_DEBUG_FUNC_ON) {\ + pr_warn("<<-GTP-FUNC->> Func:%s@Line:%d\n", \ + __func__, __LINE__);\ + } \ +} while (0) +#define GTP_SWAP(x, y) \ +do {\ + typeof(x) z = x;\ + x = y;\ + y = z;\ +} while (0) + +/******************************End of Part III********************************/ +#ifdef CONFIG_OF +extern int gtp_parse_dt_cfg(struct device *dev, u8 *cfg, int *cfg_len, u8 sid); +#endif + +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern void gtp_int_sync(struct goodix_ts_data *ts, s32 ms); +extern void gtp_esd_on(struct goodix_ts_data *ts); +extern void gtp_esd_off(struct goodix_ts_data *ts); +extern void gtp_work_control_enable(struct goodix_ts_data *ts, bool enable); + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_UPDATE +extern u16 show_len; +extern u16 total_len; +extern u8 gup_init_update_proc(struct goodix_ts_data *ts); +extern s32 gup_update_proc(void *dir); +extern s32 gup_enter_update_mode(struct i2c_client *client); +extern void gup_leave_update_mode(struct i2c_client *client); +#endif + +#ifdef CONFIG_TOUCHSCREEN_GT9XX_TOOL +extern s32 init_wr_node(struct i2c_client *client); +extern void uninit_wr_node(void); +#endif + +/*********** For gt9xx_update Start *********/ +extern struct i2c_client *i2c_connect_client; +extern void gtp_reset_guitar(struct i2c_client *client, s32 ms); +extern void gtp_int_output(struct goodix_ts_data *ts, int level); +extern void gtp_rst_output(struct goodix_ts_data *ts, int level); +extern void gtp_rst_input(struct goodix_ts_data *ts); +extern s32 gtp_send_cfg(struct i2c_client *client); +extern s32 gtp_get_fw_info(struct i2c_client *client, + struct goodix_fw_info *fw_info); +extern s32 gtp_i2c_read_dbl_check(struct i2c_client *client, + u16 addr, u8 *rxbuf, int len); +extern int gtp_i2c_read(struct i2c_client *client, u8 *buf, int len); +extern int gtp_i2c_write(struct i2c_client *client, u8 *buf, int len); +extern s32 gtp_fw_startup(struct i2c_client *client); +extern int gtp_ascii_to_array(const u8 *src_buf, int src_len, u8 *dst_buf); +/*********** For gt9xx_update End *********/ + +#endif /* _GOODIX_GT9XX_H_ */ diff --git a/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c new file mode 100644 index 0000000000000000000000000000000000000000..7a428a3f6c6f0f5feefc06aea9f19e2c13270cb7 --- /dev/null +++ b/drivers/input/touchscreen/gt9xx_v2.8/gt9xx_update.c @@ -0,0 +1,2090 @@ +/* + * Goodix GT9xx touchscreen driver + * + * Copyright (C) 2016 - 2017 Goodix. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be a reference + * to you, when you are integrating the GOODiX's CTP IC into your system, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#include +#include "gt9xx.h" + +#include +#include +#include +#include + +#define GUP_REG_HW_INFO 0x4220 +#define GUP_REG_FW_MSG 0x41E4 +#define GUP_REG_PID_VID 0x8140 + +#define FIRMWARE_NAME_LEN_MAX 256 +#define GOODIX_FIRMWARE_FILE_NAME "goodix_firmware.bin" +#define GOODIX_CONFIG_FILE_NAME "goodix_config.cfg" + +#define FW_HEAD_LENGTH 14 +#define FW_SECTION_LENGTH 0x2000 /* 8K */ +#define FW_DSP_ISP_LENGTH 0x1000 /* 4K */ +#define FW_DSP_LENGTH 0x1000 /* 4K */ +#define FW_BOOT_LENGTH 0x800 /* 2K */ +#define FW_SS51_LENGTH (4 * FW_SECTION_LENGTH) /* 32K */ +#define FW_BOOT_ISP_LENGTH 0x800 /* 2k */ +#define FW_GLINK_LENGTH 0x3000 /* 12k */ +#define FW_GWAKE_LENGTH (4 * FW_SECTION_LENGTH) /* 32k */ + +#define DELAY_FOR_SENDCFG 500 +#define PACK_SIZE 256 +#define MAX_FRAME_CHECK_TIME 5 + +#define _bRW_MISCTL__SRAM_BANK 0x4048 +#define _bRW_MISCTL__MEM_CD_EN 0x4049 +#define _bRW_MISCTL__CACHE_EN 0x404B +#define _bRW_MISCTL__TMR0_EN 0x40B0 +#define _rRW_MISCTL__SWRST_B0_ 0x4180 +#define _bWO_MISCTL__CPU_SWRST_PULSE 0x4184 +#define _rRW_MISCTL__BOOTCTL_B0_ 0x4190 +#define _rRW_MISCTL__BOOT_OPT_B0_ 0x4218 +#define _rRW_MISCTL__BOOT_CTL_ 0x5094 + +#pragma pack(1) +struct st_fw_head { + u8 hw_info[4]; /* hardware info */ + u8 pid[8]; /* product id */ + u16 vid; /* version id */ +}; +#pragma pack() + +struct st_update_msg { + u8 fw_damaged; + u8 fw_flag; + const u8 *fw_data; + struct file *cfg_file; + struct st_fw_head ic_fw_msg; + u32 fw_total_len; + u32 fw_burned_len; + const struct firmware *fw; +} update_msg; + +struct st_update_msg update_msg; + +u16 show_len; +u16 total_len; + +static u8 gup_burn_fw_gwake_section(struct i2c_client *client, + u8 *fw_section, u16 start_addr, + u32 len, u8 bank_cmd); + +static s32 gup_init_panel(struct goodix_ts_data *ts) +{ + s32 ret = 0; + u8 opr_buf[16]; + u8 sensor_id = 0; + u8 drv_cfg_version; + u8 flash_cfg_version; + struct goodix_config_data *cfg = &ts->pdata->config; + + if (cfg->length < GTP_CONFIG_MIN_LENGTH) { + dev_err(&ts->client->dev, + "No valid config with sensor_ID(%d) ", + sensor_id); + + return -EPERM; + } + + ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA, + &opr_buf[0], 1); + if (ret == SUCCESS) { + dev_dbg(&ts->client->dev, + "CFG_GROUP%d Config Version: %d, IC Config Version: %d", + sensor_id, cfg->data[GTP_ADDR_LENGTH], opr_buf[0]); + + flash_cfg_version = opr_buf[0]; + drv_cfg_version = cfg->data[GTP_ADDR_LENGTH]; + + if (flash_cfg_version < 90 && + flash_cfg_version > drv_cfg_version) + cfg->data[GTP_ADDR_LENGTH] = 0x00; + } else { + dev_err(&ts->client->dev, + "Failed to get ic config version!No config sent!"); + return -EPERM; + } + + ret = gtp_send_cfg(ts->client); + if (ret < 0) + dev_err(&ts->client->dev, "Send config error."); + else + usleep_range(10000, 11000); + + /* restore config vrsion */ + cfg->data[GTP_ADDR_LENGTH] = drv_cfg_version; + + return 0; +} + + +static u8 gup_get_ic_msg(struct i2c_client *client, u16 addr, u8 *msg, s32 len) +{ + s32 i = 0; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + + for (i = 0; i < 5; i++) { + if (gtp_i2c_read(client, msg, GTP_ADDR_LENGTH + len) > 0) + break; + } + + if (i >= 5) { + dev_err(&client->dev, + "Read data from 0x%02x%02x failed!", + msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_set_ic_msg(struct i2c_client *client, u16 addr, u8 val) +{ + s32 i = 0; + u8 msg[3]; + + msg[0] = (addr >> 8) & 0xff; + msg[1] = addr & 0xff; + msg[2] = val; + + for (i = 0; i < 5; i++) { + if (gtp_i2c_write(client, msg, GTP_ADDR_LENGTH + 1) > 0) + break; + } + + if (i >= 5) { + dev_err(&client->dev, + "Set data to 0x%02x%02x failed!", msg[0], msg[1]); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_get_ic_fw_msg(struct i2c_client *client) +{ + s32 ret = -1; + u8 retry = 0; + u8 buf[16]; + u8 i; + + /* step1:get hardware info */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_HW_INFO, + &buf[GTP_ADDR_LENGTH], 4); + if (ret == FAIL) { + dev_err(&client->dev, "[get_ic_fw_msg]get hw_info failed,exit"); + return FAIL; + } + + /* buf[2~5]: 00 06 90 00 + * hw_info: 00 90 06 00 + */ + for (i = 0; i < 4; i++) + update_msg.ic_fw_msg.hw_info[i] = buf[GTP_ADDR_LENGTH + 3 - i]; + dev_dbg(&client->dev, + "IC Hardware info:%02x%02x%02x%02x", + update_msg.ic_fw_msg.hw_info[0], + update_msg.ic_fw_msg.hw_info[1], + update_msg.ic_fw_msg.hw_info[2], + update_msg.ic_fw_msg.hw_info[3]); + /* step2:get firmware message */ + for (retry = 0; retry < 2; retry++) { + ret = gup_get_ic_msg(client, GUP_REG_FW_MSG, buf, 1); + if (ret == FAIL) { + dev_err(&client->dev, "Read firmware message fail."); + return ret; + } + + update_msg.fw_damaged = buf[GTP_ADDR_LENGTH]; + if ((update_msg.fw_damaged != 0xBE) && (!retry)) { + dev_info(&client->dev, "The check sum in ic is error."); + dev_info(&client->dev, "The IC will be updated by force."); + continue; + } + break; + } + dev_dbg(&client->dev, + "IC force update flag:0x%x", update_msg.fw_damaged); + + /* step3:get pid & vid */ + ret = gtp_i2c_read_dbl_check(client, GUP_REG_PID_VID, + &buf[GTP_ADDR_LENGTH], 6); + if (ret == FAIL) { + dev_err(&client->dev, "[get_ic_fw_msg]get pid & vid failed,exit"); + return FAIL; + } + + memset(update_msg.ic_fw_msg.pid, 0, sizeof(update_msg.ic_fw_msg.pid)); + memcpy(update_msg.ic_fw_msg.pid, &buf[GTP_ADDR_LENGTH], 4); + dev_dbg(&client->dev, "IC Product id:%s", update_msg.ic_fw_msg.pid); + + /* GT9XX PID MAPPING */ + /*|-----FLASH-----RAM-----| + *|------918------918-----| + *|------968------968-----| + *|------913------913-----| + *|------913P-----913P----| + *|------927------927-----| + *|------927P-----927P----| + *|------9110-----9110----| + *|------9110P----9111----| + */ + if (update_msg.ic_fw_msg.pid[0] != 0) { + if (!memcmp(update_msg.ic_fw_msg.pid, "9111", 4)) { + dev_dbg(&client->dev, "IC Mapping Product id:%s", + update_msg.ic_fw_msg.pid); + memcpy(update_msg.ic_fw_msg.pid, "9110P", 5); + } + } + + update_msg.ic_fw_msg.vid = buf[GTP_ADDR_LENGTH + 4] + + (buf[GTP_ADDR_LENGTH + 5] << 8); + dev_dbg(&client->dev, "IC version id:%04x", update_msg.ic_fw_msg.vid); + + return SUCCESS; +} + +s32 gup_enter_update_mode(struct i2c_client *client) +{ + s32 ret = -1; + s32 retry = 0; + u8 rd_buf[3]; + + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + /* step1:RST output low last at least 2ms */ + if (!gpio_is_valid(ts->pdata->rst_gpio)) { + dev_err(&ts->client->dev, "update failed, no rst pin\n"); + return FAIL; + } + gtp_rst_output(ts, 0); + usleep_range(2000, 3000); + + /* step2:select I2C slave addr,INT:0--0xBA;1--0x28. */ + gtp_int_output(ts, client->addr == 0x14); + usleep_range(2000, 3000); + + /* step3:RST output high reset guitar */ + gtp_rst_output(ts, 1); + + /* 20121211 modify start */ + usleep_range(5000, 6000); + while (retry++ < 200) { + /* step4:Hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_dbg(&client->dev, + "Hold ss51 & dsp I2C error,retry:%d", + retry); + continue; + } + + /* step5:Confirm hold */ + ret = gup_get_ic_msg(client, _rRW_MISCTL__SWRST_B0_, rd_buf, 1); + if (ret <= 0) { + dev_dbg(&client->dev, + "Hold ss51 & dsp I2C error,retry:%d", + retry); + continue; + } + if (rd_buf[GTP_ADDR_LENGTH] == 0x0C) { + dev_dbg(&client->dev, "Hold ss51 & dsp confirm SUCCESS"); + break; + } + dev_dbg(&client->dev, + "Hold ss51 & dsp confirm 0x4180 failed,value:%d", + rd_buf[GTP_ADDR_LENGTH]); + } + if (retry >= 200) { + dev_err(&client->dev, "Enter update Hold ss51 failed."); + return FAIL; + } + + /* step6:DSP_CK and DSP_ALU_CK PowerOn */ + ret = gup_set_ic_msg(client, 0x4010, 0x00); + + /* 20121211 modify end */ + return ret; +} + +void gup_leave_update_mode(struct i2c_client *client) +{ + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts->pdata->int_sync && ts->pinctrl.pinctrl) + pinctrl_select_state(ts->pinctrl.pinctrl, + ts->pinctrl.int_input); + else if (ts->pdata->int_sync && gpio_is_valid(ts->pdata->irq_gpio)) + gpio_direction_input(ts->pdata->irq_gpio); + dev_dbg(&client->dev, "[leave_update_mode]reset chip."); + gtp_reset_guitar(i2c_connect_client, 20); +} + +static u8 gup_enter_update_judge(struct i2c_client *client, + struct st_fw_head *fw_head) +{ + u16 u16_tmp; + s32 i = 0; + u32 fw_len = 0; + s32 pid_cmp_len = 0; + + u16_tmp = fw_head->vid; + fw_head->vid = (u16)(u16_tmp>>8) + (u16)(u16_tmp<<8); + + dev_info(&client->dev, "FILE HARDWARE INFO:%*ph\n", 4, + &fw_head->hw_info[0]); + dev_info(&client->dev, "FILE PID:%s\n", fw_head->pid); + dev_info(&client->dev, "FILE VID:%04x\n", fw_head->vid); + + dev_info(&client->dev, "IC HARDWARE INFO:%*ph\n", 4, + &update_msg.ic_fw_msg.hw_info[0]); + dev_info(&client->dev, "IC PID:%s\n", update_msg.ic_fw_msg.pid); + dev_info(&client->dev, "IC VID:%04x\n", update_msg.ic_fw_msg.vid); + + if (!memcmp(fw_head->pid, "9158", 4) && + !memcmp(update_msg.ic_fw_msg.pid, "915S", 4)) { + dev_info(&client->dev, "Update GT915S to GT9158 directly!"); + return SUCCESS; + } + /* First two conditions */ + if (!memcmp(fw_head->hw_info, update_msg.ic_fw_msg.hw_info, + sizeof(update_msg.ic_fw_msg.hw_info))) { + fw_len = 42 * 1024; + } else { + fw_len = fw_head->hw_info[3]; + fw_len += (((u32)fw_head->hw_info[2]) << 8); + fw_len += (((u32)fw_head->hw_info[1]) << 16); + fw_len += (((u32)fw_head->hw_info[0]) << 24); + } + if (update_msg.fw_total_len != fw_len) { + dev_err(&client->dev, + "Inconsistent firmware size, Update aborted!"); + dev_err(&client->dev, + " Default size: %d(%dK), actual size: %d(%dK)", + fw_len, fw_len/1024, update_msg.fw_total_len, + update_msg.fw_total_len/1024); + return FAIL; + } + dev_info(&client->dev, "Firmware length:%d(%dK)", + update_msg.fw_total_len, + update_msg.fw_total_len/1024); + + if (update_msg.fw_damaged != 0xBE) { + dev_info(&client->dev, "FW chksum error,need enter update."); + return SUCCESS; + } + + /* 20130523 start */ + if (strlen(update_msg.ic_fw_msg.pid) < 3) { + dev_info(&client->dev, "Illegal IC pid, need enter update"); + return SUCCESS; + } + + /* check pid legality */ + for (i = 0; i < 3; i++) { + if (!isdigit(update_msg.ic_fw_msg.pid[i])) { + dev_info(&client->dev, + "Illegal IC pid, need enter update"); + return SUCCESS; + } + } + /* 20130523 end */ + + pid_cmp_len = strlen(fw_head->pid); + if (pid_cmp_len < strlen(update_msg.ic_fw_msg.pid)) + pid_cmp_len = strlen(update_msg.ic_fw_msg.pid); + + if ((!memcmp(fw_head->pid, update_msg.ic_fw_msg.pid, pid_cmp_len)) || + (!memcmp(update_msg.ic_fw_msg.pid, "91XX", 4)) || + (!memcmp(fw_head->pid, "91XX", 4))) { + if (!memcmp(fw_head->pid, "91XX", 4)) + dev_dbg(&client->dev, + "Force none same pid update mode."); + else + dev_dbg(&client->dev, "Get the same pid."); + + /* The third condition */ + if (fw_head->vid != update_msg.ic_fw_msg.vid) { + dev_info(&client->dev, "Need enter update."); + return SUCCESS; + } + dev_err(&client->dev, "File VID == Ic VID, update aborted!"); + } else { + dev_err(&client->dev, "File PID != Ic PID, update aborted!"); + } + + return FAIL; +} + +static int gup_update_config(struct i2c_client *client) +{ + s32 ret = 0; + s32 i = 0; + s32 file_cfg_len = 0; + u8 *file_config; + const struct firmware *fw_cfg; + + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + ret = request_firmware(&fw_cfg, GOODIX_CONFIG_FILE_NAME, + &client->dev); + if (ret < 0) { + dev_err(&client->dev, + "Cannot get config file - %s (%d)\n", + GOODIX_CONFIG_FILE_NAME, ret); + return -EFAULT; + } + if (!fw_cfg || !fw_cfg->data || fw_cfg->size > PAGE_SIZE) { + dev_err(&client->dev, "config file illegal"); + ret = -EFAULT; + goto cfg_fw_err; + } + + dev_dbg(&client->dev, "config firmware file len:%zu", fw_cfg->size); + + file_config = kzalloc(GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH, + GFP_KERNEL); + if (!file_config) { + ret = -ENOMEM; + goto cfg_fw_err; + } + file_config[0] = GTP_REG_CONFIG_DATA >> 8; + file_config[1] = GTP_REG_CONFIG_DATA & 0xff; + file_cfg_len = gtp_ascii_to_array(fw_cfg->data, fw_cfg->size, + &file_config[GTP_ADDR_LENGTH]); + if (file_cfg_len < 0) { + dev_err(&client->dev, "failed covert ascii to hex"); + ret = -EFAULT; + goto update_cfg_file_failed; + } + + GTP_DEBUG_ARRAY(file_config + GTP_ADDR_LENGTH, file_cfg_len); + + i = 0; + while (i++ < 5) { + ret = gtp_i2c_write(client, file_config, file_cfg_len + 2); + if (ret > 0) { + dev_info(&client->dev, "Send config SUCCESS."); + msleep(DELAY_FOR_SENDCFG); + break; + } + dev_err(&ts->client->dev, "Send config i2c error."); + } + +update_cfg_file_failed: + kfree(file_config); +cfg_fw_err: + release_firmware(fw_cfg); + return ret; +} + +static u8 gup_check_firmware_name(struct i2c_client *client, + u8 **path_p) +{ + u8 len; + u8 *fname; + + if (!(*path_p)) { + *path_p = GOODIX_FIRMWARE_FILE_NAME; + return 0; + } + + len = strnlen(*path_p, FIRMWARE_NAME_LEN_MAX); + if (len >= FIRMWARE_NAME_LEN_MAX) { + dev_err(&client->dev, "firmware name too long!"); + return -EINVAL; + } + + fname = strrchr(*path_p, '/'); + if (fname) { + fname = fname + 1; + *path_p = fname; + } + + return 0; +} + +static u8 gup_get_update_file(struct i2c_client *client, + struct st_fw_head *fw_head, u8 *path) +{ + s32 ret = 0; + s32 i = 0; + s32 fw_checksum = 0; + struct goodix_ts_data *ts = i2c_get_clientdata(client); + + if (ts->pdata->auto_update_cfg) { + ret = gup_update_config(client); + if (ret <= 0) + dev_err(&client->dev, "Update config failed."); + } + + ret = gup_check_firmware_name(client, &path); + if (ret < 0) + return FAIL; + + ret = request_firmware(&update_msg.fw, path, &client->dev); + if (ret < 0) { + dev_err(&client->dev, "Failed get firmware:%d\n", ret); + return FAIL; + } + + dev_info(&client->dev, "FW File: %s size=%zu", + path, update_msg.fw->size); + update_msg.fw_data = update_msg.fw->data; + update_msg.fw_total_len = update_msg.fw->size; + + if (update_msg.fw_total_len < + FW_HEAD_LENGTH + FW_SECTION_LENGTH * 4 + FW_DSP_ISP_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH) { + dev_err(&client->dev, + "INVALID bin file(size: %d), update aborted.", + update_msg.fw_total_len); + goto invalied_fw; + } + + update_msg.fw_total_len -= FW_HEAD_LENGTH; + + dev_dbg(&client->dev, "Bin firmware actual size: %d(%dK)", + update_msg.fw_total_len, update_msg.fw_total_len/1024); + + memcpy(fw_head, update_msg.fw_data, FW_HEAD_LENGTH); + + /* check firmware legality */ + fw_checksum = 0; + for (i = 0; i < update_msg.fw_total_len; i += 2) { + u16 temp; + + temp = (update_msg.fw_data[FW_HEAD_LENGTH + i] << 8) + + update_msg.fw_data[FW_HEAD_LENGTH + i + 1]; + fw_checksum += temp; + } + + dev_dbg(&client->dev, "firmware checksum:%x", fw_checksum&0xFFFF); + if (fw_checksum & 0xFFFF) { + dev_err(&client->dev, "Illegal firmware file."); + goto invalied_fw; + } + + return SUCCESS; + +invalied_fw: + update_msg.fw_data = NULL; + update_msg.fw_total_len = 0; + release_firmware(update_msg.fw); + return FAIL; +} + +static u8 gup_burn_proc(struct i2c_client *client, u8 *burn_buf, + u16 start_addr, u16 total_length) +{ + s32 ret = 0; + u16 burn_addr = start_addr; + u16 frame_length = 0; + u16 burn_length = 0; + u8 wr_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + u8 retry = 0; + + dev_dbg(&client->dev, "Begin burn %dk data to addr 0x%x", + total_length / 1024, start_addr); + while (burn_length < total_length) { + dev_dbg(&client->dev, + "B/T:%04d/%04d", burn_length, total_length); + frame_length = ((total_length - burn_length) + > PACK_SIZE) ? PACK_SIZE : (total_length - burn_length); + wr_buf[0] = (u8)(burn_addr>>8); + rd_buf[0] = wr_buf[0]; + wr_buf[1] = (u8)burn_addr; + rd_buf[1] = wr_buf[1]; + memcpy(&wr_buf[GTP_ADDR_LENGTH], + &burn_buf[burn_length], frame_length); + + for (retry = 0; retry < MAX_FRAME_CHECK_TIME; retry++) { + ret = gtp_i2c_write(client, + wr_buf, GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + dev_err(&client->dev, + "Write frame data i2c error."); + continue; + } + ret = gtp_i2c_read(client, rd_buf, + GTP_ADDR_LENGTH + frame_length); + if (ret <= 0) { + dev_err(&client->dev, + "Read back frame data i2c error."); + continue; + } + if (memcmp(&wr_buf[GTP_ADDR_LENGTH], + &rd_buf[GTP_ADDR_LENGTH], frame_length)) { + dev_err(&client->dev, + "Check frame data fail,not equal."); + dev_dbg(&client->dev, "write array:"); + GTP_DEBUG_ARRAY(&wr_buf[GTP_ADDR_LENGTH], + frame_length); + dev_dbg(&client->dev, "read array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], + frame_length); + continue; + } else { + /* dev_dbg(&client->dev, + * "Check frame data success."); + */ + break; + } + } + if (retry >= MAX_FRAME_CHECK_TIME) { + dev_err(&client->dev, + "Burn frame data time out,exit."); + return FAIL; + } + burn_length += frame_length; + burn_addr += frame_length; + } + + return SUCCESS; +} + +static u8 gup_load_section_file(u8 *buf, u32 offset, u16 length, u8 set_or_end) +{ + if (!update_msg.fw_data || + update_msg.fw_total_len < FW_HEAD_LENGTH + offset + length) { + pr_err("<<-GTP->> cannot load section data. fw_len=%d read end=%d\n", + update_msg.fw_total_len, + FW_HEAD_LENGTH + offset + length); + return FAIL; + } + + if (set_or_end == SEEK_SET) { + memcpy(buf, &update_msg.fw_data[FW_HEAD_LENGTH + offset], + length); + } else { + /* seek end */ + memcpy(buf, &update_msg.fw_data[update_msg.fw_total_len + + FW_HEAD_LENGTH - offset], length); + } + + return SUCCESS; +} + +static u8 gup_recall_check(struct i2c_client *client, u8 *chk_src, + u16 start_rd_addr, u16 chk_length) +{ + u8 rd_buf[PACK_SIZE + GTP_ADDR_LENGTH]; + s32 ret = 0; + u16 recall_addr = start_rd_addr; + u16 recall_length = 0; + u16 frame_length = 0; + + while (recall_length < chk_length) { + frame_length = ((chk_length - recall_length) + > PACK_SIZE) ? PACK_SIZE : + (chk_length - recall_length); + ret = gup_get_ic_msg(client, recall_addr, rd_buf, frame_length); + if (ret <= 0) { + dev_err(&client->dev, "recall i2c error,exit"); + return FAIL; + } + + if (memcmp(&rd_buf[GTP_ADDR_LENGTH], + &chk_src[recall_length], frame_length)) { + dev_err(&client->dev, "Recall frame data fail,not equal."); + dev_dbg(&client->dev, "chk_src array:"); + GTP_DEBUG_ARRAY(&chk_src[recall_length], frame_length); + dev_dbg(&client->dev, "recall array:"); + GTP_DEBUG_ARRAY(&rd_buf[GTP_ADDR_LENGTH], frame_length); + return FAIL; + } + + recall_length += frame_length; + recall_addr += frame_length; + } + dev_dbg(&client->dev, + "Recall check %dk firmware success.", + (chk_length/1024)); + + return SUCCESS; +} + +static u8 gup_burn_fw_section(struct i2c_client *client, u8 *fw_section, + u16 start_addr, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]set scramble fail."); + return FAIL; + } + + /* step3:select bank */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, + (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step4:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + /* step5:burn 8k fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, FW_SECTION_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_section]burn fw_section fail."); + return FAIL; + } + + /* step6:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step7:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0f); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_section]send burn cmd fail."); + return FAIL; + } + dev_dbg(&client->dev, + "[burn_fw_section]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]Get burn state fail"); + return FAIL; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_section]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:select bank */ + ret = gup_set_ic_msg(client, + _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4) & 0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step9:enable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]enable accessing code fail."); + return FAIL; + } + + /* step10:recall 8k fw section */ + ret = gup_recall_check(client, + fw_section, start_addr, FW_SECTION_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_section]recall check %dk firmware fail.", + FW_SECTION_LENGTH / 1024); + return FAIL; + } + + /* step11:disable accessing code */ + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]disable accessing code fail."); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_dsp_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp_isp = NULL; + u8 retry = 0; + + dev_info(&client->dev, "[burn_dsp_isp]Begin burn dsp isp---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_dsp_isp]step1:alloc memory"); + while (retry++ < 5) { + fw_dsp_isp = kzalloc(FW_DSP_ISP_LENGTH, GFP_KERNEL); + if (fw_dsp_isp == NULL) { + continue; + } else { + dev_info(&client->dev, + "[burn_dsp_isp]Alloc %dk byte memory success.", + FW_DSP_ISP_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_dsp_isp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load dsp isp file data */ + dev_dbg(&client->dev, "[burn_dsp_isp]step2:load dsp isp file data"); + ret = gup_load_section_file(fw_dsp_isp, + FW_DSP_ISP_LENGTH, FW_DSP_ISP_LENGTH, SEEK_END); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_dsp_isp]load firmware dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + /* step3:disable wdt,clear cache enable */ + dev_dbg(&client->dev, + "[burn_dsp_isp]step3:disable wdt,clear cache enable"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__TMR0_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]disable wdt fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + ret = gup_set_ic_msg(client, _bRW_MISCTL__CACHE_EN, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_dsp_isp]clear cache enable fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step4:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_dsp_isp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step5:set boot from sram */ + dev_dbg(&client->dev, "[burn_dsp_isp]step5:set boot from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOTCTL_B0_, 0x02); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]set boot from sram fail"); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step6:software reboot */ + dev_dbg(&client->dev, "[burn_dsp_isp]step6:software reboot"); + ret = gup_set_ic_msg(client, _bWO_MISCTL__CPU_SWRST_PULSE, 0x01); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]software reboot fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step7:select bank2 */ + dev_dbg(&client->dev, "[burn_dsp_isp]step7:select bank2"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x02); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]select bank2 fail"); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step8:enable accessing code */ + dev_dbg(&client->dev, "[burn_dsp_isp]step8:enable accessing code"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__MEM_CD_EN, 0x01); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_dsp_isp]enable accessing code fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + + /* step9:burn 4k dsp_isp */ + dev_dbg(&client->dev, "[burn_dsp_isp]step9:burn 4k dsp_isp"); + ret = gup_burn_proc(client, fw_dsp_isp, 0xC000, FW_DSP_ISP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_dsp_isp]burn dsp_isp fail."); + goto exit_burn_dsp_isp; + } + + /* step10:set scramble */ + dev_dbg(&client->dev, "[burn_dsp_isp]step10:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_dsp_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_dsp_isp; + } + update_msg.fw_burned_len += FW_DSP_ISP_LENGTH; + dev_dbg(&client->dev, "[burn_dsp_isp]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_dsp_isp: + kfree(fw_dsp_isp); + + return ret; +} + +static u8 gup_burn_fw_ss51(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + dev_info(&client->dev, "[burn_fw_ss51]Begin burn ss51 firmware---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_ss51]step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_ss51]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH / 1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_ss51]Alloc memory fail,exit."); + return FAIL; + } + + dev_info(&client->dev, "[burn_fw_ss51]Reset first 8K of ss51 to 0xFF."); + dev_dbg(&client->dev, "[burn_fw_ss51]step2: reset bank0 0xC000~0xD000"); + memset(fw_ss51, 0xFF, FW_SECTION_LENGTH); + + /* step3:clear control flag */ + dev_dbg(&client->dev, "[burn_fw_ss51]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_ss51]clear control flag fail."); + ret = FAIL; + goto exit_burn_fw_ss51; + } + + /* step4:burn ss51 firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_ss51; + } + + /* step5:load ss51 firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step5:load ss51 firmware section 2 file data"); + ret = gup_load_section_file(fw_ss51, + FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + /* step6:burn ss51 firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step6:burn ss51 firmware section 2"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x02); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 2 fail."); + goto exit_burn_fw_ss51; + } + + /* step7:load ss51 firmware section 3 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step7:load ss51 firmware section 3 file data"); + ret = gup_load_section_file(fw_ss51, + 2 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + /* step8:burn ss51 firmware section 3 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step8:burn ss51 firmware section 3"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x13); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 3 fail."); + goto exit_burn_fw_ss51; + } + + /* step9:load ss51 firmware section 4 file data */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step9:load ss51 firmware section 4 file data"); + ret = gup_load_section_file(fw_ss51, + 3 * FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]load ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + /* step10:burn ss51 firmware section 4 */ + dev_dbg(&client->dev, + "[burn_fw_ss51]step10:burn ss51 firmware section 4"); + ret = gup_burn_fw_section(client, fw_ss51, 0xE000, 0x14); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_ss51]burn ss51 firmware section 4 fail."); + goto exit_burn_fw_ss51; + } + + update_msg.fw_burned_len += (FW_SECTION_LENGTH*4); + dev_dbg(&client->dev, "[burn_fw_ss51]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_ss51: + kfree(fw_ss51); + return ret; +} + +static u8 gup_burn_fw_dsp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_dsp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + dev_info(&client->dev, "[burn_fw_dsp]Begin burn dsp firmware---->>"); + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_dsp]step1:alloc memory"); + while (retry++ < 5) { + fw_dsp = kzalloc(FW_DSP_LENGTH, GFP_KERNEL); + if (fw_dsp == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_dsp]Alloc %dk byte memory success.", + FW_SECTION_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_dsp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step2:load firmware dsp"); + ret = gup_load_section_file(fw_dsp, + 4 * FW_SECTION_LENGTH, FW_DSP_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_fw_dsp]load firmware dsp fail."); + goto exit_burn_fw_dsp; + } + + /* step3:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_dsp]step3:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step4:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step4:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step5:set scramble */ + dev_dbg(&client->dev, "[burn_fw_dsp]step5:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + + /* step6:release ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_dsp]step6:release ss51 & dsp"); + ret = gup_set_ic_msg( + client, _rRW_MISCTL__SWRST_B0_, 0x04);/* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_dsp; + } + /* must delay */ + usleep_range(1000, 1100); + + /* step7:burn 4k dsp firmware */ + dev_dbg(&client->dev, "[burn_fw_dsp]step7:burn 4k dsp firmware"); + ret = gup_burn_proc(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_fw_dsp]burn fw_section fail."); + goto exit_burn_fw_dsp; + } + + /* step8:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_dsp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x05); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]send burn cmd fail."); + goto exit_burn_fw_dsp; + } + dev_dbg(&client->dev, "[burn_fw_dsp]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_dsp]Get burn state fail"); + goto exit_burn_fw_dsp; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_dsp]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step9:recall check 4k dsp firmware */ + dev_dbg(&client->dev, + "[burn_fw_dsp]step9:recall check 4k dsp firmware"); + ret = gup_recall_check(client, fw_dsp, 0x9000, FW_DSP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_dsp]recall check 4k dsp firmware fail."); + goto exit_burn_fw_dsp; + } + + update_msg.fw_burned_len += FW_DSP_LENGTH; + dev_dbg(&client->dev, "[burn_fw_dsp]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_dsp: + kfree(fw_dsp); + + return ret; +} + +static u8 gup_burn_fw_boot(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + dev_info(&client->dev, + "[burn_fw_boot]Begin burn bootloader firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_boot]step1:Alloc memory"); + while (retry++ < 5) { + fw_boot = kzalloc(FW_BOOT_LENGTH, GFP_KERNEL); + if (fw_boot == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_boot]Alloc %dk byte memory success.", + FW_BOOT_LENGTH / 1024); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_boot]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + dev_dbg(&client->dev, "[burn_fw_boot]step2:load firmware bootloader"); + ret = gup_load_section_file(fw_boot, + (4 * FW_SECTION_LENGTH + FW_DSP_LENGTH), FW_BOOT_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot]load firmware bootcode fail."); + goto exit_burn_fw_boot; + } + + /* step3:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_boot]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]hold ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step4:set scramble */ + dev_dbg(&client->dev, "[burn_fw_boot]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step5:hold ss51 & release dsp */ + dev_dbg(&client->dev, "[burn_fw_boot]step5:hold ss51 & release dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + /* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]release ss51 & dsp fail"); + ret = FAIL; + goto exit_burn_fw_boot; + } + /* must delay */ + usleep_range(1000, 1100); + + /* step6:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_boot]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot; + } + + /* step6:burn 2k bootloader firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot]step6:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, "[burn_fw_boot]burn fw_boot fail."); + goto exit_burn_fw_boot; + } + + /* step7:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_boot]step7:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x06); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot]send burn cmd fail."); + goto exit_burn_fw_boot; + } + dev_dbg(&client->dev, + "[burn_fw_boot]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot]Get burn state fail"); + goto exit_burn_fw_boot; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_boot]Get burn state:%d.", + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootloader firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot]step8:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot, 0x9000, FW_BOOT_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot]recall check 2k bootcode firmware fail"); + goto exit_burn_fw_boot; + } + + update_msg.fw_burned_len += FW_BOOT_LENGTH; + dev_dbg(&client->dev, "[burn_fw_boot]Burned length:%d", + update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_boot: + kfree(fw_boot); + + return ret; +} +static u8 gup_burn_fw_boot_isp(struct i2c_client *client) +{ + s32 ret = 0; + u8 *fw_boot_isp = NULL; + u8 retry = 0; + u8 rd_buf[5]; + + if (update_msg.fw_burned_len >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the boot_isp code!"); + return SUCCESS; + } + dev_info(&client->dev, + "[burn_fw_boot_isp]Begin burn boot_isp firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step1:Alloc memory"); + while (retry++ < 5) { + fw_boot_isp = kzalloc(FW_BOOT_ISP_LENGTH, GFP_KERNEL); + if (fw_boot_isp == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Alloc %dk byte memory success.", + (FW_BOOT_ISP_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, + "[burn_fw_boot_isp]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware bootloader */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step2:load firmware bootloader isp"); + /* ret = gup_load_section_file(fw_boot_isp, + * (4*FW_SECTION_LENGTH+FW_DSP_LENGTH + + * FW_BOOT_LENGTH+FW_DSP_ISP_LENGTH), FW_BOOT_ISP_LENGTH, SEEK_SET); + */ + ret = gup_load_section_file(fw_boot_isp, + (update_msg.fw_burned_len - FW_DSP_ISP_LENGTH), + FW_BOOT_ISP_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot_isp]load firmware boot_isp fail."); + goto exit_burn_fw_boot_isp; + } + + /* step3:hold ss51 & dsp */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step3:hold ss51 & dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]hold ss51 & dsp fail"); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + /* step4:set scramble */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step4:set scramble"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]set scramble fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + + /* step5:hold ss51 & release dsp */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step5:hold ss51 & release dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + /* 20121211 */ + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot_isp]release ss51 & dsp fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step6:select bank3 */ + dev_dbg(&client->dev, "[burn_fw_boot_isp]step6:select bank3"); + ret = gup_set_ic_msg(client, _bRW_MISCTL__SRAM_BANK, 0x03); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]select bank3 fail."); + ret = FAIL; + goto exit_burn_fw_boot_isp; + } + + /* step7:burn 2k bootload_isp firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step7:burn 2k bootloader firmware"); + ret = gup_burn_proc(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot_isp]burn fw_section fail."); + goto exit_burn_fw_boot_isp; + } + + /* step7:send burn cmd to move data to flash from sram */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step8:send burn cmd to move data to flash from sram"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x07); + if (ret <= 0) { + dev_err(&client->dev, "[burn_fw_boot_isp]send burn cmd fail."); + goto exit_burn_fw_boot_isp; + } + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_boot_isp]Get burn state fail"); + goto exit_burn_fw_boot_isp; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_boot_isp]Get + * burn state:%d.", rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step8:recall check 2k bootload_isp firmware */ + dev_dbg(&client->dev, + "[burn_fw_boot_isp]step9:recall check 2k bootloader firmware"); + ret = gup_recall_check(client, fw_boot_isp, 0x9000, FW_BOOT_ISP_LENGTH); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_boot_isp]recall check 2k bootcode_isp firmware fail."); + goto exit_burn_fw_boot_isp; + } + + update_msg.fw_burned_len += FW_BOOT_ISP_LENGTH; + dev_dbg(&client->dev, + "[burn_fw_boot_isp]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_boot_isp: + kfree(fw_boot_isp); + + return ret; +} + +static u8 gup_burn_fw_link(struct i2c_client *client) +{ + u8 *fw_link = NULL; + u8 retry = 0; + s32 ret = 0; + u32 offset; + + if (update_msg.fw_burned_len >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the link code!"); + return SUCCESS; + } + dev_info(&client->dev, "[burn_fw_link]Begin burn link firmware---->>"); + + /* step1:Alloc memory */ + dev_dbg(&client->dev, "[burn_fw_link]step1:Alloc memory"); + while (retry++ < 5) { + fw_link = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_link == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_link]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_link]Alloc memory fail,exit."); + return FAIL; + } + + /* step2:load firmware link section 1 */ + dev_dbg(&client->dev, + "[burn_fw_link]step2:load firmware link section 1"); + offset = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; + ret = gup_load_section_file( + fw_link, offset, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]load firmware link section 1 fail."); + goto exit_burn_fw_link; + } + + /* step3:burn link firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_link]step3:burn link firmware section 1"); + ret = gup_burn_fw_gwake_section( + client, fw_link, 0x9000, FW_SECTION_LENGTH, 0x38); + + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]burn link firmware section 1 fail."); + goto exit_burn_fw_link; + } + + /* step4:load link firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_link]step4:load link firmware section 2 file data"); + offset += FW_SECTION_LENGTH; + ret = gup_load_section_file( + fw_link, offset, FW_GLINK_LENGTH - FW_SECTION_LENGTH, SEEK_SET); + + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]load link firmware section 2 fail."); + goto exit_burn_fw_link; + } + + /* step5:burn link firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_link]step4:burn link firmware section 2"); + ret = gup_burn_fw_gwake_section(client, + fw_link, 0x9000, FW_GLINK_LENGTH - FW_SECTION_LENGTH, 0x39); + + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_link]burn link firmware section 2 fail."); + goto exit_burn_fw_link; + } + + update_msg.fw_burned_len += FW_GLINK_LENGTH; + dev_dbg(&client->dev, + "[burn_fw_link]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_link: + kfree(fw_link); + + return ret; +} + +static u8 gup_burn_fw_gwake_section(struct i2c_client *client, + u8 *fw_section, u16 start_addr, u32 len, u8 bank_cmd) +{ + s32 ret = 0; + u8 rd_buf[5]; + + /* step1:hold ss51 & dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x0C); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]hold ss51 & dsp fail."); + return FAIL; + } + + /* step2:set scramble */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_OPT_B0_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]set scramble fail."); + return FAIL; + } + + /* step3:hold ss51 & release dsp */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x04); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]hold ss51 & release dsp fail."); + return FAIL; + } + /* must delay */ + usleep_range(1000, 2000); + + /* step4:select bank */ + ret = gup_set_ic_msg( + client, _bRW_MISCTL__SRAM_BANK, (bank_cmd >> 4)&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_section]select bank %d fail.", + (bank_cmd >> 4)&0x0F); + return FAIL; + } + + /* step5:burn fw section */ + ret = gup_burn_proc(client, fw_section, start_addr, len); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_app_section]burn fw_section fail."); + return FAIL; + } + + /* step6:send burn cmd to move data to flash from sram */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, bank_cmd&0x0F); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]send burn cmd fail."); + return FAIL; + } + dev_dbg(&client->dev, + "[burn_fw_section]Wait for the burn is complete......"); + do { + ret = gup_get_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, rd_buf, 1); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_app_section]Get burn state fail"); + return FAIL; + } + usleep_range(10000, 11000); + /* dev_dbg(&client->dev, "[burn_fw_app_section]Get burn state:%d." + * rd_buf[GTP_ADDR_LENGTH]); + */ + } while (rd_buf[GTP_ADDR_LENGTH]); + + /* step7:recall fw section */ + ret = gup_recall_check(client, fw_section, start_addr, len); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_app_section]recall check %dk firmware fail.", + len/1024); + return FAIL; + } + + return SUCCESS; +} + +static u8 gup_burn_fw_gwake(struct i2c_client *client) +{ + u8 *fw_gwake = NULL; + u8 retry = 0; + s32 ret = 0; + u16 start_index = 4*FW_SECTION_LENGTH + + FW_DSP_LENGTH + FW_BOOT_LENGTH + + FW_BOOT_ISP_LENGTH + FW_GLINK_LENGTH;/* 32 + 4 + 2 + 4 = 42K */ + /* u16 start_index; */ + + if (start_index >= update_msg.fw_total_len) { + dev_dbg(&client->dev, "No need to upgrade the gwake code!"); + return SUCCESS; + } + /* start_index = update_msg.fw_burned_len - FW_DSP_ISP_LENGTH; */ + dev_info(&client->dev, + "[burn_fw_gwake]Begin burn gwake firmware---->>"); + + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_gwake]step1:alloc memory"); + while (retry++ < 5) { + fw_gwake = + kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_gwake == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_gwake]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, "[burn_fw_gwake]Alloc memory fail,exit."); + return FAIL; + } + + /* clear control flag */ + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]clear control flag fail."); + goto exit_burn_fw_gwake; + } + + /* step2:load app_code firmware section 1 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step2:load app_code firmware section 1 file data"); + ret = gup_load_section_file(fw_gwake, + start_index, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 1 fail."); + goto exit_burn_fw_gwake; + } + + /* step3:burn app_code firmware section 1 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step3:burn app_code firmware section 1"); + ret = gup_burn_fw_gwake_section(client, + fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3A); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 1 fail."); + goto exit_burn_fw_gwake; + } + + /* step5:load app_code firmware section 2 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step5:load app_code firmware section 2 file data"); + ret = gup_load_section_file( + fw_gwake, start_index+FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 2 fail."); + goto exit_burn_fw_gwake; + } + + /* step6:burn app_code firmware section 2 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step6:burn app_code firmware section 2"); + ret = gup_burn_fw_gwake_section(client, + fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3B); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 2 fail."); + goto exit_burn_fw_gwake; + } + + /* step7:load app_code firmware section 3 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step7:load app_code firmware section 3 file data"); + ret = gup_load_section_file( + fw_gwake, start_index + 2*FW_SECTION_LENGTH, + FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 3 fail."); + goto exit_burn_fw_gwake; + } + + /* step8:burn app_code firmware section 3 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step8:burn app_code firmware section 3"); + ret = gup_burn_fw_gwake_section( + client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3C); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 3 fail."); + goto exit_burn_fw_gwake; + } + + /* step9:load app_code firmware section 4 file data */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step9:load app_code firmware section 4 file data"); + ret = gup_load_section_file(fw_gwake, + start_index + 3*FW_SECTION_LENGTH, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]load app_code firmware section 4 fail."); + goto exit_burn_fw_gwake; + } + + /* step10:burn app_code firmware section 4 */ + dev_dbg(&client->dev, + "[burn_fw_gwake]step10:burn app_code firmware section 4"); + ret = gup_burn_fw_gwake_section( + client, fw_gwake, 0x9000, FW_SECTION_LENGTH, 0x3D); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_gwake]burn app_code firmware section 4 fail."); + goto exit_burn_fw_gwake; + } + + /* update_msg.fw_burned_len += FW_GWAKE_LENGTH; */ + dev_dbg(&client->dev, + "[burn_fw_gwake]Burned length:%d", update_msg.fw_burned_len); + ret = SUCCESS; + +exit_burn_fw_gwake: + kfree(fw_gwake); + + return ret; +} + +static u8 gup_burn_fw_finish(struct i2c_client *client) +{ + u8 *fw_ss51 = NULL; + u8 retry = 0; + s32 ret = 0; + + dev_info(&client->dev, + "[burn_fw_finish]burn first 8K of ss51 and finish update."); + /* step1:alloc memory */ + dev_dbg(&client->dev, "[burn_fw_finish]step1:alloc memory"); + while (retry++ < 5) { + fw_ss51 = kzalloc(FW_SECTION_LENGTH, GFP_KERNEL); + if (fw_ss51 == NULL) { + continue; + } else { + dev_dbg(&client->dev, + "[burn_fw_finish]Alloc %dk byte memory success.", + (FW_SECTION_LENGTH/1024)); + break; + } + } + if (retry >= 5) { + dev_err(&client->dev, + "[burn_fw_finish]Alloc memory fail,exit."); + return FAIL; + } + + dev_dbg(&client->dev, "[burn_fw_finish]step2: burn ss51 first 8K."); + ret = gup_load_section_file(fw_ss51, 0, FW_SECTION_LENGTH, SEEK_SET); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_finish]load ss51 firmware section 1 fail."); + goto exit_burn_fw_finish; + } + + dev_dbg(&client->dev, "[burn_fw_finish]step3:clear control flag"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x00); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]clear control flag fail."); + goto exit_burn_fw_finish; + } + + dev_dbg(&client->dev, + "[burn_fw_finish]step4:burn ss51 firmware section 1"); + ret = gup_burn_fw_section(client, fw_ss51, 0xC000, 0x01); + if (ret == FAIL) { + dev_err(&client->dev, + "[burn_fw_finish]burn ss51 firmware section 1 fail."); + goto exit_burn_fw_finish; + } + + /* step11:enable download DSP code */ + dev_dbg(&client->dev, + "[burn_fw_finish]step5:enable download DSP code "); + ret = gup_set_ic_msg(client, _rRW_MISCTL__BOOT_CTL_, 0x99); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]enable download DSP code fail."); + goto exit_burn_fw_finish; + } + + /* step12:release ss51 & hold dsp */ + dev_dbg(&client->dev, "[burn_fw_finish]step6:release ss51 & hold dsp"); + ret = gup_set_ic_msg(client, _rRW_MISCTL__SWRST_B0_, 0x08); + if (ret <= 0) { + dev_err(&client->dev, + "[burn_fw_finish]release ss51 & hold dsp fail."); + goto exit_burn_fw_finish; + } + + if (fw_ss51 != NULL) + kfree(fw_ss51); + return SUCCESS; + +exit_burn_fw_finish: + if (fw_ss51 != NULL) + kfree(fw_ss51); + + return FAIL; +} + +/* return 0 can update, else no update condition */ +static int gup_update_condition_check(struct goodix_ts_data *ts) +{ + if (test_bit(SLEEP_MODE, &ts->flags)) { + dev_info(&ts->client->dev, "Update abort, tp in sleep mode\n"); + return -EINVAL; + } + + return 0; +} +s32 gup_update_proc(void *dir) +{ + s32 ret = 0; + s32 update_ret = FAIL; + u8 retry = 0; + struct st_fw_head fw_head; + struct goodix_ts_data *ts = NULL; + + ts = i2c_get_clientdata(i2c_connect_client); + + dev_dbg(&ts->client->dev, "[update_proc]Begin update ......\n"); + + show_len = 1; + total_len = 100; + + ret = gup_update_condition_check(ts); + if (ret) { + dev_warn(&ts->client->dev, "Update start failed\n"); + return FAIL; + } + + if (test_and_set_bit(FW_UPDATE_RUNNING, &ts->flags)) { + dev_warn(&ts->client->dev, "FW update may already running\n"); + return FAIL; + } + + ret = gup_get_update_file(i2c_connect_client, &fw_head, (u8 *)dir); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "Failed get valied firmware data\n"); + clear_bit(FW_UPDATE_RUNNING, &ts->flags); + return FAIL; + } + + gtp_work_control_enable(ts, false); + gtp_esd_off(ts); + + ret = gup_get_ic_fw_msg(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, "[update_proc]get ic message fail."); + goto file_fail; + } + + if (ts->force_update || dir) { + dev_dbg(&ts->client->dev, "Enter force update."); + } else { + ret = gup_enter_update_judge(i2c_connect_client, &fw_head); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]Doesn't meet update condition\n"); + goto file_fail; + } + } + + ret = gup_enter_update_mode(ts->client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]enter update mode fail."); + goto update_fail; + } + + while (retry++ < 5) { + show_len = 10; + total_len = 100; + update_msg.fw_burned_len = 0; + ret = gup_burn_dsp_isp(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn dsp isp fail."); + continue; + } + + show_len = 20; + ret = gup_burn_fw_gwake(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn app_code firmware fail."); + continue; + } + + show_len = 30; + ret = gup_burn_fw_ss51(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn ss51 firmware fail."); + continue; + } + + show_len = 40; + ret = gup_burn_fw_dsp(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn dsp firmware fail."); + continue; + } + + show_len = 50; + ret = gup_burn_fw_boot(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn bootloader firmware fail."); + continue; + } + show_len = 60; + + ret = gup_burn_fw_boot_isp(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn boot_isp firmware fail."); + continue; + } + + show_len = 70; + ret = gup_burn_fw_link(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn link firmware fail."); + continue; + } + + show_len = 80; + ret = gup_burn_fw_finish(i2c_connect_client); + if (ret == FAIL) { + dev_err(&ts->client->dev, + "[update_proc]burn finish fail."); + continue; + } + show_len = 90; + dev_info(&ts->client->dev, "[update_proc]UPDATE SUCCESS."); + retry = 0; + break; + } + + if (retry >= 5) { + dev_err(&ts->client->dev, + "[update_proc]retry timeout,UPDATE FAIL."); + update_ret = FAIL; + } else { + update_ret = SUCCESS; + } + +update_fail: + dev_dbg(&ts->client->dev, "[update_proc]leave update mode."); + gup_leave_update_mode(i2c_connect_client); + + msleep(GTP_100_DLY_MS); + + if (update_ret == SUCCESS) { + dev_info(&ts->client->dev, + "firmware error auto update, resent config!\n"); + gup_init_panel(ts); + } + gtp_get_fw_info(ts->client, &ts->fw_info); + +file_fail: + + update_msg.fw_data = NULL; + update_msg.fw_total_len = 0; + release_firmware(update_msg.fw); + + clear_bit(FW_UPDATE_RUNNING, &ts->flags); + gtp_work_control_enable(ts, true); + gtp_esd_on(ts); + total_len = 100; + ts->force_update = false; + if (update_ret == SUCCESS) { + show_len = 100; + clear_bit(FW_ERROR, &ts->flags); + return SUCCESS; + } + + show_len = 200; + return FAIL; +} + +u8 gup_init_update_proc(struct goodix_ts_data *ts) +{ + struct task_struct *thread = NULL; + + dev_info(&ts->client->dev, "Ready to run update thread."); + + thread = kthread_run(gup_update_proc, + (void *)NULL, "guitar_update"); + + if (IS_ERR(thread)) { + dev_err(&ts->client->dev, + "Failed to create update thread.\n"); + return -EPERM; + } + + return 0; +} diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig index ebf3aa478af51d0991a760a0d871988846c83e49..3dc5a026c851cbd802cf573d46f41dc309ff00f7 100644 --- a/drivers/input/touchscreen/hxchipset/Kconfig +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -3,19 +3,44 @@ # config TOUCHSCREEN_HIMAX_I2C - tristate "HIMAX chipset i2c touchscreen" - depends on TOUCHSCREEN_HIMAX_CHIPSET - help + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + Say Y here to enable support for HIMAX CHIPSET over I2C based touchscreens. + If unsure, say N. + + To compile this driver as a module, This enables support for HIMAX CHIPSET over I2C based touchscreens. config TOUCHSCREEN_HIMAX_DEBUG - tristate "HIMAX debug function" - depends on TOUCHSCREEN_HIMAX_I2C - help + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX debug function. + + If unsure, say N. + + To compile this driver as a module, This enables support for HIMAX debug function. +config TOUCHSCREEN_HIMAX_ITO_TEST + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. + config HMX_DB tristate "HIMAX driver test over Dragon Board" depends on TOUCHSCREEN_HIMAX_I2C help - This enables support for HIMAX driver test over Dragon Board. + Say Y here to enable support for HIMAX driver test over Dragon Board. + + If unsure, say N. + + To compile this driver as a module, + this enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile index 509d4913bc39f4577ba64fa4b8e8fefd5bd1c53a..522907a48956cdbf8ee19720d237dab90d97b387 100644 --- a/drivers/input/touchscreen/hxchipset/Makefile +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -1,3 +1,4 @@ # Makefile for the Himax touchscreen drivers. obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o +obj-$(CONFIG_TOUCHSCREEN_HIMAX_ITO_TEST) += himax_ito_test.o \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c index 417b0c08e3615ee256fba5f4c9f9d1da8bd78f91..d4bc5beb0203e5eece80c10e11d29cfb966cdf16 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.c +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -1,4 +1,4 @@ -/* Himax Android Driver Sample Code for Himax chipset + /* Himax Android Driver Sample Code for Himax chipset * * Copyright (C) 2015 Himax Corporation. * @@ -21,107 +21,32 @@ #define FRAME_COUNT 5 #if defined(HX_AUTO_UPDATE_FW) - static unsigned char i_CTPM_FW[]= - { - #include "HX83100_Amber_0901_030B.i" - }; + char *i_CTPM_firmware_name = "HX83100_Amber_0B01_030E.bin"; + const struct firmware *i_CTPM_FW = NULL; #endif -#ifdef HX_ESD_WORKAROUND - extern void HX_report_ESD_event(void); - unsigned char ESD_00_counter = 0; - unsigned char ESD_00_Flag = 0; -#endif - -//static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array +/*static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; +// for Virtual key array */ struct himax_ts_data *private_ts; -struct himax_ic_data* ic_data; - -static int HX_TOUCH_INFO_POINT_CNT; - -#ifdef HX_AUTO_UPDATE_FW -extern unsigned long FW_VER_MAJ_FLASH_ADDR; -extern unsigned long FW_VER_MIN_FLASH_ADDR; -extern unsigned long CFG_VER_MAJ_FLASH_ADDR; -extern unsigned long CFG_VER_MIN_FLASH_ADDR; -#endif -extern unsigned long FW_VER_MAJ_FLASH_LENG; -extern unsigned long FW_VER_MIN_FLASH_LENG; -extern unsigned long CFG_VER_MAJ_FLASH_LENG; -extern unsigned long CFG_VER_MIN_FLASH_LENG; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; - -#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -//PROC-START -#ifdef HX_TP_PROC_FLASH_DUMP -extern void himax_ts_flash_func(void); -extern void setFlashBuffer(void); -extern bool getFlashDumpGoing(void); -extern uint8_t getSysOperation(void); -extern void setSysOperation(uint8_t operation); -#endif - -#ifdef HX_TP_PROC_HITOUCH -extern bool hitouch_is_connect; -#endif - -#ifdef HX_TP_PROC_DIAG - extern int touch_monitor_stop_flag; - extern int touch_monitor_stop_limit; - extern void himax_ts_diag_func(void); - extern int16_t *getMutualBuffer(void); - extern int16_t *getMutualNewBuffer(void); - extern int16_t *getMutualOldBuffer(void); - extern int16_t *getSelfBuffer(void); - extern uint8_t getXChannel(void); - extern uint8_t getYChannel(void); - extern uint8_t getDiagCommand(void); - extern void setXChannel(uint8_t x); - extern void setYChannel(uint8_t y); - extern void setMutualBuffer(void); - extern void setMutualNewBuffer(void); - extern void setMutualOldBuffer(void); - extern uint8_t coordinate_dump_enable; - extern struct file *coordinate_fn; - extern uint8_t diag_coor[128]; -#ifdef HX_TP_PROC_2T2R - extern int16_t *getMutualBuffer_2(void); - extern uint8_t getXChannel_2(void); - extern uint8_t getYChannel_2(void); - extern void setXChannel_2(uint8_t x); - extern void setYChannel_2(uint8_t y); - extern void setMutualBuffer_2(void); -#endif -#endif -//PROC-END -#endif - -extern int himax_parse_dt(struct himax_ts_data *ts, - struct himax_i2c_platform_data *pdata); -extern int himax_ts_pinctrl_init(struct himax_ts_data *ts); - -static uint8_t vk_press; -static uint8_t AA_press; -static uint8_t EN_NoiseFilter; -static uint8_t Last_EN_NoiseFilter; -static int hx_point_num; // for himax_ts_work_func use -static int p_point_num = 0xFFFF; -static int tpd_key; -static int tpd_key_old; -static int probe_fail_flag; -static bool config_load; +struct himax_ic_data *ic_data; + +static int HX_TOUCH_INFO_POINT_CNT; + +static uint8_t vk_press = 0x00; +static uint8_t AA_press = 0x00; +static uint8_t EN_NoiseFilter = 0x00; +static int hx_point_num; /*for himax_ts_work_func use*/ +static int p_point_num = 0xFFFF; +static int tpd_key = 0x00; +static int tpd_key_old = 0x00; +static int probe_fail_flag; +static bool config_load; static struct himax_config *config_selected; -//static int iref_number = 11; -//static bool iref_found = false; +/*static int iref_number = 11;*/ +/*static bool iref_found = false;*/ -#ifdef HX_USB_DETECT2 -extern bool USB_Flag; -#endif #if defined(CONFIG_FB) int fb_notifier_callback(struct notifier_block *self, @@ -134,6 +59,7 @@ static void himax_ts_late_resume(struct early_suspend *h); int himax_input_register(struct himax_ts_data *ts) { int ret; + ts->input_dev = input_allocate_device(); if (ts->input_dev == NULL) { ret = -ENOMEM; @@ -175,25 +101,36 @@ int himax_input_register(struct himax_ts_data *ts) set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); if (ts->protocol_type == PROTOCOL_TYPE_A) { - //ts->input_dev->mtsize = ts->nFinger_support; + /*ts->input_dev->mtsize = ts->nFinger_support;*/ input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 3, 0, 0); } else {/* PROTOCOL_TYPE_B */ set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); - input_mt_init_slots(ts->input_dev, ts->nFinger_support,0); + input_mt_init_slots(ts->input_dev, ts->nFinger_support, 0); } I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", - ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); - - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); - input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); - -// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); -// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); + ts->pdata->abs_x_min, ts->pdata->abs_x_max, + ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, + ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, + ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, + ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, + ts->pdata->abs_width_min, ts->pdata->abs_width_max, + ts->pdata->abs_pressure_fuzz, 0); + +/*input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, +((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0);*/ +/*input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, +(BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0);*/ return input_register_device(ts->input_dev); } @@ -201,87 +138,103 @@ int himax_input_register(struct himax_ts_data *ts) static void calcDataSize(uint8_t finger_num) { struct himax_ts_data *ts_data = private_ts; + ts_data->coord_data_size = 4 * finger_num; - ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; - ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; - ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + - (((uint32_t)ts_data->x_channel * ts_data->y_channel + - ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; - I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); + ts_data->area_data_size = ((finger_num / 4) + + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - + ts_data->coord_data_size - + ts_data->area_data_size - 4 - 4 - 1; + + ts_data->raw_data_nframes = + ((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) / + ts_data->raw_data_frame_size + (((uint32_t)ts_data->x_channel * + ts_data->y_channel + ts_data->x_channel + ts_data->y_channel) % + ts_data->raw_data_frame_size) ? 1 : 0; + + I("%s: coord_data_size: %d, area_data_size:%d", + __func__, ts_data->coord_data_size, ts_data->area_data_size); + I("raw_data_frame_size:%d, raw_data_nframes:%d", + ts_data->raw_data_frame_size, ts_data->raw_data_nframes); } static void calculate_point_number(void) { - HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ; + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4; - if ( (ic_data->HX_MAX_PT % 4) == 0) - HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ; + if ((ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4; else - HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ; + HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) + 1) * 4; } -#if 0 +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH static int himax_read_Sensor_ID(struct i2c_client *client) -{ - uint8_t val_high[1], val_low[1], ID0=0, ID1=0; +{ + uint8_t val_high[1], val_low[1], ID0 = 0, ID1 = 0; char data[3]; const int normalRetry = 10; int sensor_id; - - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - //read id pin high + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); + + /*read id pin high*/ i2c_himax_read(client, 0x57, val_high, 1, normalRetry); - data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x01;/*ID pin PULL Low*/ + i2c_himax_master_write(client, &data[0], 3, normalRetry); + usleep(1000); - //read id pin low + /*read id pin low*/ i2c_himax_read(client, 0x57, val_low, 1, normalRetry); - if((val_high[0] & 0x01) ==0) - ID0=0x02;/*GND*/ - else if((val_low[0] & 0x01) ==0) - ID0=0x01;/*Floating*/ + if ((val_high[0] & 0x01) == 0) + ID0 = 0x02;/*GND*/ + else if ((val_low[0] & 0x01) == 0) + ID0 = 0x01;/*Floating*/ else - ID0=0x04;/*VCC*/ - - if((val_high[0] & 0x02) ==0) - ID1=0x02;/*GND*/ - else if((val_low[0] & 0x02) ==0) - ID1=0x01;/*Floating*/ - else - ID1=0x04;/*VCC*/ - if((ID0==0x04)&&(ID1!=0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); - - } - else if((ID0!=0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); + ID0 = 0x04;/*VCC*/ - } - else if((ID0==0x04)&&(ID1==0x04)) - { - data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/ - i2c_himax_master_write(client, &data[0],3,normalRetry); - usleep_range(1000, 2000); + if ((val_high[0] & 0x02) == 0) + ID1 = 0x02;/*GND*/ + else if ((val_low[0] & 0x02) == 0) + ID1 = 0x01;/*Floating*/ + else + ID1 = 0x04;/*VCC*/ + if ((ID0 == 0x04) && (ID1 != 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x01;/*ID pin PULL High,Low*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 != 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x01; + data[2] = 0x02;/*ID pin PULL Low,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); + + } else if ((ID0 == 0x04) && (ID1 == 0x04)) { + data[0] = 0x56; data[1] = 0x02; + data[2] = 0x02;/*ID pin PULL High,High*/ + i2c_himax_master_write(client, + &data[0], 3, normalRetry); + usleep(1000); - } - sensor_id=(ID1<<4)|ID0; + } + sensor_id = (ID1<<4)|ID0; data[0] = 0xE4; data[1] = sensor_id; - i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/ - usleep_range(1000, 2000); + i2c_himax_master_write(client, + &data[0], 2, normalRetry);/*Write to MCU*/ + usleep(1000); return sensor_id; @@ -290,125 +243,173 @@ static int himax_read_Sensor_ID(struct i2c_client *client) static void himax_power_on_initCMD(struct i2c_client *client) { I("%s:\n", __func__); - himax_touch_information(client); - - //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM + /*himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM */ } #ifdef HX_AUTO_UPDATE_FW static int i_update_FW(void) { int upgrade_times = 0; - unsigned char* ImageBuffer = i_CTPM_FW; - int fullFileLength = sizeof(i_CTPM_FW); + int fullFileLength = 0; int i_FW_VER = 0, i_CFG_VER = 0; - uint8_t ret = -1, result = 0; -// uint8_t tmp_addr[4]; -// uint8_t tmp_data[4]; + int ret = -1, result = 0; + /*uint8_t tmp_addr[4];*/ + /*uint8_t tmp_data[4];*/ int CRC_from_FW = 0; int CRC_Check_result = 0; - i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; - i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; + ret = himax_load_CRC_bin_file(private_ts->client); + if (ret < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, ret); + ret = -1; + return ret; + } + I("file name = %s\n", i_CTPM_firmware_name); + ret = request_firmware(&i_CTPM_FW, + i_CTPM_firmware_name, private_ts->dev); + if (ret < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, ret); + ret = -2; + return ret; + } + + if (i_CTPM_FW == NULL) { + I("%s: i_CTPM_FW = NULL\n", __func__); + ret = -3; + return ret; + } + fullFileLength = i_CTPM_FW->size; - I("%s: i_fullFileLength = %d\n", __func__,fullFileLength); + i_FW_VER = i_CTPM_FW->data[FW_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = i_CTPM_FW->data[CFG_VER_MAJ_FLASH_ADDR]<<8 + | i_CTPM_FW->data[CFG_VER_MIN_FLASH_ADDR]; + + I("%s: i_fullFileLength = %d\n", __func__, fullFileLength); himax_sense_off(private_ts->client); msleep(500); - CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k); - CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k); - I("%s: Check sum result = %d\n", __func__,CRC_Check_result); - //I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER); - //I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER); - - if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER )) - { - himax_int_enable(private_ts->client->irq,0); + CRC_from_FW = himax_check_CRC(private_ts->client, fw_image_64k); + CRC_Check_result = + Calculate_CRC_with_AP((unsigned char *)i_CTPM_FW->data, + CRC_from_FW, fw_image_64k); + I("%s: Check sum result = %d\n", __func__, CRC_Check_result); + /*I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", + __func__, ic_data->vendor_fw_ver, i_FW_VER);*/ + /*I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", + __func__, ic_data->vendor_config_ver, i_CFG_VER);*/ + + if ((CRC_Check_result == 0) || + (ic_data->vendor_fw_ver < i_FW_VER) || + (ic_data->vendor_config_ver < i_CFG_VER)) { + himax_int_enable(private_ts->client->irq, 0); update_retry: - if(fullFileLength == FW_SIZE_60k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_64k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_124k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false); - }else if (fullFileLength == FW_SIZE_128k){ - ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false); - } - if(ret == 0){ - upgrade_times++; - E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times); - if(upgrade_times < 3) - goto update_retry; - else - { - himax_sense_on(private_ts->client, 0x01); - msleep(120); -#ifdef HX_ESD_WORKAROUND - HX_ESD_RESET_ACTIVATE = 1; -#endif - result = -1;//upgrade fail - } - } - else if(ret == 1){ -/* - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 2. Write driver initial code condition - // write value from AHB I2C : 0x8001_C603 = 0x000000FF - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); - - // 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); -*/ + if (fullFileLength == FW_SIZE_60k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_64k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_124k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } else if (fullFileLength == FW_SIZE_128k) { + ret = fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, + (unsigned char *)i_CTPM_FW->data, + fullFileLength, false); + } + if (ret == 0) { + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", + __func__, upgrade_times); + if (upgrade_times < 3) + goto update_retry; + else { himax_sense_on(private_ts->client, 0x01); msleep(120); #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; #endif - - ic_data->vendor_fw_ver = i_FW_VER; - ic_data->vendor_config_ver = i_CFG_VER; - result = 1;//upgrade success - I("%s: TP upgrade OK\n", __func__); + result = -1;/*upgrade fail*/ } - - himax_int_enable(private_ts->client->irq,1); - return result; - } - else - { + } else if (ret == 1) { + /* + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 2. Write driver initial code condition + //write value from AHB I2C:0x8001_C603 = 0x000000FF + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xFF; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + + // 1. Set DDREG_Req = 0(0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(private_ts->client, + tmp_addr, 1, tmp_data); + */ himax_sense_on(private_ts->client, 0x01); - return 0;//NO upgrade + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + + ic_data->vendor_fw_ver = i_FW_VER; + ic_data->vendor_config_ver = i_CFG_VER; + result = 1;/*upgrade success*/ + I("%s: TP upgrade OK\n", __func__); } + + himax_int_enable(private_ts->client->irq, 1); + return result; + + } else { + himax_sense_on(private_ts->client, 0x01); + return 0;/*NO upgrade*/ + } } -#endif +#endif #ifdef HX_RST_PIN_FUNC -void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) +void himax_HW_reset(uint8_t loadconfig, uint8_t int_off) { struct himax_ts_data *ts = private_ts; int ret = 0; return; if (ts->rst_gpio) { - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,0); - else { - hrtimer_cancel(&ts->timer); - ret = cancel_work_sync(&ts->work); - } + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 0); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); } + } I("%s: Now reset the Touch chip.\n", __func__); @@ -417,51 +418,51 @@ void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) himax_rst_gpio_set(ts->rst_gpio, 1); msleep(20); - if(loadconfig) - himax_loadSensorConfig(private_ts->client,private_ts->pdata); + if (loadconfig) + himax_loadSensorConfig(private_ts->client, + private_ts->pdata); - if(int_off) - { - if (ts->use_irq) - himax_int_enable(private_ts->client->irq,1); - else - hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); - } + if (int_off) { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq, 1); + else + hrtimer_start(&ts->timer, + ktime_set(1, 0), HRTIMER_MODE_REL); + } } } #endif -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { + int err = -1; if (!client) { E("%s: Necessary parameters client are null!\n", __func__); - return -EINVAL; + return err; } - - if(config_load == false) - { - config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); - if (config_selected == NULL) { - E("%s: alloc config_selected fail!\n", __func__); - return -ENOMEM; - } + if (config_load == false) { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return err; } + } + himax_power_on_initCMD(client); - himax_power_on_initCMD(client); - - himax_int_enable(client->irq,0); - himax_read_FW_ver(client); + himax_int_enable(client->irq, 0); + himax_read_FW_ver(client); #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif - himax_int_enable(client->irq,1); - I("FW_VER : %X \n",ic_data->vendor_fw_ver); + himax_int_enable(client->irq, 1); + I("FW_VER : %X\n", ic_data->vendor_fw_ver); - ic_data->vendor_sensor_id=0x2602; - I("sensor_id=%x.\n",ic_data->vendor_sensor_id); + ic_data->vendor_sensor_id = 0x2602; + I("sensor_id=%x.\n", ic_data->vendor_sensor_id); - himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM + himax_sense_on(private_ts->client, 0x01);/*1=Flash, 0=SRAM*/ msleep(120); #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; @@ -474,47 +475,49 @@ int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_ #ifdef HX_ESD_WORKAROUND void ESD_HW_REST(void) { - I("START_Himax TP: ESD - Reset\n"); - + I("START_Himax TP: ESD - Reset\n"); + HX_report_ESD_event(); ESD_00_counter = 0; ESD_00_Flag = 0; - /*************************************/ - if (private_ts->protocol_type == PROTOCOL_TYPE_A) + /*************************************/ + if (private_ts->protocol_type == PROTOCOL_TYPE_A) input_mt_sync(private_ts->input_dev); - input_report_key(private_ts->input_dev, BTN_TOUCH, 0); - input_sync(private_ts->input_dev); - /*************************************/ + input_report_key(private_ts->input_dev, BTN_TOUCH, 0); + input_sync(private_ts->input_dev); + /*************************************/ I("END_Himax TP: ESD - Reset\n"); } #endif #ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable) +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable) { uint8_t tmp_data[4]; - if(HSEN_enable) - { + if (HSEN_enable) { I(" %s in", __func__); - HSEN_bit_retry: - himax_set_HSEN_enable(client,HSEN_enable); +HSEN_bit_retry: + himax_set_HSEN_enable(client, HSEN_enable); msleep(20); - himax_get_HSEN_enable(client,tmp_data); - I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry HSEN bit write data[0]=%x \n",__func__,tmp_data[0]); - goto HSEN_bit_retry; - } + himax_get_HSEN_enable(client, tmp_data); + I("%s: Read HSEN bit data[0]=%x data[1]=%x", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry HSEN bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto HSEN_bit_retry; + } } } static void himax_HSEN_func(struct work_struct *work) { - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - hsen_work.work); + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, hsen_work.work); himax_set_HSEN_func(ts->client, ts->HSEN_enable); } @@ -525,9 +528,10 @@ static void himax_HSEN_func(struct work_struct *work) #ifdef HX_GESTURE_TRACK static void gest_pt_log_coordinate(int rx, int tx) { - //driver report x y with range 0 - 255 , we scale it up to x/y pixel - gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255; - gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255; + /*driver report x y with range 0 - 255*/ + /* And we scale it up to x/y coordinates*/ + gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255; + gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255; } #endif static int himax_parse_wake_event(struct himax_ts_data *ts) @@ -535,145 +539,143 @@ static int himax_parse_wake_event(struct himax_ts_data *ts) uint8_t buf[64]; unsigned char check_sum_cal = 0; #ifdef HX_GESTURE_TRACK - int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; + int tmp_max_x = 0x00, tmp_min_x = 0xFFFF, + tmp_max_y = 0x00, tmp_min_y = 0xFFFF; int gest_len; #endif - int i=0, check_FC = 0, gesture_flag = 0; + int i = 0, check_FC = 0, gesture_flag = 0; himax_burst_enable(ts->client, 0); - himax_read_event_stack(ts->client,buf,56); + himax_read_event_stack(ts->client, buf, 56); - for(i=0;igest_pt_x[i]) - tmp_min_x=gest_pt_x[i]; - if(tmp_max_ygest_pt_y[i]) - tmp_min_y=gest_pt_y[i]; - } - I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); - gest_start_x=gest_pt_x[0]; - gn_gesture_coor[0] = gest_start_x; - gest_start_y=gest_pt_y[0]; - gn_gesture_coor[1] = gest_start_y; - gest_end_x=gest_pt_x[gest_pt_cnt-1]; - gn_gesture_coor[2] = gest_end_x; - gest_end_y=gest_pt_y[gest_pt_cnt-1]; - gn_gesture_coor[3] = gest_end_y; - gest_width = tmp_max_x - tmp_min_x; - gn_gesture_coor[4] = gest_width; - gest_height = tmp_max_y - tmp_min_y; - gn_gesture_coor[5] = gest_height; - gest_mid_x = (tmp_max_x + tmp_min_x)/2; - gn_gesture_coor[6] = gest_mid_x; - gest_mid_y = (tmp_max_y + tmp_min_y)/2; - gn_gesture_coor[7] = gest_mid_y; - gn_gesture_coor[8] = gest_mid_x;//gest_up_x - gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y - gn_gesture_coor[10] = gest_mid_x;//gest_down_x - gn_gesture_coor[11] = gest_mid_y+gest_height/2; //gest_down_y - gn_gesture_coor[12] = gest_mid_x-gest_width/2; //gest_left_x - gn_gesture_coor[13] = gest_mid_y; //gest_left_y - gn_gesture_coor[14] = gest_mid_x+gest_width/2; //gest_right_x - gn_gesture_coor[15] = gest_mid_y; //gest_right_y - + if (gest_pt_cnt) { + for (i = 0 ; i < gest_pt_cnt ; i++) { + if (tmp_max_x < gest_pt_x[i]) + tmp_max_x = gest_pt_x[i]; + if (tmp_min_x > gest_pt_x[i]) + tmp_min_x = gest_pt_x[i]; + if (tmp_max_y < gest_pt_y[i]) + tmp_max_y = gest_pt_y[i]; + if (tmp_min_y > gest_pt_y[i]) + tmp_min_y = gest_pt_y[i]; } + I("gest_point x_min= %d, x_max= %d\n", + tmp_min_x, tmp_max_x); + I("y_min= %d, y_max= %d\n", + tmp_min_y, tmp_max_y); + gest_start_x = gest_pt_x[0]; + gn_gesture_coor[0] = gest_start_x; + gest_start_y = gest_pt_y[0]; + gn_gesture_coor[1] = gest_start_y; + gest_end_x = gest_pt_x[gest_pt_cnt - 1]; + gn_gesture_coor[2] = gest_end_x; + gest_end_y = gest_pt_y[gest_pt_cnt - 1]; + gn_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + gn_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + gn_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x) / 2; + gn_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y) / 2; + gn_gesture_coor[7] = gest_mid_y; + /*gest_up_x*/ + gn_gesture_coor[8] = gest_mid_x; + /*gest_up_y*/ + gn_gesture_coor[9] = gest_mid_y - gest_height / 2; + /*gest_down_x*/ + gn_gesture_coor[10] = gest_mid_x; + /*gest_down_y*/ + gn_gesture_coor[11] = gest_mid_y + gest_height / 2; + /*gest_left_x*/ + gn_gesture_coor[12] = gest_mid_x - gest_width / 2; + /*gest_left_y*/ + gn_gesture_coor[13] = gest_mid_y; + /*gest_right_x*/ + gn_gesture_coor[14] = gest_mid_x + gest_width / 2; + /*gest_right_y*/ + gn_gesture_coor[15] = gest_mid_y; + + } } #endif - if(gesture_flag != 0x80) - { - if(!ts->gesture_cust_en[gesture_flag]) - { - I("%s NOT report customer key \n ",__func__); - return 0;//NOT report customer key - } - } - else - { - if(!ts->gesture_cust_en[0]) - { - I("%s NOT report report double click \n",__func__); - return 0;//NOT report power key - } + if (gesture_flag != 0x80) { + if (!ts->gesture_cust_en[gesture_flag]) { + I("%s NOT report customer key\n ", __func__); + return 0;/*NOT report customer key*/ + } + } else { + if (!ts->gesture_cust_en[0]) { + I("%s NOT report report double click\n", __func__); + return 0;/*NOT report power key*/ + } } - if(gesture_flag == 0x80) + if (gesture_flag == 0x80) return EV_GESTURE_PWR; else return gesture_flag; @@ -685,225 +687,242 @@ void himax_wake_check_func(void) ret_event = himax_parse_wake_event(private_ts); switch (ret_event) { - case EV_GESTURE_PWR: - KEY_EVENT = KEY_POWER; + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; break; - case EV_GESTURE_01: - KEY_EVENT = KEY_CUST_01; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; break; - case EV_GESTURE_02: - KEY_EVENT = KEY_CUST_02; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; break; - case EV_GESTURE_03: - KEY_EVENT = KEY_CUST_03; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; break; - case EV_GESTURE_04: - KEY_EVENT = KEY_CUST_04; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; break; - case EV_GESTURE_05: - KEY_EVENT = KEY_CUST_05; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; break; - case EV_GESTURE_06: - KEY_EVENT = KEY_CUST_06; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; break; - case EV_GESTURE_07: - KEY_EVENT = KEY_CUST_07; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; break; - case EV_GESTURE_08: - KEY_EVENT = KEY_CUST_08; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; break; - case EV_GESTURE_09: - KEY_EVENT = KEY_CUST_09; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; break; - case EV_GESTURE_10: - KEY_EVENT = KEY_CUST_10; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; break; - case EV_GESTURE_11: - KEY_EVENT = KEY_CUST_11; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; break; - case EV_GESTURE_12: - KEY_EVENT = KEY_CUST_12; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; break; - case EV_GESTURE_13: - KEY_EVENT = KEY_CUST_13; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; break; - case EV_GESTURE_14: - KEY_EVENT = KEY_CUST_14; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; break; - case EV_GESTURE_15: - KEY_EVENT = KEY_CUST_15; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; break; } - if(ret_event) - { - I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 1); - input_sync(private_ts->input_dev); - //msleep(100); - I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT); - input_report_key(private_ts->input_dev, KEY_EVENT, 0); - input_sync(private_ts->input_dev); - FAKE_POWER_KEY_SEND=true; + if (ret_event) { + I(" %s SMART WAKEUP KEY event %x press\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + /*msleep(100);*/ + I(" %s SMART WAKEUP KEY event %x release\n", + __func__, KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND = true; #ifdef HX_GESTURE_TRACK - I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, - gest_end_x,gest_end_y); - I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, - gest_mid_x,gest_mid_y); - I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9], - gn_gesture_coor[10],gn_gesture_coor[11]); - I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13], - gn_gesture_coor[14],gn_gesture_coor[15]); + I("gest_start_x= %d, gest_start_y= %d\n", + gest_start_x, gest_start_y); + I("gest_end_x= %d, gest_end_y= %d\n", + gest_end_x, gest_end_y); + I("gest_width= %d, gest_height= %d\n", + gest_width, gest_height); + I("gest_mid_x= %d, gest_mid_y= %d\n", + gest_mid_x, gest_mid_y); + I("gest_up_x= %d, gest_up_y= %d\n", + gn_gesture_coor[8], gn_gesture_coor[9]); + I("gest_down_x= %d, gest_down_y= %d\n", + gn_gesture_coor[10], gn_gesture_coor[11]); + I("gest_left_x= %d, gest_left_y= %d\n", + gn_gesture_coor[12], gn_gesture_coor[13]); + I("gest_right_x= %d, gest_right_y= %d\n", + gn_gesture_coor[14], gn_gesture_coor[15]); #endif - } + } } #endif -static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) +static void himax_ts_button_func(int tp_key_index, struct himax_ts_data *ts) { uint16_t x_position = 0, y_position = 0; -if ( tp_key_index != 0x00) - { - I("virtual key index =%x\n",tp_key_index); - if ( tp_key_index == 0x01) { + + if (tp_key_index != 0x00) { + I("virtual key index =%x\n", tp_key_index); + if (tp_key_index == 0x01) { vk_press = 1; I("back key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[0].index) { - x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; - y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } + if (ts->pdata->virtual_key) { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + + ts->button[0].y_range_max) / 2; } - else - input_report_key(ts->input_dev, KEY_BACK, 1); - } - else if ( tp_key_index == 0x02) { + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_BACK, 1); + } else if (tp_key_index == 0x02) { vk_press = 1; I("home key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[1].index) { - x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; - y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } + if (ts->pdata->virtual_key) { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + + ts->button[1].y_range_max) / 2; } - else - input_report_key(ts->input_dev, KEY_HOME, 1); - } - else if ( tp_key_index == 0x04) { + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type + == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_HOME, 1); + } else if (tp_key_index == 0x04) { vk_press = 1; I("APP_switch key pressed\n"); - if (ts->pdata->virtual_key) - { - if (ts->button[2].index) { - x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; - y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; - } - if (ts->protocol_type == PROTOCOL_TYPE_A) { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - input_mt_sync(ts->input_dev); - } else if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, - 1); - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, - 100); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, - 100); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, - x_position); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, - y_position); - } + if (ts->pdata->virtual_key) { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + + ts->button[2].y_range_max) / 2; } - else - input_report_key(ts->input_dev, KEY_F10, 1); + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == + PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 1); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, 100); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, 100); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x_position); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y_position); + } + } else + input_report_key(ts->input_dev, KEY_F10, 1); } input_sync(ts->input_dev); - } -else/*tp_key_index =0x00*/ - { + } else {/*tp_key_index =0x00*/ I("virtual key released\n"); vk_press = 0; if (ts->protocol_type == PROTOCOL_TYPE_A) { input_mt_sync(ts->input_dev); - } - else if (ts->protocol_type == PROTOCOL_TYPE_B) { + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { input_mt_slot(ts->input_dev, 0); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + input_mt_report_slot_state(ts->input_dev, + MT_TOOL_FINGER, 0); } input_report_key(ts->input_dev, KEY_BACK, 0); input_report_key(ts->input_dev, KEY_HOME, 0); input_report_key(ts->input_dev, KEY_F10, 0); - input_sync(ts->input_dev); + input_sync(ts->input_dev); } } @@ -915,8 +934,8 @@ void himax_ts_work(struct himax_ts_data *ts) uint8_t finger_on = 0; int32_t loop_i; uint16_t check_sum_cal = 0; - int raw_cnt_max ; - int raw_cnt_rmd ; + int raw_cnt_max; + int raw_cnt_rmd; int hx_touch_info_size; uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; @@ -924,121 +943,111 @@ void himax_ts_work(struct himax_ts_data *ts) int16_t *mutual_data; int16_t *self_data; uint8_t diag_cmd; - int i; - int mul_num; - int self_num; + int i; + int mul_num; + int self_num; int RawDataLen = 0; - //coordinate dump start - char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2]; - //coordinate dump end + /*coordinate dump start*/ + char coordinate_char[15 + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 2]; + struct timeval t; + struct tm broken; + /*coordinate dump end*/ #endif memset(buf, 0x00, sizeof(buf)); memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); - raw_cnt_max = ic_data->HX_MAX_PT/4; - raw_cnt_rmd = ic_data->HX_MAX_PT%4; - + raw_cnt_max = ic_data->HX_MAX_PT / 4; + raw_cnt_rmd = ic_data->HX_MAX_PT % 4; #if defined(HX_USB_DETECT2) himax_cable_detect_func(); #endif - if (raw_cnt_rmd != 0x00) //more than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4; - } - else //less than 4 fingers - { - RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); - hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4; + if (raw_cnt_rmd != 0x00) { /*more than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 2) * 4; + } else { /*less than 4 fingers*/ + RawDataLen = cal_data_len(raw_cnt_rmd, + ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT + raw_cnt_max + 1) * 4; } #ifdef HX_TP_PROC_DIAG diag_cmd = getDiagCommand(); - if( diag_cmd ){ + if (diag_cmd) { ret = read_event_stack(ts->client, buf, 128); - } - else{ - if(touch_monitor_stop_flag != 0){ + } else { + if (touch_monitor_stop_flag != 0) { ret = read_event_stack(ts->client, buf, 128); - touch_monitor_stop_flag-- ; - } - else{ - ret = read_event_stack(ts->client, buf, hx_touch_info_size); + touch_monitor_stop_flag--; + } else { + ret = read_event_stack(ts->client, + buf, hx_touch_info_size); } } if (!ret) #else - if(!read_event_stack(ts->client, buf, hx_touch_info_size)) -#endif - { - E("%s: can't read data from chip!\n", __func__); - goto err_workqueue_out; - } + if (!read_event_stack(ts->client, buf, hx_touch_info_size)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } post_read_event_stack(ts->client); #ifdef HX_ESD_WORKAROUND - for(i = 0; i < hx_touch_info_size; i++) - { - if(buf[i] == 0xED)/*case 1 ESD recovery flow*/ - { + for (i = 0; i < hx_touch_info_size; i++) { + if (buf[i] == 0xED) { /*case 1 ESD recovery flow*/ check_sum_cal = 1; - }else if(buf[i] == 0x00) - { + } else if (buf[i] == 0x00) { ESD_00_Flag = 1; - } - else - { + } else { check_sum_cal = 0; ESD_00_counter = 0; - ESD_00_Flag = 0; + ESD_00_Flag = 0; i = hx_touch_info_size; break; - } - } - if (ESD_00_Flag == 1){ - ESD_00_counter ++; + } } - if (ESD_00_counter > 1){ + if (ESD_00_Flag == 1) + ESD_00_counter++; + if (ESD_00_counter > 1) check_sum_cal = 2; + if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + return; } - - if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) - { - I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); - ESD_HW_REST(); - return; - } - - if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) - { + if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) { I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); ESD_HW_REST(); return; - } - else if (HX_ESD_RESET_ACTIVATE) - { + } else if (HX_ESD_RESET_ACTIVATE) { #ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50)); + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(50)); #endif #ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50)); + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(50)); #endif - HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ - I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); +/*drop 1st interrupts after chip reset*/ + HX_ESD_RESET_ACTIVATE = 0; + I("[HIMAX TP MSG]:%s: Back from reset,ready to serve.\n", + __func__); } #endif - for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) + for (loop_i = 0, check_sum_cal = 0; + loop_i < hx_touch_info_size; loop_i++) check_sum_cal += buf[loop_i]; - - if ((check_sum_cal % 0x100 != 0) ) - { - I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); + + if ((check_sum_cal % 0x100 != 0)) { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", + check_sum_cal); return; } - if (ts->debug_log_level & BIT(0)) { I("%s: raw data:\n", __func__); for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { @@ -1048,260 +1057,289 @@ void himax_ts_work(struct himax_ts_data *ts) } } - //touch monitor raw data fetch + /*touch monitor raw data fetch*/ #ifdef HX_TP_PROC_DIAG diag_cmd = getDiagCommand(); - if (diag_cmd >= 1 && diag_cmd <= 6) - { - //Check 124th byte CRC - if(!diag_check_sum(hx_touch_info_size, buf)) - { + if (diag_cmd >= 1 && diag_cmd <= 6) { + /*Check 124th byte CRC*/ + if (!diag_check_sum(hx_touch_info_size, buf)) goto bypass_checksum_failed_packet; - } + #ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_cmd == 4) - { + if (Is_2T2R && diag_cmd == 4) { mutual_data = getMutualBuffer_2(); - self_data = getSelfBuffer(); + self_data = getSelfBuffer(); - // initiallize the block number of mutual and self + /* initiallize the block number of mutual and self*/ mul_num = getXChannel_2() * getYChannel_2(); #ifdef HX_EN_SEL_BUTTON - self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM; + self_num = getXChannel_2() + + getYChannel_2() + ic_data->HX_BT_NUM; #else self_num = getXChannel_2() + getYChannel_2(); #endif - } - else -#endif + } else +#endif { mutual_data = getMutualBuffer(); - self_data = getSelfBuffer(); + self_data = getSelfBuffer(); - // initiallize the block number of mutual and self + /* initiallize the block number of mutual and self*/ mul_num = getXChannel() * getYChannel(); #ifdef HX_EN_SEL_BUTTON - self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM; + self_num = getXChannel() + + getYChannel() + ic_data->HX_BT_NUM; #else self_num = getXChannel() + getYChannel(); #endif } - diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data, self_data); + diag_parse_raw_data(hx_touch_info_size, + RawDataLen, mul_num, self_num, buf, + diag_cmd, mutual_data, self_data); - } - else if (diag_cmd == 7) - { + } else if (diag_cmd == 7) { memcpy(&(diag_coor[0]), &buf[0], 128); } - //coordinate dump start - if (coordinate_dump_enable == 1) - { - for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++) - { + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + for (i = 0; i < (15 + (ic_data-> + HX_MAX_PT + 5) * 2 * 5); + i++) { coordinate_char[i] = 0x20; } - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD; - coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA; + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5] = 0xD; + coordinate_char[15 + + (ic_data->HX_MAX_PT + 5) * 2 * 5 + 1] = 0xA; } - //coordinate dump end + /*coordinate dump end*/ bypass_checksum_failed_packet: #endif - EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); - //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); - EN_NoiseFilter = EN_NoiseFilter & 0x01; - //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3); + /*I("EN_NoiseFilter=%d\n",EN_NoiseFilter);*/ + EN_NoiseFilter = EN_NoiseFilter & 0x01; + /*I("EN_NoiseFilter2=%d\n",EN_NoiseFilter);*/ #if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) - tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); - if (tpd_key == 0x0F)/*All (VK+AA)leave*/ - { - tpd_key = 0x00; - } - //I("[DEBUG] tpd_key: %x\r\n", tpd_key); -#else + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 4); + if (tpd_key == 0x0F) {/*All (VK+AA)leave*/ tpd_key = 0x00; + } + /*I("[DEBUG] tpd_key: %x\r\n", tpd_key);*/ +#else + tpd_key = 0x00; #endif - p_point_num = hx_point_num; - - if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) - hx_point_num = 0; - else - hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; - - // Touch Point information - if (hx_point_num != 0 ) { - if(vk_press == 0x00) - { - uint16_t old_finger = ts->pre_finger_mask; - ts->pre_finger_mask = 0; - finger_num = buf[coordInfoSize - 4] & 0x0F; - finger_on = 1; - AA_press = 1; - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - int base = loop_i * 4; - int x = buf[base] << 8 | buf[base + 1]; - int y = (buf[base + 2] << 8 | buf[base + 3]); - int w = buf[(ts->nFinger_support * 4) + loop_i]; - if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){ - finger_num--; - - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 0) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x * ts->widthFactor >> SHIFTBITS, - y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", - loop_i+1, x, y, w, EN_NoiseFilter); - } - } - } - - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - } - - input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); - input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); - input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); - input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); - - if (ts->protocol_type == PROTOCOL_TYPE_A) - { - input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); - input_mt_sync(ts->input_dev); - } - else - { - ts->last_slot = loop_i; - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); - } - - if (!ts->first_pressed) - { - ts->first_pressed = 1; - I("S1@%d, %d\n", x, y); - } - - ts->pre_finger_data[loop_i][0] = x; - ts->pre_finger_data[loop_i][1] = y; - - - if (ts->debug_log_level & BIT(1)) - I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", - loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); - - ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i); - - } else { - if (ts->protocol_type == PROTOCOL_TYPE_B) - { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - - if (loop_i == 0 && ts->first_pressed == 1) - { - ts->first_pressed = 2; - I("E1@%d, %d\n", - ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); - } - if ((ts->debug_log_level & BIT(3)) > 0) - { - if (old_finger >> loop_i == 1) - { - if (ts->useScreenRes) - { - I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } - else - { - I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", - loop_i+1, ts->pre_finger_data[loop_i][0], - ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - } - } + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num = buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + /* Touch Point information*/ + if ((hx_point_num != 0) && (vk_press == 0x00)) { + uint16_t old_finger = ts->pre_finger_mask; - }else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - //temp_x[0] = 0xFFFF; - //temp_y[0] = 0xFFFF; - //temp_x[1] = 0xFFFF; - //temp_y[1] = 0xFFFF; - himax_ts_button_func(tpd_key,ts); - finger_on = 0; + ts->pre_finger_mask = 0; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_on = 1; + AA_press = 1; + for (i = 0; i < ts->nFinger_support; i++) { + int base = i * 4; + int x = buf[base] << 8 | buf[base + 1]; + int y = (buf[base + 2] << 8 | buf[base + 3]); + int w = buf[(ts->nFinger_support * 4) + i]; + + if (x >= 0 && x <= ts->pdata->abs_x_max + && y >= 0 && y <= ts->pdata->abs_y_max) { + finger_num--; + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, + w, EN_NoiseFilter); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 0)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d", i + 1); + I("Down,X:%d,Y:%d,W:%d,N:%d\n", + x, y, w, EN_NoiseFilter); } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); - } else if (hx_point_num == 0){ - if(AA_press) - { - // leave event - finger_on = 0; - AA_press = 0; - if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); - for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->protocol_type == PROTOCOL_TYPE_B) { - input_mt_slot(ts->input_dev, loop_i); - input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); - } - } - } - if (ts->pre_finger_mask > 0) { - for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { - if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { - if (ts->useScreenRes) { - I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, - ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); - } else { - I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); - } - } - } - ts->pre_finger_mask = 0; + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_slot(ts->input_dev, i); + + input_report_abs(ts->input_dev, + ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, + ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, + ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, + ABS_MT_TRACKING_ID, i); + input_mt_sync(ts->input_dev); + } else { + ts->last_slot = i; + input_mt_report_slot_state + (ts->input_dev, + MT_TOOL_FINGER, 1); } - if (ts->first_pressed == 1) { - ts->first_pressed = 2; - I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + if (!ts->first_pressed) { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); } - if (ts->debug_log_level & BIT(1)) - I("All Finger leave\n"); + ts->pre_finger_data[i][0] = x; + ts->pre_finger_data[i][1] = y; + + if (ts->debug_log_level & BIT(1)) { + I("Finger %d=> X:%d,Y:%d,W:%d,", + i + 1, x, y, w); + I("Z:%d,F:%d,N:%d\n", + w, i + 1, EN_NoiseFilter); + } + ts->pre_finger_mask = + ts->pre_finger_mask + (1 << i); + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } + if (i == 0 && ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); + } + if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && (ts->useScreenRes)) { + I("status:Screen:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS); + } else if ((((ts->debug_log_level & BIT(3)) > 0) + && (old_finger >> i == 1)) + && !(ts->useScreenRes)) { + I("status:Raw:F:%02d,Up,X:%d,Y:%d\n", + i + 1, ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } } - else if (tpd_key != 0x00) { - himax_ts_button_func(tpd_key,ts); - finger_on = 1; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if ((hx_point_num != 0) + && ((tpd_key_old != 0x00) && (tpd_key == 0x00))) { + /*temp_x[0] = 0xFFFF;*/ + /*temp_y[0] = 0xFFFF;*/ + /*temp_x[1] = 0xFFFF;*/ + /*temp_y[1] = 0xFFFF;*/ + himax_ts_button_func(tpd_key, ts); + finger_on = 0; + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0) { + if (AA_press) { + /*leave event*/ + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (i = 0 ; i < ts->nFinger_support ; i++) { + if ((((ts->pre_finger_mask >> i) & 1) == 1) + && (ts->protocol_type == PROTOCOL_TYPE_B)) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state + (ts->input_dev, MT_TOOL_FINGER, 0); + } } - else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { - himax_ts_button_func(tpd_key,ts); - finger_on = 0; + if (ts->pre_finger_mask > 0) { + for (i = 0; i < ts->nFinger_support + && (ts->debug_log_level & BIT(3)) > 0; i++) { + if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && (ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0] + * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[i][1] + * ts->heightFactor >> SHIFTBITS + ); + } else if ((((ts->pre_finger_mask + >> i) & 1) == 1) + && !(ts->useScreenRes)) { + I("status:%X,", 0); + I("Screen:F:%02d,", i + 1); + I("Up,X:%d,Y:%d\n", + ts->pre_finger_data[i][0], + ts->pre_finger_data[i][1]); + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n", ts->pre_finger_data[0][0], + ts->pre_finger_data[0][1]); } - input_report_key(ts->input_dev, BTN_TOUCH, finger_on); - input_sync(ts->input_dev); + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + +#ifdef HX_TP_PROC_DIAG + /*coordinate dump start*/ + if (coordinate_dump_enable == 1) { + do_gettimeofday(&t); + time_to_tm(t.tv_sec, 0, &broken); + snprintf(&coordinate_char[0], 15, + "%2d:%2d:%2d:%lu,", broken.tm_hour, + broken.tm_min, broken.tm_sec, + t.tv_usec / 1000); + + snprintf(&coordinate_char[15], 10, + "Touch up!"); + + coordinate_fn->f_op->write + (coordinate_fn, &coordinate_char[0], + 15 + (ic_data->HX_MAX_PT + 5) + * 2 * sizeof(char) * 5 + 2, + &coordinate_fn->f_pos); + } + /*coordinate dump end*/ +#endif + } else if (tpd_key != 0x00) { + himax_ts_button_func(tpd_key, ts); + finger_on = 1; + } else if ((tpd_key_old != 0x00) && (tpd_key == 0x00)) { + himax_ts_button_func(tpd_key, ts); + finger_on = 0; } - tpd_key_old = tpd_key; - Last_EN_NoiseFilter = EN_NoiseFilter; + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; workqueue_out: return; @@ -1310,7 +1348,7 @@ void himax_ts_work(struct himax_ts_data *ts) I("%s: Now reset the Touch chip.\n", __func__); #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif goto workqueue_out; @@ -1329,6 +1367,7 @@ enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) static void himax_cable_tp_status_handler_func(int connect_status) { struct himax_ts_data *ts; + I("Touch: cable change to %d\n", connect_status); ts = private_ts; if (ts->cable_config) { @@ -1342,18 +1381,23 @@ static void himax_cable_tp_status_handler_func(int connect_status) ts->usb_connected = 0x00; } - i2c_himax_master_write(ts->client, ts->cable_config, - sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES); + i2c_himax_master_write(ts->client, + ts->cable_config, + sizeof(ts->cable_config), + HIMAX_I2C_RETRY_TIMES); - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->cable_config[1]); } else - I("%s: Cable status is the same as previous one, ignore.\n", __func__); + I("%s: Cable status is same, ignore.\n", + __func__); } else { if (connect_status) ts->usb_connected = 0x01; else ts->usb_connected = 0x00; - I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); + I("%s: Cable status remembered: 0x%2.2X\n", + __func__, ts->usb_connected); } } } @@ -1373,16 +1417,20 @@ void himax_cable_detect_func(void) struct himax_ts_data *ts; u32 connect_status = 0; - connect_status = USB_Flag;//upmu_is_chr_det(); + connect_status = USB_Flag;/*upmu_is_chr_det();*/ ts = private_ts; - //I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected); + /*I("Touch: cable status=%d, cable_config=%p, + usb_connected=%d\n", connect_status, + ts->cable_config, ts->usb_connected);*/ + if (ts->cable_config) { if ((!!connect_status) != ts->usb_connected) { - //notify USB plug/unplug - // 0x9008_8060 ==> 0x0000_0000/0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; - + /*notify USB plug/unplug*/ + /*0x9008_8060 ==> 0x0000_0000/0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; if (!!connect_status) { tmp_data[0] = 0x01; ts->usb_connected = 0x01; @@ -1393,10 +1441,13 @@ void himax_cable_detect_func(void) himax_flash_write_burst(ts->client, tmp_addr, tmp_data); - I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); - } - //else - //I("%s: Cable status is the same as previous one, ignore.\n", __func__); + I("%s: Cable status change: 0x%2.2X\n", + __func__, ts->usb_connected); + } + /*else*/ + /*I("%s: Cable status is the same as previous one, + ignore.\n", __func__);*/ + } } #endif @@ -1417,52 +1468,52 @@ int himax_fb_register(struct himax_ts_data *ts) #endif #ifdef HX_SMART_WAKEUP -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable) +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable) { uint8_t tmp_data[4]; - if(SMWP_enable) - { - SMWP_bit_retry: + if (SMWP_enable) { +SMWP_bit_retry: himax_set_SMWP_enable(client, SMWP_enable); msleep(20); - himax_get_SMWP_enable(client,tmp_data); - I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - if(tmp_data[0]!= 0x01) - { - I("%s: retry SMWP bit write data[0]=%x \n",__func__,tmp_data[0]); - goto SMWP_bit_retry; - } + himax_get_SMWP_enable(client, tmp_data); +I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", +__func__, tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]); + + if (tmp_data[0] != 0x01) { + I("%s: retry SMWP bit write data[0]=%x\n", + __func__, tmp_data[0]); + goto SMWP_bit_retry; + } } } static void himax_SMWP_work(struct work_struct *work) { - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, - smwp_work.work); + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, smwp_work.work); I(" %s in", __func__); - himax_set_SMWP_func(ts->client,ts->SMWP_enable); + himax_set_SMWP_func(ts->client, ts->SMWP_enable); } #endif -#ifdef HX_TP_PROC_FLASH_DUMP +#ifdef HX_TP_PROC_FLASH_DUMP static void himax_ts_flash_work_func(struct work_struct *work) { himax_ts_flash_func(); } #endif -#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_DIAG static void himax_ts_diag_work_func(struct work_struct *work) { himax_ts_diag_func(); } #endif -void himax_ts_init(struct himax_ts_data *ts) +bool himax_ts_init(struct himax_ts_data *ts) { int ret = 0, err = 0; struct himax_i2c_platform_data *pdata; @@ -1476,15 +1527,14 @@ void himax_ts_init(struct himax_ts_data *ts) /* Set pinctrl in active state */ if (ts->ts_pinctrl) { ret = pinctrl_select_state(ts->ts_pinctrl, - ts->pinctrl_state_active); - if (ret < 0) { - E("Failed to set pin in active state %d",ret); - } + ts->pinctrl_state_active); + if (ret < 0) + E("Failed to set pin in active state %d", ret); } himax_burst_enable(client, 0); - //Get Himax IC Type / FW information / Calculate the point number + /*Get Himax IC Type / FW information / Calculate the point number */ if (himax_check_chip_version(ts->client) == false) { E("Himax chip doesn NOT EXIST"); goto err_ic_package_failed; @@ -1496,10 +1546,9 @@ void himax_ts_init(struct himax_ts_data *ts) if (pdata->virtual_key) ts->button = pdata->virtual_key; -#ifdef HX_TP_PROC_FLASH_DUMP +#ifdef HX_TP_PROC_FLASH_DUMP ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); - if (!ts->flash_wq) - { + if (!ts->flash_wq) { E("%s: create flash workqueue failed\n", __func__); err = -ENOMEM; goto err_create_wq_failed; @@ -1511,10 +1560,9 @@ void himax_ts_init(struct himax_ts_data *ts) setFlashBuffer(); #endif -#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_DIAG ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); - if (!ts->himax_diag_wq) - { + if (!ts->himax_diag_wq) { E("%s: create diag workqueue failed\n", __func__); err = -ENOMEM; goto err_create_wq_failed; @@ -1526,40 +1574,42 @@ himax_read_FW_ver(client); #ifdef HX_AUTO_UPDATE_FW I(" %s in", __func__); - if(i_update_FW() == false) - I("NOT Have new FW=NOT UPDATE=\n"); + if (i_update_FW() <= 0) + I("FW NOT UPDATE=\n"); else I("Have new FW=UPDATE=\n"); #endif - //Himax Power On and Load Config + /*Himax Power On and Load Config*/ if (himax_loadSensorConfig(client, pdata) < 0) { - E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + E("%s: Load Sesnsor config failed,unload driver.\n", + __func__); goto err_detect_failed; } calculate_point_number(); #ifdef HX_TP_PROC_DIAG - setXChannel(ic_data->HX_RX_NUM); // X channel - setYChannel(ic_data->HX_TX_NUM); // Y channel + setXChannel(ic_data->HX_RX_NUM); /*X channel*/ + setYChannel(ic_data->HX_TX_NUM); /*Y channel*/ setMutualBuffer(); setMutualNewBuffer(); setMutualOldBuffer(); if (getMutualBuffer() == NULL) { E("%s: mutual buffer allocate fail failed\n", __func__); - return; + return false; } #ifdef HX_TP_PROC_2T2R - if(Is_2T2R){ - setXChannel_2(ic_data->HX_RX_NUM_2); // X channel - setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel + if (Is_2T2R) { + setXChannel_2(ic_data->HX_RX_NUM_2); /*X channel*/ + setYChannel_2(ic_data->HX_TX_NUM_2); /*Y channel*/ setMutualBuffer_2(); if (getMutualBuffer_2() == NULL) { - E("%s: mutual buffer 2 allocate fail failed\n", __func__); - return; + E("%s: mutual buffer 2 allocate fail failed\n", + __func__); + return false; } } #endif @@ -1572,7 +1622,7 @@ himax_read_FW_ver(client); ts->x_channel = ic_data->HX_RX_NUM; ts->y_channel = ic_data->HX_TX_NUM; ts->nFinger_support = ic_data->HX_MAX_PT; - //calculate the i2c data size + /*calculate the i2c data size*/ calcDataSize(ts->nFinger_support); I("%s: calcDataSize complete\n", __func__); #ifdef CONFIG_OF @@ -1584,14 +1634,13 @@ himax_read_FW_ver(client); pdata->cable_config[1] = 0x00; #endif ts->suspended = false; -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) ts->usb_connected = 0x00; ts->cable_config = pdata->cable_config; #endif ts->protocol_type = pdata->protocol_type; I("%s: Use Protocol Type %c\n", __func__, ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); - ret = himax_input_register(ts); if (ret) { E("%s: Unable to register %s input device\n", @@ -1599,8 +1648,9 @@ himax_read_FW_ver(client); goto err_input_register_device_failed; } #ifdef HX_SMART_WAKEUP - ts->SMWP_enable=0; - wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); + ts->SMWP_enable = 0; + wakeup_source_init(&ts->ts_SMWP_wake_lock, + WAKE_LOCK_SUSPEND, HIMAX_common_NAME); ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); if (!ts->himax_smwp_wq) { @@ -1611,7 +1661,7 @@ himax_read_FW_ver(client); INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); #endif #ifdef HX_HIGH_SENSE - ts->HSEN_enable=0; + ts->HSEN_enable = 0; ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); if (!ts->himax_hsen_wq) { E(" allocate himax_hsen_wq failed\n"); @@ -1633,7 +1683,7 @@ himax_read_FW_ver(client); err = himax_ts_register_interrupt(ts->client); if (err) goto err_register_interrupt_failed; - return; + return true; err_register_interrupt_failed: #ifdef HX_HIGH_SENSE @@ -1641,26 +1691,26 @@ himax_read_FW_ver(client); #endif #ifdef HX_SMART_WAKEUP err_smwp_wq_failed: - wake_lock_destroy(&ts->ts_SMWP_wake_lock); + wakeup_source_trash(&ts->ts_SMWP_wake_lock); #endif err_input_register_device_failed: input_free_device(ts->input_dev); err_detect_failed: -#ifdef HX_TP_PROC_FLASH_DUMP +#ifdef HX_TP_PROC_FLASH_DUMP err_create_wq_failed: #endif err_ic_package_failed: - -return; +return false; } -int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id) { int err = 0; struct himax_ts_data *ts; struct himax_i2c_platform_data *pdata; - //Check I2C functionality + /*Check I2C functionality*/ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { E("%s: i2c check functionality error\n", __func__); err = -ENODEV; @@ -1677,6 +1727,7 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i i2c_set_clientdata(client, ts); ts->client = client; ts->dev = &client->dev; + mutex_init(&ts->rw_lock); pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (pdata == NULL) { /*Allocate Platform data space*/ @@ -1691,7 +1742,8 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i } #ifdef CONFIG_OF - if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ + /*DeviceTree Init Platform_data*/ + if (client->dev.of_node) { err = himax_parse_dt(ts, pdata); if (err < 0) { I(" pdata is NULL for DT\n"); @@ -1704,12 +1756,11 @@ int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_i ts->rst_gpio = pdata->gpio_reset; #endif -himax_gpio_power_config(ts->client, pdata); + himax_gpio_power_config(ts->client, pdata); err = himax_ts_pinctrl_init(ts); - if (err || ts->ts_pinctrl == NULL) { + if (err || ts->ts_pinctrl == NULL) E(" Pinctrl init failed\n"); - } #ifndef CONFIG_OF if (pdata->power) { @@ -1736,7 +1787,7 @@ himax_gpio_power_config(ts->client, pdata); } #endif - return 0; + return 0; #ifdef CONFIG_FB err_fb_notif_wq_create: @@ -1783,8 +1834,10 @@ int himax_chip_common_remove(struct i2c_client *client) himax_touch_proc_deinit(); #endif #ifdef CONFIG_FB - if (fb_unregister_client(&ts->fb_notif)) - dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); + if (fb_unregister_client(&ts->fb_notif)) { + dev_err(&client->dev, + "Error occurred while unregistering fb_notifier.\n"); + } #endif if (!ts->use_irq) @@ -1810,7 +1863,7 @@ int himax_chip_common_remove(struct i2c_client *client) } } #ifdef HX_SMART_WAKEUP - wake_lock_destroy(&ts->ts_SMWP_wake_lock); + wakeup_source_trash(&ts->ts_SMWP_wake_lock); #endif kfree(ts); @@ -1822,38 +1875,36 @@ int himax_chip_common_suspend(struct himax_ts_data *ts) { int ret; - if(ts->suspended) - { - I("%s: Already suspended. Skipped. \n", __func__); + if (ts->suspended) { + I("%s: Already suspended. Skipped.\n", __func__); return 0; - } - else - { + + } else { ts->suspended = true; - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); } #ifdef HX_TP_PROC_FLASH_DUMP - if (getFlashDumpGoing()) - { - I("[himax] %s: Flash dump is going, reject suspend\n",__func__); + if (getFlashDumpGoing()) { + I("[himax] %s: Flash dump is going,reject suspend\n", + __func__); return 0; } #endif #ifdef HX_TP_PROC_HITOUCH - if(hitouch_is_connect) - { - I("[himax] %s: Hitouch connect, reject suspend\n",__func__); + if (hitouch_is_connect) { + I("[himax] %s: Hitouch connect,reject suspend\n", + __func__); return 0; } #endif #ifdef HX_SMART_WAKEUP - if(ts->SMWP_enable) - { + if (ts->SMWP_enable) { atomic_set(&ts->suspend_mode, 1); ts->pre_finger_mask = 0; - FAKE_POWER_KEY_SEND=false; - I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__); + FAKE_POWER_KEY_SEND = false; + I("[himax] %s: SMART_WAKEUP enable,reject suspend\n", + __func__); return 0; } #endif @@ -1864,19 +1915,18 @@ int himax_chip_common_suspend(struct himax_ts_data *ts) if (!ts->use_irq) { ret = cancel_work_sync(&ts->work); if (ret) - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); } - //ts->first_pressed = 0; + /*ts->first_pressed = 0;*/ atomic_set(&ts->suspend_mode, 1); ts->pre_finger_mask = 0; if (ts->ts_pinctrl) { ret = pinctrl_select_state(ts->ts_pinctrl, ts->pinctrl_state_suspend); - if (ret < 0) { + if (ret < 0) E("Failed to get idle pinctrl state %d\n", ret); - } } if (ts->pdata->powerOff3V3 && ts->pdata->power) @@ -1889,20 +1939,16 @@ int himax_chip_common_resume(struct himax_ts_data *ts) { int retval; - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); if (ts->pdata->powerOff3V3 && ts->pdata->power) ts->pdata->power(1); - - - /*************************************/ + if (ts->protocol_type == PROTOCOL_TYPE_A) - input_mt_sync(ts->input_dev); + input_mt_sync(ts->input_dev); input_report_key(ts->input_dev, BTN_TOUCH, 0); input_sync(ts->input_dev); - /*************************************/ - - + if (ts->ts_pinctrl) { retval = pinctrl_select_state(ts->ts_pinctrl, ts->pinctrl_state_active); @@ -1914,7 +1960,7 @@ int himax_chip_common_resume(struct himax_ts_data *ts) atomic_set(&ts->suspend_mode, 0); - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); ts->suspended = false; #if defined(HX_USB_DETECT2) @@ -1922,10 +1968,12 @@ int himax_chip_common_resume(struct himax_ts_data *ts) himax_cable_detect_func(); #endif #ifdef HX_SMART_WAKEUP - queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000)); + queue_delayed_work(ts->himax_smwp_wq, + &ts->smwp_work, msecs_to_jiffies(1000)); #endif #ifdef HX_HIGH_SENSE - queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000)); + queue_delayed_work(ts->himax_hsen_wq, + &ts->hsen_work, msecs_to_jiffies(1000)); #endif return 0; err_pinctrl_select_resume: diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h index 27ce9aafd959cc3bdbcaa7ca9166374398033bae..c4e24ba191bb1b6828b7ea867176ad807d92eac6 100644 --- a/drivers/input/touchscreen/hxchipset/himax_common.h +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -16,9 +16,13 @@ #ifndef HIMAX_COMMON_H #define HIMAX_COMMON_H +#include "himax_platform.h" + #include -#include -#include +/*#include */ +/*#include */ +#include +#include #include #include @@ -36,7 +40,6 @@ #include #include #include -#include "himax_platform.h" #if defined(CONFIG_FB) #include @@ -48,7 +51,7 @@ #ifdef CONFIG_OF #include #endif -#define HIMAX_DRIVER_VER "0.2.4.0" +#define HIMAX_DRIVER_VER "0.3.1.0" #define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" #define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" @@ -62,39 +65,39 @@ #define HX_TP_PROC_SELF_TEST #define HX_TP_PROC_RESET #define HX_TP_PROC_SENSE_ON_OFF -//#define HX_TP_PROC_2T2R +/*#define HX_TP_PROC_2T2R*/ int himax_touch_proc_init(void); void himax_touch_proc_deinit(void); #endif -//===========Himax Option function============= -//#define HX_RST_PIN_FUNC -//#define HX_AUTO_UPDATE_FW -//#define HX_HIGH_SENSE -//#define HX_SMART_WAKEUP -//#define HX_USB_DETECT -//#define HX_ESD_WORKAROUND -//#define HX_USB_DETECT2 - -//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close -#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close - -#define HX_KEY_MAX_COUNT 4 -#define DEFAULT_RETRY_CNT 3 - -#define HX_VKEY_0 KEY_BACK -#define HX_VKEY_1 KEY_HOME -#define HX_VKEY_2 KEY_RESERVED -#define HX_VKEY_3 KEY_RESERVED -#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} +/*===========Himax Option function=============*/ +/*#define HX_RST_PIN_FUNC*/ +#define HX_AUTO_UPDATE_FW +/*#define HX_HIGH_SENSE*/ +/*#define HX_SMART_WAKEUP*/ +/*#define HX_USB_DETECT*/ +/*#define HX_ESD_WORKAROUND*/ +/*#define HX_USB_DETECT2*/ +/*#define HX_EN_SEL_BUTTON*//* Support Self Virtual key ,default is close*/ +#define HX_EN_MUT_BUTTON/* Support Mutual Virtual Key ,default is close*/ +/*#define HX_EN_CHECK_PATCH*/ + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} #define SHIFTBITS 5 -//#define FLASH_SIZE 131072 -#define FW_SIZE_60k 61440 -#define FW_SIZE_64k 65536 -#define FW_SIZE_124k 126976 -#define FW_SIZE_128k 131072 +/*#define FLASH_SIZE 131072*/ +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 struct himax_ic_data { int vendor_fw_ver; @@ -183,12 +186,12 @@ struct himax_ts_data { bool suspended; bool probe_done; struct mutex fb_mutex; + struct mutex rw_lock; atomic_t suspend_mode; uint8_t x_channel; uint8_t y_channel; uint8_t useScreenRes; uint8_t diag_command; - uint8_t protocol_type; uint8_t first_pressed; uint8_t coord_data_size; @@ -198,11 +201,9 @@ struct himax_ts_data { uint8_t nFinger_support; uint8_t irq_enabled; uint8_t diag_self[50]; - uint16_t finger_pressed; uint16_t last_slot; uint16_t pre_finger_mask; - uint32_t debug_log_level; uint32_t widthFactor; uint32_t heightFactor; @@ -214,20 +215,20 @@ struct himax_ts_data { uint32_t pl_x_max; uint32_t pl_y_min; uint32_t pl_y_max; - + int use_irq; int (*power)(int on); int pre_finger_data[10][2]; - + struct device *dev; struct workqueue_struct *himax_wq; struct work_struct work; struct input_dev *input_dev; struct hrtimer timer; struct i2c_client *client; - struct himax_i2c_platform_data *pdata; + struct himax_i2c_platform_data *pdata; struct himax_virtual_key *button; - + #if defined(CONFIG_FB) struct notifier_block fb_notif; #elif defined(CONFIG_HAS_EARLYSUSPEND) @@ -235,8 +236,8 @@ struct himax_ts_data { #endif #ifdef HX_TP_PROC_FLASH_DUMP - struct workqueue_struct *flash_wq; - struct work_struct flash_work; + struct workqueue_struct *flash_wq; + struct work_struct flash_work; #endif #ifdef HX_RST_PIN_FUNC @@ -250,7 +251,7 @@ struct himax_ts_data { #ifdef HX_SMART_WAKEUP uint8_t SMWP_enable; uint8_t gesture_cust_en[16]; - struct wake_lock ts_SMWP_wake_lock; + struct wakeup_source ts_SMWP_wake_lock; struct workqueue_struct *himax_smwp_wq; struct delayed_work smwp_work; #endif @@ -261,7 +262,7 @@ struct himax_ts_data { struct delayed_work hsen_work; #endif -#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) +#if defined(HX_USB_DETECT) || defined(HX_USB_DETECT2) uint8_t usb_connected; uint8_t *cable_config; #endif @@ -273,30 +274,30 @@ struct himax_ts_data { struct pinctrl_state *pinctrl_state_release; }; -#define HX_CMD_NOP 0x00 -#define HX_CMD_SETMICROOFF 0x35 -#define HX_CMD_SETROMRDY 0x36 -#define HX_CMD_TSSLPIN 0x80 -#define HX_CMD_TSSLPOUT 0x81 -#define HX_CMD_TSSOFF 0x82 -#define HX_CMD_TSSON 0x83 -#define HX_CMD_ROE 0x85 -#define HX_CMD_RAE 0x86 -#define HX_CMD_RLE 0x87 -#define HX_CMD_CLRES 0x88 -#define HX_CMD_TSSWRESET 0x9E -#define HX_CMD_SETDEEPSTB 0xD7 -#define HX_CMD_SET_CACHE_FUN 0xDD -#define HX_CMD_SETIDLE 0xF2 -#define HX_CMD_SETIDLEDELAY 0xF3 -#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D #define HX_CMD_MANUALMODE 0x42 -#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_ENABLE 0x43 #define HX_CMD_FLASH_SET_ADDRESS 0x44 #define HX_CMD_FLASH_WRITE_REGISTER 0x45 #define HX_CMD_FLASH_SET_COMMAND 0x47 #define HX_CMD_FLASH_WRITE_BUFFER 0x48 -#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_PAGE_ERASE 0x4D #define HX_CMD_FLASH_SECTOR_ERASE 0x4E #define HX_CMD_CB 0xCB #define HX_CMD_EA 0xEA @@ -311,7 +312,7 @@ enum input_protocol_type { }; #ifdef HX_HIGH_SENSE -void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); +void himax_set_HSEN_func(struct i2c_client *client, uint8_t HSEN_enable); #endif #ifdef HX_SMART_WAKEUP @@ -319,18 +320,18 @@ void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); #define GEST_PTLG_HDR_LEN (4) #define GEST_PTLG_HDR_ID1 (0xCC) #define GEST_PTLG_HDR_ID2 (0x44) -#define GEST_PT_MAX_NUM (128) +#define GEST_PT_MAX_NUM (128) #ifdef HX_GESTURE_TRACK static int gest_pt_cnt; static int gest_pt_x[GEST_PT_MAX_NUM]; static int gest_pt_y[GEST_PT_MAX_NUM]; -static int gest_start_x,gest_start_y,gest_end_x,gest_end_y; -static int gest_width,gest_height,gest_mid_x,gest_mid_y; +static int gest_start_x, gest_start_y, gest_end_x, gest_end_y; +static int gest_width, gest_height, gest_mid_x, gest_mid_y; static int gn_gesture_coor[16]; #endif -void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable); +void himax_set_SMWP_func(struct i2c_client *client, uint8_t SMWP_enable); extern bool FAKE_POWER_KEY_SEND; enum gesture_event_type { @@ -380,16 +381,91 @@ irqreturn_t himax_ts_thread(int irq, void *ptr); int himax_input_register(struct himax_ts_data *ts); #endif -extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id); -extern int himax_chip_common_remove(struct i2c_client *client); -extern int himax_chip_common_suspend(struct himax_ts_data *ts); -extern int himax_chip_common_resume(struct himax_ts_data *ts); -int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata); +int himax_chip_common_probe(struct i2c_client *client, +const struct i2c_device_id *id); +int himax_chip_common_remove(struct i2c_client *client); +int himax_chip_common_suspend(struct himax_ts_data *ts); +int himax_chip_common_resume(struct himax_ts_data *ts); +int himax_loadSensorConfig(struct i2c_client *client, +struct himax_i2c_platform_data *pdata); #ifdef HX_USB_DETECT2 -//extern kal_bool upmu_is_chr_det(void); +/*extern kal_bool upmu_is_chr_det(void);*/ void himax_cable_detect_func(void); #endif +#ifdef HX_AUTO_UPDATE_FW +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +#endif +extern unsigned long FW_VER_MAJ_FLASH_LENG; +extern unsigned long FW_VER_MIN_FLASH_LENG; +extern unsigned long CFG_VER_MAJ_FLASH_LENG; +extern unsigned long CFG_VER_MIN_FLASH_LENG; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +/*PROC-START*/ +#ifdef HX_TP_PROC_FLASH_DUMP +extern void himax_ts_flash_func(void); +extern void setFlashBuffer(void); +extern bool getFlashDumpGoing(void); +extern uint8_t getSysOperation(void); +extern void setSysOperation(uint8_t operation); +#endif + +#ifdef HX_TP_PROC_HITOUCH +extern bool hitouch_is_connect; +#endif + +#ifdef HX_TP_PROC_DIAG + extern int touch_monitor_stop_flag; + + extern int touch_monitor_stop_limit; + + extern void himax_ts_diag_func(void); + + extern int16_t *getMutualBuffer(void); + extern int16_t *getMutualNewBuffer(void); + extern int16_t *getMutualOldBuffer(void); + extern int16_t *getSelfBuffer(void); + extern uint8_t getXChannel(void); + extern uint8_t getYChannel(void); + extern uint8_t getDiagCommand(void); + extern void setXChannel(uint8_t x); + extern void setYChannel(uint8_t y); + extern void setMutualBuffer(void); + extern void setMutualNewBuffer(void); + extern void setMutualOldBuffer(void); + extern uint8_t coordinate_dump_enable; + extern struct file *coordinate_fn; + extern uint8_t diag_coor[128]; +#ifdef HX_TP_PROC_2T2R + extern int16_t *getMutualBuffer_2(void); + extern uint8_t getXChannel_2(void); + extern uint8_t getYChannel_2(void); + extern void setXChannel_2(uint8_t x); + extern void setYChannel_2(uint8_t y); + extern void setMutualBuffer_2(void); +#endif +#endif +/*PROC-END*/ +#endif + +#ifdef HX_USB_DETECT2 + extern bool USB_Flag; +#endif +#ifdef HX_ESD_WORKAROUND + extern void HX_report_ESD_event(void); + unsigned char ESD_00_counter = 0; + unsigned char ESD_00_Flag = 0; +#endif +bool himax_ts_init(struct himax_ts_data *ts); + #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c index f8bee11b43515e3bb3c84124aaaf00766d312741..a5bdbf207e015319f264f456c317184d254602a3 100644 --- a/drivers/input/touchscreen/hxchipset/himax_debug.c +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -16,32 +16,16 @@ #include "himax_debug.h" #include "himax_ic.h" -//struct himax_debug_data* debug_data; - -extern struct himax_ic_data* ic_data; -extern struct himax_ts_data *private_ts; -extern unsigned char IC_TYPE; -extern unsigned char IC_CHECKSUM; -extern int himax_input_register(struct himax_ts_data *ts); -#ifdef QCT -extern irqreturn_t himax_ts_thread(int irq, void *ptr); -#endif -#ifdef MTK -#ifdef CONFIG_OF_TOUCH -extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); -#else -extern void tpd_eint_interrupt_handler(void); -#endif -#endif +/*struct himax_debug_data* debug_data;*/ #ifdef HX_TP_PROC_DIAG #ifdef HX_TP_PROC_2T2R -int HX_RX_NUM_2 = 0; -int HX_TX_NUM_2 = 0; +int HX_RX_NUM_2; +int HX_TX_NUM_2; #endif -int touch_monitor_stop_flag = 0; +int touch_monitor_stop_flag; int touch_monitor_stop_limit = 5; -uint8_t g_diag_arr_num = 0; +uint8_t g_diag_arr_num; #endif #ifdef HX_ESD_WORKAROUND @@ -52,11 +36,11 @@ u8 HX_ESD_RESET_ACTIVATE; bool FAKE_POWER_KEY_SEND; #endif -//============================================================================================================= -// -// Segment : Himax PROC Debug Function -// -//============================================================================================================= +/*======================================================== + +Segment : Himax PROC Debug Function + +==========================================================*/ #if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) static ssize_t himax_vendor_read(struct file *file, char *buf, @@ -65,33 +49,26 @@ static ssize_t himax_vendor_read(struct file *file, char *buf, ssize_t ret = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } + ret += snprintf(temp_buf, len, + "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", + HIMAX_common_NAME, ic_data->vendor_fw_ver, + ic_data->vendor_config_ver, ic_data->vendor_sensor_id); - ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME, - ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id); - HX_PROC_SEND_FLAG=1; + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } -static const struct file_operations himax_proc_vendor_ops = -{ +const struct file_operations himax_proc_vendor_ops = { .owner = THIS_MODULE, .read = himax_vendor_read, }; @@ -107,29 +84,21 @@ static ssize_t himax_attn_read(struct file *file, char *buf, if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); + ret += snprintf(temp_buf, len, "attn = %x\n", + himax_int_gpio_read(ts_data->pdata->gpio_irq)); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } - -static const struct file_operations himax_proc_attn_ops = -{ +const struct file_operations himax_proc_attn_ops = { .owner = THIS_MODULE, .read = himax_attn_read, }; @@ -143,23 +112,16 @@ static ssize_t himax_int_en_read(struct file *file, char *buf, if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf, len-1, "%d ", ts->irq_enabled); + ret += snprintf(temp_buf, 1, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -167,18 +129,15 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, size_t len, loff_t *pos) { struct himax_ts_data *ts = private_ts; - char buf_tmp[12]= {0}; - int value, ret=0; + char buf_tmp[12] = {0}; + int value, ret = 0; - if (len >= 12) - { + if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf_tmp, buff, len)) - { return -EFAULT; - } if (buf_tmp[0] == '0') value = false; @@ -188,36 +147,43 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, return -EINVAL; if (value) { - if(ic_data->HX_INT_IS_EDGE) - { + if (ic_data->HX_INT_IS_EDGE) { #ifdef MTK #ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); #else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); #endif #endif #ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + ts->client->name, ts); #endif - } - else - { + } else { #ifdef MTK #ifdef CONFIG_OF_TOUCH - himax_int_enable(ts->client->irq,1); + himax_int_enable(ts->client->irq, 1); #else - //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); - //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); - mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); + /*mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_TYPE); + mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, + CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN);*/ + mt_eint_registration(ts->client->irq, + EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); #endif #endif #ifdef QCT - ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); + ret = request_threaded_irq(ts->client->irq, + NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + ts->client->name, ts); #endif } if (ret == 0) { @@ -225,7 +191,7 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, irq_enable_count = 1; } } else { - himax_int_enable(ts->client->irq,0); + himax_int_enable(ts->client->irq, 0); free_irq(ts->client->irq, ts); ts->irq_enabled = 0; } @@ -233,8 +199,7 @@ static ssize_t himax_int_en_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_int_en_ops = -{ +const struct file_operations himax_proc_int_en_ops = { .owner = THIS_MODULE, .read = himax_int_en_read, .write = himax_int_en_write, @@ -249,26 +214,19 @@ static ssize_t himax_layout_read(struct file *file, char *buf, if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min); - ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_max); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_min); + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_y_max); + ret += snprintf(temp_buf, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -283,17 +241,14 @@ static ssize_t himax_layout_write(struct file *file, const char *buff, int layout[4] = {0}; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - for (i = 0; i < 20; i++) { + for (i = 0 ; i < 20 ; i++) { if (buf[i] == ',' || buf[i] == '\n') { memset(buf_tmp, 0x0, sizeof(buf_tmp)); if (i - j <= 5) @@ -310,20 +265,24 @@ static ssize_t himax_layout_write(struct file *file, const char *buff, } } if (k == 4) { - ts->pdata->abs_x_min=layout[0]; - ts->pdata->abs_x_max=layout[1]; - ts->pdata->abs_y_min=layout[2]; - ts->pdata->abs_y_max=layout[3]; - I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + ts->pdata->abs_x_min = layout[0]; + ts->pdata->abs_x_max = layout[1]; + ts->pdata->abs_y_min = layout[2]; + ts->pdata->abs_y_max = layout[3]; + I("%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); input_unregister_device(ts->input_dev); himax_input_register(ts); - } else - I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + } else { + I("ERR@%d, %d, %d, %d\n", ts->pdata->abs_x_min, + ts->pdata->abs_x_max, ts->pdata->abs_y_min, + ts->pdata->abs_y_max); + } return len; } -static const struct file_operations himax_proc_layout_ops = -{ +const struct file_operations himax_proc_layout_ops = { .owner = THIS_MODULE, .read = himax_layout_read, .write = himax_layout_write, @@ -335,26 +294,21 @@ static ssize_t himax_debug_level_read(struct file *file, char *buf, struct himax_ts_data *ts_data; size_t ret = 0; char *temp_buf; + ts_data = private_ts; if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level); + ret += snprintf(temp_buf, len, "%d\n", + ts_data->debug_log_level); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -365,29 +319,26 @@ static ssize_t himax_debug_level_write(struct file *file, const char *buff, struct himax_ts_data *ts; char buf_tmp[11]; int i; + ts = private_ts; - if (len >= 12) - { + if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf_tmp, buff, len)) - { return -EFAULT; - } ts->debug_log_level = 0; - for(i=0; i='0' && buf_tmp[i]<='9' ) - ts->debug_log_level |= (buf_tmp[i]-'0'); - else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' ) - ts->debug_log_level |= (buf_tmp[i]-'A'+10); - else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' ) - ts->debug_log_level |= (buf_tmp[i]-'a'+10); - - if(i!=len-2) + for (i = 0 ; i < len - 1 ; i++) { + if (buf_tmp[i] >= '0' && buf_tmp[i] <= '9') + ts->debug_log_level |= (buf_tmp[i] - '0'); + else if (buf_tmp[i] >= 'A' && buf_tmp[i] <= 'F') + ts->debug_log_level |= (buf_tmp[i]-'A' + 10); + else if (buf_tmp[i] >= 'a' && buf_tmp[i] <= 'f') + ts->debug_log_level |= (buf_tmp[i] - 'a' + 10); + + if (i != len - 2) ts->debug_log_level <<= 4; } @@ -395,8 +346,12 @@ static ssize_t himax_debug_level_write(struct file *file, const char *buff, if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { - ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); - ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); + ts->widthFactor = + (ts->pdata->screenWidth << SHIFTBITS) + / (ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = + (ts->pdata->screenHeight << SHIFTBITS) + / (ts->pdata->abs_y_max - ts->pdata->abs_y_min); if (ts->widthFactor > 0 && ts->heightFactor > 0) ts->useScreenRes = 1; else { @@ -415,8 +370,7 @@ static ssize_t himax_debug_level_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_debug_level_ops = -{ +const struct file_operations himax_proc_debug_level_ops = { .owner = THIS_MODULE, .read = himax_debug_level_read, .write = himax_debug_level_write, @@ -433,35 +387,33 @@ static ssize_t himax_proc_register_read(struct file *file, char *buf, memset(data, 0x00, sizeof(data)); - I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); - if(!HX_PROC_SEND_FLAG) - { + I("himax_register_show: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], register_command[3]); + + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_register_read(private_ts->client, register_command, 1, data); + himax_register_read(private_ts->client, + register_command, 1, data); - ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", + register_command[0], register_command[1], + register_command[2], register_command[3]); - for (loop_i = 0; loop_i < 128; loop_i++) { - ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, + sizeof(data[loop_i]), "0x%2.2X ", data[loop_i]); if ((loop_i % 16) == 15) - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf + ret, 1, "\n"); } - ret += snprintf(temp_buf+ret, len-ret, "\n"); - HX_PROC_SEND_FLAG=1; + ret += snprintf(temp_buf + ret, len, "\n"); + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } @@ -475,40 +427,48 @@ static ssize_t himax_proc_register_write(struct file *file, const char *buff, uint8_t write_da[128]; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } memset(buf_tmp, 0x0, sizeof(buf_tmp)); memset(write_da, 0x0, sizeof(write_da)); - I("himax %s \n",buf); + I("himax %s\n", buf); if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { if (buf[2] == 'x') { memcpy(buf_tmp, buf + 3, 8); - if (!kstrtoul(buf_tmp, 16, &result)) - { - register_command[0] = (uint8_t)result; - register_command[1] = (uint8_t)(result >> 8); - register_command[2] = (uint8_t)(result >> 16); - register_command[3] = (uint8_t)(result >> 24); - } + if (!kstrtoul(buf_tmp, 16, &result)) { + register_command[0] = + (uint8_t)result; + register_command[1] = + (uint8_t)(result >> 8); + register_command[2] = + (uint8_t)(result >> 16); + register_command[3] = + (uint8_t)(result >> 24); + } base = 11; - I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + I("CMD: %x,%x,%x,%x\n", register_command[0], + register_command[1], register_command[2], + register_command[3]); - for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) { + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { if (buf[base] == '\n') { if (buf[0] == 'w') { - himax_register_write(private_ts->client, register_command, 1, write_da); - I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length); + himax_register_write + (private_ts->client, + register_command + , 1, write_da); + I("CMD:%x, %x, %x, %x,len=%d\n", + write_da[0], write_da[1], + write_da[2], write_da[3], + length); } I("\n"); return len; @@ -518,12 +478,16 @@ static ssize_t himax_proc_register_write(struct file *file, const char *buff, buf_tmp[11] = '\0'; memcpy(buf_tmp, buf + base + 2, 8); if (!kstrtoul(buf_tmp, 16, &result)) { - write_da[loop_i] = (uint8_t)result; - write_da[loop_i+1] = (uint8_t)(result >> 8); - write_da[loop_i+2] = (uint8_t)(result >> 16); - write_da[loop_i+3] = (uint8_t)(result >> 24); + write_da[loop_i] = + (uint8_t)result; + write_da[loop_i+1] = + (uint8_t)(result >> 8); + write_da[loop_i+2] = + (uint8_t)(result >> 16); + write_da[loop_i+3] = + (uint8_t)(result >> 24); } - length+=4; + length += 4; } base += 10; } @@ -532,8 +496,7 @@ static ssize_t himax_proc_register_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_register_ops = -{ +const struct file_operations himax_proc_register_ops = { .owner = THIS_MODULE, .read = himax_proc_register_read, .write = himax_proc_register_write, @@ -579,15 +542,18 @@ void setYChannel(uint8_t y) } void setMutualBuffer(void) { - diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); + diag_mutual = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); } void setMutualNewBuffer(void) { - diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); + diag_mutual_new = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); } void setMutualOldBuffer(void) { - diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); + diag_mutual_old = kzalloc + (x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); } #ifdef HX_TP_PROC_2T2R @@ -613,94 +579,82 @@ void setYChannel_2(uint8_t y) } void setMutualBuffer_2(void) { - diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); + diag_mutual_2 = kzalloc + (x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); } #endif static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, size_t len, loff_t *pos) { - //struct himax_ts_data *ts = private_ts; + /*struct himax_ts_data *ts = private_ts;*/ char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } g_diag_arr_num = buf[0] - '0'; - I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num); + I("%s: g_diag_arr_num = %d\n", __func__, g_diag_arr_num); return len; } -static const struct file_operations himax_proc_diag_arrange_ops = -{ +const struct file_operations himax_proc_diag_arrange_ops = { .owner = THIS_MODULE, .write = himax_diag_arrange_write, }; -static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) +static void himax_diag_arrange_print +(struct seq_file *s, int i, int j, int transpose) { - if(transpose) - seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]); + if (transpose) + seq_printf(s, "%6d", diag_mutual[j + i * x_channel]); else - seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]); + seq_printf(s, "%6d", diag_mutual[i + j * x_channel]); } -static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j) +static void himax_diag_arrange_inloop +(struct seq_file *s, int in_init, bool transpose, int j) { int i; int in_max = 0; - if(transpose) + if (transpose) in_max = y_channel; else in_max = x_channel; - if (in_init > 0) - { - for(i = in_init-1;i >= 0;i--) - { + if (in_init > 0) { + for (i = in_init - 1 ; i >= 0 ; i--) himax_diag_arrange_print(s, i, j, transpose); - } - } - else - { - for (i = 0; i < in_max; i++) - { + } else { + for (i = 0 ; i < in_max ; i++) himax_diag_arrange_print(s, i, j, transpose); - } } } -static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init) +static void himax_diag_arrange_outloop +(struct seq_file *s, int transpose, int out_init, int in_init) { int j; int out_max = 0; - if(transpose) + if (transpose) out_max = x_channel; else out_max = y_channel; - if(out_init > 0) - { - for(j = out_init-1;j >= 0;j--) - { + if (out_init > 0) { + for (j = out_init - 1 ; j >= 0 ; j--) { himax_diag_arrange_inloop(s, in_init, transpose, j); seq_printf(s, " %5d\n", diag_self[j]); } - } - else - { - for(j = 0;j < out_max;j++) - { + } else { + for (j = 0 ; j < out_max ; j++) { himax_diag_arrange_inloop(s, in_init, transpose, j); seq_printf(s, " %5d\n", diag_self[j]); } @@ -709,33 +663,35 @@ static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int ou static void himax_diag_arrange(struct seq_file *s) { - int bit2,bit1,bit0; + int bit2, bit1, bit0; int i; bit2 = g_diag_arr_num >> 2; bit1 = g_diag_arr_num >> 1 & 0x1; bit0 = g_diag_arr_num & 0x1; - if (g_diag_arr_num < 4) - { - himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel); - for (i = y_channel; i < x_channel + y_channel; i++) { + if (g_diag_arr_num < 4) { + himax_diag_arrange_outloop(s, + bit2, bit1 * y_channel, bit0 * x_channel); + + for (i = y_channel ; i < x_channel + y_channel ; i++) seq_printf(s, "%6d", diag_self[i]); - } - } - else - { - himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel); - for (i = x_channel; i < x_channel + y_channel; i++) { + + } else { + himax_diag_arrange_outloop(s, + bit2, bit1 * x_channel, bit0 * y_channel); + + for (i = x_channel ; i < x_channel + y_channel ; i++) seq_printf(s, "%6d", diag_self[i]); - } + } } static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) { - if (*pos>=1) return NULL; - return (void *)((unsigned long) *pos+1); + if (*pos >= 1) + return NULL; + return (void *)((unsigned long) *pos + 1); } static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) @@ -748,87 +704,96 @@ static void himax_diag_seq_stop(struct seq_file *s, void *v) static int himax_diag_seq_read(struct seq_file *s, void *v) { size_t count = 0; - int32_t loop_i;//,loop_j + int32_t loop_i;/*loop_j*/ uint16_t mutual_num, self_num, width; #ifdef HX_TP_PROC_2T2R - if(Is_2T2R && diag_command == 4) - { + if (Is_2T2R && diag_command == 4) { mutual_num = x_channel_2 * y_channel_2; - self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT + /*don't add KEY_COUNT*/ + self_num = x_channel_2 + y_channel_2; width = x_channel_2; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); - } - else + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel_2, y_channel_2); + } else #endif { mutual_num = x_channel * y_channel; - self_num = x_channel + y_channel; //don't add KEY_COUNT + /*don't add KEY_COUNT*/ + self_num = x_channel + y_channel; width = x_channel; - seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); + seq_printf(s, "ChannelStart: %4d, %4d\n\n", + x_channel, y_channel); } - // start to show out the raw data in adb shell + /* start to show out the raw data in adb shell*/ if (diag_command >= 1 && diag_command <= 6) { if (diag_command <= 3) { himax_diag_arrange(s); - seq_printf(s, "\n\n"); + seq_puts(s, "\n\n"); #ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) + seq_printf(s, "%6d", + diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); #endif #ifdef HX_TP_PROC_2T2R - }else if(Is_2T2R && diag_command == 4 ) { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { + } else if (Is_2T2R && diag_command == 4) { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { seq_printf(s, "%4d", diag_mutual_2[loop_i]); if ((loop_i % width) == (width - 1)) - seq_printf(s, " %6d\n", diag_self[width + loop_i/width]); + seq_printf(s, " %6d\n", + diag_self[width + loop_i / width]); } - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < width; loop_i++) { + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < width ; loop_i++) { seq_printf(s, "%6d", diag_self[loop_i]); if (((loop_i) % width) == (width - 1)) - seq_printf(s, "\n"); + seq_putc(s, '\n'); } #ifdef HX_EN_SEL_BUTTON - seq_printf(s, "\n"); - for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) - seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); + seq_putc(s, '\n'); + for (loop_i = 0 ; loop_i < HX_BT_NUM ; loop_i++) { + seq_printf(s, "%4d", + diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); + } #endif #endif } else if (diag_command > 4) { - for (loop_i = 0; loop_i < self_num; loop_i++) { + for (loop_i = 0 ; loop_i < self_num ; loop_i++) { seq_printf(s, "%4d", diag_self[loop_i]); - if (((loop_i - mutual_num) % width) == (width - 1)) - seq_printf(s, "\n"); + if (((loop_i - mutual_num) % width) + == (width - 1)) { + seq_putc(s, '\n'); + } } } else { - for (loop_i = 0; loop_i < mutual_num; loop_i++) { + for (loop_i = 0 ; loop_i < mutual_num ; loop_i++) { seq_printf(s, "%4d", diag_mutual[loop_i]); if ((loop_i % width) == (width - 1)) - seq_printf(s, "\n"); + seq_putc(s, '\n'); } } - seq_printf(s, "ChannelEnd"); - seq_printf(s, "\n"); + seq_puts(s, "ChannelEnd"); + seq_putc(s, '\n'); } else if (diag_command == 7) { - for (loop_i = 0; loop_i < 128 ;loop_i++) { + for (loop_i = 0; loop_i < 128 ; loop_i++) { if ((loop_i % 16) == 0) - seq_printf(s, "LineStart:"); + seq_puts(s, "LineStart:"); seq_printf(s, "%4d", diag_coor[loop_i]); if ((loop_i % 16) == 15) - seq_printf(s, "\n"); + seq_putc(s, '\n'); } - } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){ + } else if (diag_command == 9 || + diag_command == 91 || diag_command == 92) { + himax_diag_arrange(s); - seq_printf(s, "\n"); + seq_putc(s, '\n'); } return count; } -static const struct seq_operations himax_diag_seq_ops = -{ +const struct seq_operations himax_diag_seq_ops = { .start = himax_diag_seq_start, .next = himax_diag_seq_next, .stop = himax_diag_seq_stop, @@ -838,25 +803,24 @@ static int himax_diag_proc_open(struct inode *inode, struct file *file) { return seq_open(file, &himax_diag_seq_ops); }; -bool DSRAM_Flag; +bool DSRAM_Flag = false; -//DSRAM thread +/*DSRAM thread*/ void himax_ts_diag_func(void) { - int i=0, j=0; + int i = 0, j = 0; unsigned int index = 0; int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; uint8_t info_data[total_size]; - int16_t *mutual_data = NULL; + int16_t *mutual_data = NULL; int16_t *mutual_data_new = NULL; int16_t *mutual_data_old = NULL; int16_t new_data; himax_burst_enable(private_ts->client, 1); - if(diag_command == 9 || diag_command == 91) - { + if (diag_command == 9 || diag_command == 91) { mutual_data = getMutualBuffer(); - }else if(diag_command == 92){ + } else if (diag_command == 92) { mutual_data = getMutualBuffer(); mutual_data_new = getMutualNewBuffer(); mutual_data_old = getMutualOldBuffer(); @@ -864,49 +828,63 @@ void himax_ts_diag_func(void) himax_get_DSRAM_data(private_ts->client, info_data); index = 0; - for (i = 0; i < ic_data->HX_TX_NUM; i++) - { - for (j = 0; j < ic_data->HX_RX_NUM; j++) - { - new_data = (short)(info_data[index + 1] << 8 | info_data[index]); - if(diag_command == 9){ - mutual_data[i*ic_data->HX_RX_NUM+j] = new_data; - }else if(diag_command == 91){ //Keep max data for 100 frame - if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data) - mutual_data[i * ic_data->HX_RX_NUM + j] = new_data; - }else if(diag_command == 92){ //Cal data for [N]-[N-1] frame - mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data; - mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j]; + for (i = 0 ; i < ic_data->HX_TX_NUM ; i++) { + for (j = 0 ; j < ic_data->HX_RX_NUM ; j++) { + new_data = (short)(info_data[index + 1] + << 8 | info_data[index]); + if (diag_command == 9) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + /*Keep max data for 100 frame*/ + } else if (diag_command == 91) { + if (mutual_data[i * ic_data->HX_RX_NUM + j] + < new_data) { + mutual_data[i * ic_data->HX_RX_NUM + j] + = new_data; + } + /*Cal data for [N]-[N-1] frame*/ + } else if (diag_command == 92) { + mutual_data_new[i * ic_data->HX_RX_NUM + j] + = new_data; + + mutual_data[i * ic_data->HX_RX_NUM + j] = + mutual_data_new[i * ic_data->HX_RX_NUM + j] - + mutual_data_old[i * ic_data->HX_RX_NUM + j]; } index += 2; } } - if(diag_command == 92){ - memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array + /*copy N data to N-1 array*/ + if (diag_command == 92) { + memcpy(mutual_data_old, mutual_data_new, + x_channel * y_channel * sizeof(int16_t)); } + diag_max_cnt++; - if(diag_command == 9 || diag_command == 92){ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); - }else if(diag_command == 91){ - if(diag_max_cnt > 100) //count for 100 frame - { - //Clear DSRAM flag + if (diag_command == 9 || diag_command == 92) { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } else if (diag_command == 91) { + if (diag_max_cnt > 100) {/*count for 100 frame*/ + /*Clear DSRAM flag*/ DSRAM_Flag = false; - //Enable ISR - himax_int_enable(private_ts->client->irq,1); + /*Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); - //===================================== - // test result command : 0x8002_0324 ==> 0x00 - //===================================== + /*===================================== + test result command : 0x8002_0324 ==> 0x00 + =====================================*/ himax_diag_register_set(private_ts->client, 0x00); - }else{ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } else { + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 1 / 10 * HZ); } } } -static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) +static ssize_t himax_diag_write +(struct file *filp, const char __user *buff, size_t len, loff_t *data) { char messages[80] = {0}; @@ -915,67 +893,66 @@ static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size memset(receive, 0x00, sizeof(receive)); - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(messages, buff, len)) - { return -EFAULT; - } - if (messages[1] == 0x0A){ - diag_command =messages[0] - '0'; - }else{ - diag_command =(messages[0] - '0')*10 + (messages[1] - '0'); - } - I("[Himax]diag_command=0x%x\n",diag_command); - if (diag_command < 0x04){ - if(DSRAM_Flag) - { - //1. Clear DSRAM flag + if (messages[1] == 0x0A) + diag_command = messages[0] - '0'; + else + diag_command = (messages[0] - '0') * 10 + (messages[1] - '0'); + + + I("[Himax]diag_command=0x%x\n", diag_command); + if (diag_command < 0x04) { + if (DSRAM_Flag) { + /*1. Clear DSRAM flag*/ DSRAM_Flag = false; - //2. Stop DSRAM thread - cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok); + /*2. Stop DSRAM thread*/ + cancel_delayed_work_sync + (&private_ts->himax_diag_delay_wrok); - //3. Enable ISR - himax_int_enable(private_ts->client->irq,1); + /*3. Enable ISR*/ + himax_int_enable(private_ts->client->irq, 1); } command[0] = diag_command; himax_diag_register_set(private_ts->client, command[0]); - } - //coordinate dump start - else if (diag_command == 0x08) { - E("%s: coordinate_dump_file_create error\n", __func__); - } - else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){ + /*coordinate dump start*/ + } else if (diag_command == 0x09 || + diag_command == 91 || diag_command == 92) { + diag_max_cnt = 0; - memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime + /*Set data 0 everytime*/ + memset(diag_mutual, 0x00, + x_channel * y_channel * sizeof(int16_t)); - //1. Disable ISR - himax_int_enable(private_ts->client->irq,0); + /*1. Disable ISR*/ + himax_int_enable(private_ts->client->irq, 0); - //2. Start DSRAM thread - //himax_diag_register_set(private_ts->client, 0x0A); + /*2. Start DSRAM thread*/ + /*himax_diag_register_set(private_ts->client, 0x0A);*/ - queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100); + queue_delayed_work(private_ts->himax_diag_wq, + &private_ts->himax_diag_delay_wrok, 2 * HZ / 100); I("%s: Start get raw data in DSRAM\n", __func__); - //3. Set DSRAM flag + /*3. Set DSRAM flag*/ DSRAM_Flag = true; - }else{ + } else { command[0] = 0x00; himax_diag_register_set(private_ts->client, command[0]); - E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); + E("[Himax]Diag command error!diag_command=0x%x\n", + diag_command); } return len; } -static const struct file_operations himax_proc_diag_ops = -{ +const struct file_operations himax_proc_diag_ops = { .owner = THIS_MODULE, .open = himax_diag_proc_open, .read = seq_read, @@ -989,23 +966,20 @@ static ssize_t himax_reset_write(struct file *file, const char *buff, { char buf_tmp[12]; - if (len >= 12) - { + if (len >= 12) { I("%s: no command exceeds 12 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf_tmp, buff, len)) - { return -EFAULT; - } - //if (buf_tmp[0] == '1') - // ESD_HW_REST(); + + /*if (buf_tmp[0] == '1') + ESD_HW_REST();*/ return len; } -static const struct file_operations himax_proc_reset_ops = -{ +const struct file_operations himax_proc_reset_ops = { .owner = THIS_MODULE, .write = himax_reset_write, }; @@ -1018,291 +992,263 @@ static ssize_t himax_debug_read(struct file *file, char *buf, size_t count = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf){ - HX_PROC_SEND_FLAG=0; - return count; - } - - if (debug_level_cmd == 't') - { - if (fw_update_complete) - count += snprintf(temp_buf+count, len-count, "FW Update Complete "); - else - { - count += snprintf(temp_buf+count, len-count, "FW Update Fail "); - } - } - else if (debug_level_cmd == 'h') - { - if (handshaking_result == 0) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result); - } - else if (handshaking_result == 1) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); - } - else if (handshaking_result == 2) - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result); - } - else - { - count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n"); - } - } - else if (debug_level_cmd == 'v') - { - count += snprintf(temp_buf+count, len-count, "FW_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver); - count += snprintf(temp_buf+count, len-count, "CONFIG_VER = "); - count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver); - count += snprintf(temp_buf+count, len-count, "\n"); - } - else if (debug_level_cmd == 'd') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n"); - if (IC_TYPE == HX_85XX_D_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : D\n"); - } - else if (IC_TYPE == HX_85XX_E_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : E\n"); - } - else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : ES\n"); - } - else if (IC_TYPE == HX_85XX_F_SERIES_PWON) - { - count += snprintf(temp_buf+count, len-count, "IC Type : F\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "IC Type error.\n"); + if (debug_level_cmd == 't') { + if (fw_update_complete) { + count += snprintf(temp_buf, len, + "FW Update Complete "); + } else { + count += snprintf(temp_buf, len, + "FW Update Fail "); } - if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n"); + } else if (debug_level_cmd == 'h') { + if (handshaking_result == 0) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Running)\n", + handshaking_result); + } else if (handshaking_result == 1) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (MCU Stop)\n", + handshaking_result); + } else if (handshaking_result == 2) { + count += snprintf(temp_buf, len, + "Handshaking Result = %d (I2C Error)\n", + handshaking_result); + } else { + count += snprintf(temp_buf, len, + "Handshaking Result = error\n"); } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n"); + } else if (debug_level_cmd == 'v') { + count += snprintf(temp_buf + count, len, + "FW_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_fw_ver); + count += snprintf(temp_buf + count, len, + "CONFIG_VER = "); + count += snprintf(temp_buf + count, len, + "0x%2.2X\n", ic_data->vendor_config_ver); + count += snprintf(temp_buf + count, len, + "\n"); + } else if (debug_level_cmd == 'd') { + count += snprintf(temp_buf + count, len, + "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : D\n"); + } else if (IC_TYPE == HX_85XX_E_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : E\n"); + } else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : ES\n"); + } else if (IC_TYPE == HX_85XX_F_SERIES_PWON) { + count += snprintf(temp_buf + count, len, + "IC Type : F\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Type error.\n"); } - else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) - { - count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n"); + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : SW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) { + count += snprintf(temp_buf + count, len, + "IC Checksum : HW\n"); + } else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) { + count += snprintf(temp_buf + count, len, + "IC Checksum : CRC\n"); + } else { + count += snprintf(temp_buf + count, len, + "IC Checksum error.\n"); } - else - { - count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n"); + if (ic_data->HX_INT_IS_EDGE) { + count += snprintf(temp_buf + count, len, + "Interrupt : EDGE TIRGGER\n"); + } else { + count += snprintf(temp_buf + count, len, + "Interrupt : LEVEL TRIGGER\n"); } - - if (ic_data->HX_INT_IS_EDGE) - { - count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n"); - } - else - { - count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n"); - } - - count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM); - count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM); - count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM); - count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES); - count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES); - count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT); - count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE); + count += snprintf(temp_buf + count, len, + "RX Num : %d\n", ic_data->HX_RX_NUM); + count += snprintf(temp_buf + count, len, + "TX Num : %d\n", ic_data->HX_TX_NUM); + count += snprintf(temp_buf + count, len, + "BT Num : %d\n", ic_data->HX_BT_NUM); + count += snprintf(temp_buf + count, len, + "X Resolution : %d\n", ic_data->HX_X_RES); + count += snprintf(temp_buf + count, len, + "Y Resolution : %d\n", ic_data->HX_Y_RES); + count += snprintf(temp_buf + count, len, + "Max Point : %d\n", ic_data->HX_MAX_PT); + count += snprintf(temp_buf + count, len, + "XY reverse : %d\n", ic_data->HX_XY_REVERSE); #ifdef HX_TP_PROC_2T2R - if(Is_2T2R) - { - count += snprintf(temp_buf+count, len-count, "2T2R panel\n"); - count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2); - count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2); + if (Is_2T2R) { + count += snprintf(temp_buf + count, len, + "2T2R panel\n"); + count += snprintf(temp_buf + count, len, + "RX Num_2 : %d\n", HX_RX_NUM_2); + count += snprintf(temp_buf + count, len, + "TX Num_2 : %d\n", HX_TX_NUM_2); } #endif - } - else if (debug_level_cmd == 'i') - { - count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n"); - count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER); + } else if (debug_level_cmd == 'i') { + count += snprintf(temp_buf + count, len, + "Himax Touch Driver Version:\n"); + count += snprintf(temp_buf + count, len, + "%s\n", HIMAX_DRIVER_VER); } if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; return count; } static ssize_t himax_debug_write(struct file *file, const char *buff, size_t len, loff_t *pos) { - const struct firmware *fw = NULL; - unsigned char *fw_data = NULL; + int result = 0; char fileName[128]; char buf[80] = {0}; - int result; + const struct firmware *fw = NULL; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if ( buf[0] == 'h') //handshaking - { + if (buf[0] == 'h') {/*handshaking*/ debug_level_cmd = buf[0]; - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); - handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail + /*0:Running, 1:Stop, 2:I2C Fail*/ + handshaking_result = himax_hand_shaking(private_ts->client); - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); return len; - } - - else if ( buf[0] == 'v') //firmware version - { + } else if (buf[0] == 'v') { /*firmware version*/ debug_level_cmd = buf[0]; - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); #ifdef HX_RST_PIN_FUNC - himax_HW_reset(false,false); + himax_HW_reset(false, false); #endif himax_read_FW_ver(private_ts->client); - //himax_check_chip_version(); + /*himax_check_chip_version();*/ #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); return len; - } + } else if (buf[0] == 'd') { /*ic information*/ - else if ( buf[0] == 'd') //ic information - { debug_level_cmd = buf[0]; return len; - } + } else if (buf[0] == 'i') {/*driver version*/ - else if ( buf[0] == 'i') //driver version - { debug_level_cmd = buf[0]; return len; - } - - else if (buf[0] == 't') - { + } else if (buf[0] == 't') { - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); + debug_level_cmd = buf[0]; + fw_update_complete = false; - debug_level_cmd = buf[0]; - fw_update_complete = false; + result = himax_load_CRC_bin_file(private_ts->client); + if (result < 0) { + E("%s: himax_load_CRC_bin_file fail Error Code=%d.\n", + __func__, result); + return result; + } memset(fileName, 0, 128); - // parse the file name +/* parse the file name*/ snprintf(fileName, len-4, "%s", &buf[4]); I("%s: upgrade from file(%s) start!\n", __func__, fileName); - // open file result = request_firmware(&fw, fileName, private_ts->dev); - if (result) { - E("%s: open firmware file failed\n", __func__); - goto firmware_upgrade_done; - //return len; - } - - I("%s: FW len %d\n", __func__, fw->size); - fw_data = (unsigned char *)fw->data; - - I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); - - if (fw_data != NULL) - { - // start to upgrade - himax_int_enable(private_ts->client->irq,0); - - if ((buf[1] == '6') && (buf[2] == '0')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + if (result < 0) { + I("fail to request_firmware fwpath: %s (ret:%d)\n", + fileName, result); + return result; + } + I("%s: FW image: %02X, %02X, %02X, %02X ret=%d\n", __func__, + fw->data[0], fw->data[1], fw->data[2], fw->data[3], result); + if (result >= 0) { + /*start to upgrade*/ + himax_int_enable(private_ts->client->irq, 0); + + if ((buf[1] == '6') && (buf[2] == '0')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_60k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else if ((buf[1] == '6') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + } else if ((buf[1] == '6') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_64k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else if ((buf[1] == '2') && (buf[2] == '4')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + } else if ((buf[1] == '2') && (buf[2] == '4')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_124k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else if ((buf[1] == '2') && (buf[2] == '8')) - { - if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0) - { - E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + } else if ((buf[1] == '2') && (buf[2] == '8')) { + if (fts_ctpm_fw_upgrade_with_sys_fs_128k + (private_ts->client, (unsigned char *)fw->data, + fw->size, false) == 0) { + E("%s: TP upgrade error, line: %d\n", + __func__, __LINE__); fw_update_complete = false; - } - else - { - I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + } else { + I("%s: TP upgrade OK, line: %d\n", + __func__, __LINE__); fw_update_complete = true; } - } - else - { - E("%s: Flash command fail: %d\n", __func__, __LINE__); + } else { + E("%s: Flash command fail: %d\n", + __func__, __LINE__); fw_update_complete = false; } release_firmware(fw); goto firmware_upgrade_done; - //return count; + /*return count;*/ } } - firmware_upgrade_done: +firmware_upgrade_done: #ifdef HX_RST_PIN_FUNC - himax_HW_reset(true,false); + himax_HW_reset(true, false); #endif himax_sense_on(private_ts->client, 0x01); @@ -1310,16 +1256,15 @@ static ssize_t himax_debug_write(struct file *file, const char *buff, #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; #endif - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); - //todo himax_chip->tp_firmware_upgrade_proceed = 0; - //todo himax_chip->suspend_state = 0; - //todo enable_irq(himax_chip->irq); + /*todo himax_chip->tp_firmware_upgrade_proceed = 0; + todo himax_chip->suspend_state = 0; + todo enable_irq(himax_chip->irq);*/ return len; } -static const struct file_operations himax_proc_debug_ops = -{ +const struct file_operations himax_proc_debug_ops = { .owner = THIS_MODULE, .read = himax_debug_read, .write = himax_debug_write, @@ -1376,9 +1321,9 @@ bool getFlashDumpGoing(void) void setFlashBuffer(void) { - flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL); - if (flash_buffer) - memset(flash_buffer,0x00,Flash_Size); + flash_buffer = kzalloc + (Flash_Size * sizeof(uint8_t), GFP_KERNEL); + memset(flash_buffer, 0x00, Flash_Size); } void setSysOperation(uint8_t operation) @@ -1389,7 +1334,8 @@ void setSysOperation(uint8_t operation) static void setFlashDumpProgress(uint8_t progress) { flash_progress = progress; - //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); + /*I("setFlashDumpProgress : progress = %d , + flash_progress = %d\n",progress,flash_progress);*/ } static void setFlashDumpComplete(uint8_t status) @@ -1432,130 +1378,113 @@ static ssize_t himax_proc_flash_read(struct file *file, char *buf, { int ret = 0; int loop_i; - uint8_t local_flash_read_step=0; + uint8_t local_flash_read_step = 0; uint8_t local_flash_complete = 0; uint8_t local_flash_progress = 0; uint8_t local_flash_command = 0; uint8_t local_flash_fail = 0; char *temp_buf; + local_flash_complete = getFlashDumpComplete(); local_flash_progress = getFlashDumpProgress(); local_flash_command = getFlashCommand(); local_flash_fail = getFlashDumpFail(); - I("flash_progress = %d \n",local_flash_progress); - if(!HX_PROC_SEND_FLAG) - { + I("flash_progress = %d\n", local_flash_progress); + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - - if (local_flash_fail) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (local_flash_fail) { + ret += snprintf(temp_buf + ret, len, + "FlashStart:Fail\n"); + ret += snprintf(temp_buf + ret, len, + "FlashEnd"); + ret += snprintf(temp_buf + ret, len, + "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - if (!local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (!local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Ongoing:0x%2.2x\n", flash_progress); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - if (local_flash_command == 1 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n"); - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (local_flash_command == 1 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, + "FlashStart:Complete\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - if (local_flash_command == 3 && local_flash_complete) - { - ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n"); - for(loop_i = 0; loop_i < 128; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]); + if (local_flash_command == 3 && local_flash_complete) { + ret += snprintf(temp_buf+ret, len, "FlashStart:\n"); + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, + "x%2.2x", flash_buffer[loop_i]); if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } + ret += snprintf(temp_buf + ret, len, + "\n"); } - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; return ret; } - //flash command == 0 , report the data + /*flash command == 0 , report the data*/ local_flash_read_step = getFlashReadStep(); - ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step); + ret += snprintf(temp_buf + ret, len, + "FlashStart:%2.2x\n", local_flash_read_step); - for (loop_i = 0; loop_i < 1024; loop_i++) - { - ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); + for (loop_i = 0 ; loop_i < 1024 ; loop_i++) { + ret += snprintf(temp_buf + ret, len, "x%2.2X", + flash_buffer[local_flash_read_step * 1024 + loop_i]); if ((loop_i % 16) == 15) - { - ret += snprintf(temp_buf+ret, len-ret, "\n"); - } + ret += snprintf(temp_buf + ret, len, "\n"); } - ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); - ret += snprintf(temp_buf+ret, len-ret, "\n"); + ret += snprintf(temp_buf + ret, len, "FlashEnd"); + ret += snprintf(temp_buf + ret, len, "\n"); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } -static ssize_t himax_proc_flash_write(struct file *file, const char *buff, - size_t len, loff_t *pos) +static ssize_t himax_proc_flash_write(struct file *file, +const char *buff, size_t len, loff_t *pos) { char buf_tmp[6]; unsigned long result = 0; @@ -1563,85 +1492,74 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, int base = 0; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } memset(buf_tmp, 0x0, sizeof(buf_tmp)); I("%s: buf[0] = %s\n", __func__, buf); - if (getSysOperation() == 1) - { + if (getSysOperation() == 1) { E("%s: PROC is busy , return!\n", __func__); return len; } - if (buf[0] == '0') - { + if (buf[0] == '0') { setFlashCommand(0); - if (buf[1] == ':' && buf[2] == 'x') - { + if (buf[1] == ':' && buf[2] == 'x') { memcpy(buf_tmp, buf + 3, 2); I("%s: read_Step = %s\n", __func__, buf_tmp); - if (!kstrtoul(buf_tmp, 16, &result)) - { - I("%s: read_Step = %lu \n", __func__, result); + if (!kstrtoul(buf_tmp, 16, &result)) { + I("%s: read_Step = %lu\n", __func__, result); setFlashReadStep(result); } } - } - else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k - { + /* 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '1') { + setSysOperation(1); setFlashCommand(1); setFlashDumpProgress(0); setFlashDumpComplete(0); setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ + else if (buf[3] == '4') Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ + else if (buf[3] == '8') Flash_Size = FW_SIZE_128k; - } } queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k - { + /* 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k*/ + } else if (buf[0] == '2') { setSysOperation(1); setFlashCommand(2); setFlashDumpProgress(0); setFlashDumpComplete(0); setFlashDumpFail(0); - if ((buf[1] == '_' ) && (buf[2] == '6' )){ - if (buf[3] == '0'){ + if ((buf[1] == '_') && (buf[2] == '6')) { + if (buf[3] == '0') Flash_Size = FW_SIZE_60k; - }else if (buf[3] == '4'){ + else if (buf[3] == '4') Flash_Size = FW_SIZE_64k; - } - }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ - if (buf[3] == '4'){ + + } else if ((buf[1] == '_') && (buf[2] == '2')) { + if (buf[3] == '4') Flash_Size = FW_SIZE_124k; - }else if (buf[3] == '8'){ + else if (buf[3] == '8') Flash_Size = FW_SIZE_128k; - } + } queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '3') - { + } else if (buf[0] == '3') { setSysOperation(1); setFlashCommand(3); setFlashDumpProgress(0); @@ -1650,20 +1568,14 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, memcpy(buf_tmp, buf + 3, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpSector(result); - } memcpy(buf_tmp, buf + 7, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpPage(result); - } queue_work(private_ts->flash_wq, &private_ts->flash_work); - } - else if (buf[0] == '4') - { + } else if (buf[0] == '4') { I("%s: command 4 enter.\n", __func__); setSysOperation(1); setFlashCommand(4); @@ -1673,40 +1585,29 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, memcpy(buf_tmp, buf + 3, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpSector(result); - } else - { E("%s: command 4 , sector error.\n", __func__); return len; - } + memcpy(buf_tmp, buf + 7, 2); if (!kstrtoul(buf_tmp, 16, &result)) - { setFlashDumpPage(result); - } else - { E("%s: command 4 , page error.\n", __func__); return len; - } base = 11; I("=========Himax flash page buffer start=========\n"); - for(loop_i=0;loop_i<128 && base<80;loop_i++) - { + for (loop_i = 0 ; loop_i < 128 ; loop_i++) { memcpy(buf_tmp, buf + base, 2); - if (!kstrtoul(buf_tmp, 16, &result)) - { + if (!kstrtoul(buf_tmp, 16, &result)) { flash_buffer[loop_i] = result; - I("%d ",flash_buffer[loop_i]); + I("%d ", flash_buffer[loop_i]); if (loop_i % 16 == 15) - { I("\n"); - } } base += 3; } @@ -1717,8 +1618,7 @@ static ssize_t himax_proc_flash_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_flash_ops = -{ +const struct file_operations himax_proc_flash_ops = { .owner = THIS_MODULE, .read = himax_proc_flash_read, .write = himax_proc_flash_write, @@ -1728,31 +1628,44 @@ void himax_ts_flash_func(void) { uint8_t local_flash_command = 0; - himax_int_enable(private_ts->client->irq,0); + himax_int_enable(private_ts->client->irq, 0); setFlashDumpGoing(true); - //sector = getFlashDumpSector(); - //page = getFlashDumpPage(); + /*sector = getFlashDumpSector();*/ + /*page = getFlashDumpPage();*/ local_flash_command = getFlashCommand(); msleep(100); - I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); + I("%s: local_flash_command = %d enter.\n", + __func__, local_flash_command); - if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F)) - { - himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer); + if ((local_flash_command == 1 || local_flash_command == 2) + || (local_flash_command == 0x0F)) { + himax_flash_dump_func(private_ts->client, + local_flash_command, Flash_Size, flash_buffer); } + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); - if (local_flash_command == 2) - { - E("Flash dump failed\n"); + if (local_flash_command == 2) { + struct file *fn; + struct filename *vts_name; + + vts_name = getname_kernel(FLASH_DUMP_FILE); + fn = file_open_name(vts_name, O_CREAT | O_WRONLY, 0); + if (!IS_ERR(fn)) { + I("%s create file and ready to write\n", __func__); + fn->f_op->write(fn, flash_buffer, + Flash_Size * sizeof(uint8_t), &fn->f_pos); + + filp_close(fn, NULL); + } } - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); setFlashDumpGoing(false); setFlashDumpComplete(1); @@ -1761,7 +1674,7 @@ void himax_ts_flash_func(void) /* Flash_Dump_i2c_transfer_error: - himax_int_enable(private_ts->client->irq,1); + himax_int_enable(private_ts->client->irq, 1); setFlashDumpGoing(false); setFlashDumpComplete(0); setFlashDumpFail(1); @@ -1776,53 +1689,47 @@ void himax_ts_flash_func(void) static ssize_t himax_self_test_read(struct file *file, char *buf, size_t len, loff_t *pos) { - int val=0x00; + int val = 0x00; int ret = 0; char *temp_buf; - I("%s: enter, %d \n", __func__, __LINE__); - if(!HX_PROC_SEND_FLAG) - { + I("%s:enter, %d\n", __func__, __LINE__); + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - himax_int_enable(private_ts->client->irq,0);//disable irq + himax_int_enable(private_ts->client->irq, 0);/*disable irq*/ val = himax_chip_self_test(private_ts->client); #ifdef HX_ESD_WORKAROUND HX_ESD_RESET_ACTIVATE = 1; #endif - himax_int_enable(private_ts->client->irq,1);//enable irq + himax_int_enable(private_ts->client->irq, 1);/*enable irq*/ if (val == 0x01) { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n"); + ret += snprintf(temp_buf + ret, len, + "Self_Test Pass\n"); } else { - ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n"); + ret += snprintf(temp_buf + ret, len, + "Self_Test Fail\n"); } - if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return ret; } /* -static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count) +static ssize_t himax_chip_self_test_store(struct device *dev, +struct device_attribute *attr, const char *buf, size_t count) { char buf_tmp[2]; unsigned long result = 0; memset(buf_tmp, 0x0, sizeof(buf_tmp)); memcpy(buf_tmp, buf, 2); - if(!kstrtoul(buf_tmp, 16, &result)) + if (!kstrtoul(buf_tmp, 16, &result)) { sel_type = (uint8_t)result; } @@ -1831,8 +1738,7 @@ static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attri } */ -static const struct file_operations himax_proc_self_test_ops = -{ +const struct file_operations himax_proc_self_test_ops = { .owner = THIS_MODULE, .read = himax_self_test_read, }; @@ -1844,42 +1750,33 @@ static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, { char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if(buf[0] == '0') - { + if (buf[0] == '0') { himax_sense_off(private_ts->client); - I("Sense off \n"); - } - else if(buf[0] == '1') - { - if(buf[1] == '1'){ + I("Sense off\n"); + } else if (buf[0] == '1') { + if (buf[1] == '1') { himax_sense_on(private_ts->client, 0x01); - I("Sense on re-map off, run flash \n"); - }else if(buf[1] == '0'){ + I("Sense on re-map off, run flash\n"); + } else if (buf[1] == '0') { himax_sense_on(private_ts->client, 0x00); - I("Sense on re-map on, run sram \n"); - }else{ - I("Do nothing \n"); + I("Sense on re-map on, run sram\n"); + } else { + I("Do nothing\n"); } - } - else - { - I("Do nothing \n"); + } else { + I("Do nothing\n"); } return len; } -static const struct file_operations himax_proc_sense_on_off_ops = -{ +const struct file_operations himax_proc_sense_on_off_ops = { .owner = THIS_MODULE, .write = himax_sense_on_off_write, }; @@ -1893,25 +1790,18 @@ static ssize_t himax_HSEN_read(struct file *file, char *buf, size_t count = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); - HX_PROC_SEND_FLAG=1; + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } + kfree(temp_buf); - } - else - HX_PROC_SEND_FLAG=0; + } else + HX_PROC_SEND_FLAG = 0; return count; } @@ -1922,22 +1812,17 @@ static ssize_t himax_HSEN_write(struct file *file, const char *buff, char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if (buf[0] == '0'){ + if (buf[0] == '0') ts->HSEN_enable = 0; - } - else if (buf[0] == '1'){ + else if (buf[0] == '1') ts->HSEN_enable = 1; - } else return -EINVAL; @@ -1948,8 +1833,7 @@ static ssize_t himax_HSEN_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_HSEN_ops = -{ +const struct file_operations himax_proc_HSEN_ops = { .owner = THIS_MODULE, .read = himax_HSEN_read, .write = himax_HSEN_write, @@ -1964,25 +1848,17 @@ static ssize_t himax_SMWP_read(struct file *file, char *buf, struct himax_ts_data *ts = private_ts; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return count; - } - count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable); + count = snprintf(temp_buf, "%d\n", len, ts->SMWP_enable); if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); - HX_PROC_SEND_FLAG=1; - } - else - HX_PROC_SEND_FLAG=0; + HX_PROC_SEND_FLAG = 1; + } else + HX_PROC_SEND_FLAG = 0; return count; } @@ -1993,25 +1869,17 @@ static ssize_t himax_SMWP_write(struct file *file, const char *buff, struct himax_ts_data *ts = private_ts; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - if (buf[0] == '0') - { ts->SMWP_enable = 0; - } else if (buf[0] == '1') - { ts->SMWP_enable = 1; - } else return -EINVAL; @@ -2022,41 +1890,33 @@ static ssize_t himax_SMWP_write(struct file *file, const char *buff, return len; } -static const struct file_operations himax_proc_SMWP_ops = -{ +const struct file_operations himax_proc_SMWP_ops = { .owner = THIS_MODULE, .read = himax_SMWP_read, .write = himax_SMWP_write, }; -static ssize_t himax_GESTURE_read(struct file *file, char *buf, - size_t len, loff_t *pos) +static ssize_t himax_GESTURE_read(struct file *file, +char *buf, size_t len, loff_t *pos) { struct himax_ts_data *ts = private_ts; - int i =0; + int i = 0; int ret = 0; char *temp_buf; - if(!HX_PROC_SEND_FLAG) - { + if (!HX_PROC_SEND_FLAG) { temp_buf = kzalloc(len, GFP_KERNEL); - if (!temp_buf) { - HX_PROC_SEND_FLAG=0; - return ret; - } - for(i=0;i<16;i++) - ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + for (i = 0 ; i < 16 ; i++) + ret += snprintf(temp_buf + ret, len, + "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + HX_PROC_SEND_FLAG = 1; if (copy_to_user(buf, temp_buf, len)) - { I("%s,here:%d\n", __func__, __LINE__); - } kfree(temp_buf); HX_PROC_SEND_FLAG = 1; - } - else - { + } else { HX_PROC_SEND_FLAG = 0; ret = 0; } @@ -2067,35 +1927,30 @@ static ssize_t himax_GESTURE_write(struct file *file, const char *buff, size_t len, loff_t *pos) { struct himax_ts_data *ts = private_ts; - int i =0; + int i = 0; char buf[80] = {0}; - if (len >= 80) - { + if (len >= 80) { I("%s: no command exceeds 80 chars.\n", __func__); return -EFAULT; } if (copy_from_user(buf, buff, len)) - { return -EFAULT; - } - I("himax_GESTURE_store= %s \n",buf); - for (i=0;i<16;i++) - { + I("himax_GESTURE_store= %s\n", buf); + for (i = 0 ; i < 16 ; i++) { if (buf[i] == '0') - ts->gesture_cust_en[i]= 0; + ts->gesture_cust_en[i] = 0; else if (buf[i] == '1') - ts->gesture_cust_en[i]= 1; + ts->gesture_cust_en[i] = 1; else - ts->gesture_cust_en[i]= 0; - I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); + ts->gesture_cust_en[i] = 0; + I("gesture en[%d]=%d\n", i, ts->gesture_cust_en[i]); } return len; } -static const struct file_operations himax_proc_Gesture_ops = -{ +const struct file_operations himax_proc_Gesture_ops = { .owner = THIS_MODULE, .read = himax_GESTURE_read, .write = himax_GESTURE_write, @@ -2104,202 +1959,223 @@ static const struct file_operations himax_proc_Gesture_ops = int himax_touch_proc_init(void) { - himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); - if (himax_touch_proc_dir == NULL) - { + himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) { E(" %s: himax_touch_proc_dir file create failed!\n", __func__); return -ENOMEM; } - himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); - if (himax_proc_debug_level_file == NULL) - { + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); + + if (himax_proc_debug_level_file == NULL) { E(" %s: proc debug_level file create failed!\n", __func__); goto fail_1; } - himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops); - if(himax_proc_vendor_file == NULL) - { + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_vendor_ops); + + if (himax_proc_vendor_file == NULL) { E(" %s: proc vendor file create failed!\n", __func__); goto fail_2; } - himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops); - if(himax_proc_attn_file == NULL) - { + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_attn_ops); + + if (himax_proc_attn_file == NULL) { E(" %s: proc attn file create failed!\n", __func__); goto fail_3; } - himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); - if(himax_proc_int_en_file == NULL) - { + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); + + if (himax_proc_int_en_file == NULL) { E(" %s: proc int en file create failed!\n", __func__); goto fail_4; } - himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); - if(himax_proc_layout_file == NULL) - { + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); + + if (himax_proc_layout_file == NULL) { E(" %s: proc layout file create failed!\n", __func__); goto fail_5; } #ifdef HX_TP_PROC_RESET - himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); - if(himax_proc_reset_file == NULL) - { + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, + (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); + + if (himax_proc_reset_file == NULL) { E(" %s: proc reset file create failed!\n", __func__); goto fail_6; } #endif #ifdef HX_TP_PROC_DIAG - himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); - if(himax_proc_diag_file == NULL) - { + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); + + if (himax_proc_diag_file == NULL) { E(" %s: proc diag file create failed!\n", __func__); goto fail_7; } - himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops); - if(himax_proc_diag_arrange_file == NULL) - { + himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, + (S_IWUSR | S_IRUGO), + himax_touch_proc_dir, &himax_proc_diag_arrange_ops); + + if (himax_proc_diag_arrange_file == NULL) { E(" %s: proc diag file create failed!\n", __func__); goto fail_7_1; } #endif #ifdef HX_TP_PROC_REGISTER - himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); - if(himax_proc_register_file == NULL) - { + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); + + if (himax_proc_register_file == NULL) { E(" %s: proc register file create failed!\n", __func__); goto fail_8; } #endif #ifdef HX_TP_PROC_DEBUG - himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); - if(himax_proc_debug_file == NULL) - { + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); + + if (himax_proc_debug_file == NULL) { E(" %s: proc debug file create failed!\n", __func__); goto fail_9; } #endif #ifdef HX_TP_PROC_FLASH_DUMP - himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); - if(himax_proc_flash_dump_file == NULL) - { + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, + (S_IWUSR | S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); + + if (himax_proc_flash_dump_file == NULL) { E(" %s: proc flash dump file create failed!\n", __func__); goto fail_10; } #endif #ifdef HX_TP_PROC_SELF_TEST - himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); - if(himax_proc_self_test_file == NULL) - { + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, + (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); + + if (himax_proc_self_test_file == NULL) { E(" %s: proc self_test file create failed!\n", __func__); goto fail_11; } #endif #ifdef HX_HIGH_SENSE - himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops); - if(himax_proc_HSEN_file == NULL) - { + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_HSEN_ops); + + if (himax_proc_HSEN_file == NULL) { E(" %s: proc HSEN file create failed!\n", __func__); goto fail_12; } #endif #ifdef HX_SMART_WAKEUP - himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops); - if(himax_proc_SMWP_file == NULL) - { + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_SMWP_ops); + + if (himax_proc_SMWP_file == NULL) { E(" %s: proc SMWP file create failed!\n", __func__); goto fail_13; } - himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops); - if(himax_proc_GESTURE_file == NULL) - { + + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_Gesture_ops); + + if (himax_proc_GESTURE_file == NULL) { E(" %s: proc GESTURE file create failed!\n", __func__); goto fail_14; } #endif #ifdef HX_TP_PROC_SENSE_ON_OFF - himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops); - if(himax_proc_SENSE_ON_OFF_file == NULL) - { + himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, + (S_IWUSR | S_IRUGO | S_IWUGO), + himax_touch_proc_dir, &himax_proc_sense_on_off_ops); + + if (himax_proc_SENSE_ON_OFF_file == NULL) { E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); goto fail_15; } #endif - return 0 ; + return 0; #ifdef HX_TP_PROC_SENSE_ON_OFF - fail_15: +fail_15: #endif #ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - fail_14: - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); - fail_13: + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); +fail_14: + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); +fail_13: #endif #ifdef HX_HIGH_SENSE - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); - fail_12: + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); +fail_12: #endif #ifdef HX_TP_PROC_SELF_TEST - remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); - fail_11: + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +fail_11: #endif #ifdef HX_TP_PROC_FLASH_DUMP - remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); - fail_10: + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +fail_10: #endif #ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); - fail_9: + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); +fail_9: #endif #ifdef HX_TP_PROC_REGISTER - remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); - fail_8: + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +fail_8: #endif #ifdef HX_TP_PROC_DIAG - remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); - fail_7: - remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir ); - fail_7_1: + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +fail_7: + remove_proc_entry(HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir); +fail_7_1: #endif #ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); - fail_6: + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); +fail_6: #endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); +fail_5: remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); +fail_4: remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); +fail_3: remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); +fail_2: remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); +fail_1: remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); return -ENOMEM; } void himax_touch_proc_deinit(void) { #ifdef HX_TP_PROC_SENSE_ON_OFF - remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir); #endif #ifdef HX_SMART_WAKEUP - remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir); #endif #ifdef HX_DOT_VIEW - remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_SELF_TEST remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); @@ -2308,7 +2184,7 @@ void himax_touch_proc_deinit(void) remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_DEBUG - remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_REGISTER remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); @@ -2317,13 +2193,13 @@ void himax_touch_proc_deinit(void) remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); #endif #ifdef HX_TP_PROC_RESET - remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); + remove_proc_entry(HIMAX_PROC_RESET_FILE, himax_touch_proc_dir); #endif - remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); - remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + remove_proc_entry(HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir); + remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL); } #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h index 91a7ae2eb7abad857bcc254389074a39239fb4f1..7a24a170eaca95a320c37c3db65431f88b5d75b7 100644 --- a/drivers/input/touchscreen/hxchipset/himax_debug.h +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -17,7 +17,7 @@ #include "himax_common.h" #if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) - #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" #define HIMAX_PROC_VENDOR_FILE "vendor" #define HIMAX_PROC_ATTN_FILE "attn" @@ -33,60 +33,76 @@ uint8_t HX_PROC_SEND_FLAG; -extern int himax_touch_proc_init(void); -extern void himax_touch_proc_deinit(void); -bool getFlashDumpGoing(void); + extern int himax_touch_proc_init(void); + extern void himax_touch_proc_deinit(void); + bool getFlashDumpGoing(void); + + extern struct himax_ic_data *ic_data; + extern struct himax_ts_data *private_ts; + extern unsigned char IC_TYPE; + extern unsigned char IC_CHECKSUM; + +#ifdef QCT + extern irqreturn_t himax_ts_thread(int irq, void *ptr); +#endif +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); +#else + extern void tpd_eint_interrupt_handler(void); +#endif +#endif #ifdef HX_TP_PROC_REGISTER #define HIMAX_PROC_REGISTER_FILE "register" - struct proc_dir_entry *himax_proc_register_file; + struct proc_dir_entry *himax_proc_register_file = NULL; uint8_t register_command[4]; #endif #ifdef HX_TP_PROC_DIAG #define HIMAX_PROC_DIAG_FILE "diag" - struct proc_dir_entry *himax_proc_diag_file; + struct proc_dir_entry *himax_proc_diag_file = NULL; #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" - struct proc_dir_entry *himax_proc_diag_arrange_file; + struct proc_dir_entry *himax_proc_diag_arrange_file = NULL; #ifdef HX_TP_PROC_2T2R static bool Is_2T2R; static uint8_t x_channel_2; static uint8_t y_channel_2; static uint8_t *diag_mutual_2; - + int16_t *getMutualBuffer_2(void); - uint8_t getXChannel_2(void); - uint8_t getYChannel_2(void); - - void setMutualBuffer_2(void); - void setXChannel_2(uint8_t x); - void setYChannel_2(uint8_t y); + uint8_t getXChannel_2(void); + uint8_t getYChannel_2(void); + + void setMutualBuffer_2(void); + void setXChannel_2(uint8_t x); + void setYChannel_2(uint8_t y); #endif - uint8_t x_channel; - uint8_t y_channel; - int16_t *diag_mutual; - int16_t *diag_mutual_new; - int16_t *diag_mutual_old; - uint8_t diag_max_cnt; - - int diag_command; - uint8_t diag_coor[128];// = {0xFF}; + uint8_t x_channel = 0; + uint8_t y_channel = 0; + int16_t *diag_mutual = NULL; + int16_t *diag_mutual_new = NULL; + int16_t *diag_mutual_old = NULL; + uint8_t diag_max_cnt = 0; + + int diag_command = 0; + uint8_t diag_coor[128];/* = {0xFF};*/ int16_t diag_self[100] = {0}; int16_t *getMutualBuffer(void); int16_t *getMutualNewBuffer(void); int16_t *getMutualOldBuffer(void); int16_t *getSelfBuffer(void); - uint8_t getDiagCommand(void); - uint8_t getXChannel(void); - uint8_t getYChannel(void); - - void setMutualBuffer(void); - void setMutualNewBuffer(void); - void setMutualOldBuffer(void); - void setXChannel(uint8_t x); - void setYChannel(uint8_t y); + uint8_t getDiagCommand(void); + uint8_t getXChannel(void); + uint8_t getYChannel(void); + + void setMutualBuffer(void); + void setMutualNewBuffer(void); + void setMutualOldBuffer(void); + void setXChannel(uint8_t x); + void setYChannel(uint8_t y); uint8_t coordinate_dump_enable = 0; struct file *coordinate_fn; #endif @@ -106,24 +122,24 @@ bool getFlashDumpGoing(void); struct proc_dir_entry *himax_proc_flash_dump_file = NULL; static int Flash_Size = 131072; - static uint8_t *flash_buffer = NULL; - static uint8_t flash_command = 0; - static uint8_t flash_read_step = 0; - static uint8_t flash_progress = 0; - static uint8_t flash_dump_complete = 0; - static uint8_t flash_dump_fail = 0; - static uint8_t sys_operation = 0; - static uint8_t flash_dump_sector = 0; - static uint8_t flash_dump_page = 0; - static bool flash_dump_going = false; + static uint8_t *flash_buffer; + static uint8_t flash_command; + static uint8_t flash_read_step; + static uint8_t flash_progress; + static uint8_t flash_dump_complete; + static uint8_t flash_dump_fail; + static uint8_t sys_operation; + static uint8_t flash_dump_sector; + static uint8_t flash_dump_page; + static bool flash_dump_going; static uint8_t getFlashCommand(void); static uint8_t getFlashDumpComplete(void); static uint8_t getFlashDumpFail(void); static uint8_t getFlashDumpProgress(void); static uint8_t getFlashReadStep(void); - //static uint8_t getFlashDumpSector(void); - //static uint8_t getFlashDumpPage(void); + /*static uint8_t getFlashDumpSector(void);*/ + /*static uint8_t getFlashDumpPage(void);*/ void setFlashBuffer(void); uint8_t getSysOperation(void); @@ -150,8 +166,8 @@ bool getFlashDumpGoing(void); #ifdef HX_TP_PROC_RESET #define HIMAX_PROC_RESET_FILE "reset" -extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); -struct proc_dir_entry *himax_proc_reset_file = NULL; +extern void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); +struct proc_dir_entry *himax_proc_reset_file; #endif #ifdef HX_HIGH_SENSE @@ -165,16 +181,16 @@ struct proc_dir_entry *himax_proc_reset_file = NULL; #endif #ifdef HX_RST_PIN_FUNC - void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); + void himax_HW_reset(uint8_t loadconfig, uint8_t int_off); #endif #ifdef HX_SMART_WAKEUP #define HIMAX_PROC_SMWP_FILE "SMWP" -struct proc_dir_entry *himax_proc_SMWP_file = NULL; +struct proc_dir_entry *himax_proc_SMWP_file; #define HIMAX_PROC_GESTURE_FILE "GESTURE" -struct proc_dir_entry *himax_proc_GESTURE_file = NULL; -uint8_t HX_SMWP_EN = 0; -//extern bool FAKE_POWER_KEY_SEND; +struct proc_dir_entry *himax_proc_GESTURE_file; +uint8_t HX_SMWP_EN; +/*extern bool FAKE_POWER_KEY_SEND;*/ #endif #endif diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c index 6ad8dc03149b4b339504ee87e4abeba67dc7d28b..e2934c2d2396086c4727c81d0e86872490ef22fc 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic.c +++ b/drivers/input/touchscreen/hxchipset/himax_ic.c @@ -15,45 +15,31 @@ #include "himax_ic.h" -static unsigned char i_TP_CRC_FW_128K[]= -{ - #include "HX_CRC_128.i" -}; -static unsigned char i_TP_CRC_FW_64K[]= -{ - #include "HX_CRC_64.i" -}; -static unsigned char i_TP_CRC_FW_124K[]= -{ - #include "HX_CRC_124.i" -}; -static unsigned char i_TP_CRC_FW_60K[]= -{ - #include "HX_CRC_60.i" -}; - - -unsigned long FW_VER_MAJ_FLASH_ADDR; -unsigned long FW_VER_MAJ_FLASH_LENG; -unsigned long FW_VER_MIN_FLASH_ADDR; -unsigned long FW_VER_MIN_FLASH_LENG; -unsigned long CFG_VER_MAJ_FLASH_ADDR; -unsigned long CFG_VER_MAJ_FLASH_LENG; -unsigned long CFG_VER_MIN_FLASH_ADDR; -unsigned long CFG_VER_MIN_FLASH_LENG; - -unsigned char IC_TYPE = 0; -unsigned char IC_CHECKSUM = 0; - -extern struct himax_ic_data* ic_data; - -int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail +const struct firmware *i_TP_CRC_FW_128K; +const struct firmware *i_TP_CRC_FW_64K; +const struct firmware *i_TP_CRC_FW_124K; +const struct firmware *i_TP_CRC_FW_60K; + +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_LENG; + +unsigned char IC_TYPE; +unsigned char IC_CHECKSUM; + + /*0:Running, 1:Stop, 2:I2C Fail*/ +int himax_hand_shaking(struct i2c_client *client) { int ret, result; uint8_t hw_reset_check[1]; uint8_t hw_reset_check_2[1]; uint8_t buf0[2]; - uint8_t IC_STATUS_CHECK = 0xAA; + uint8_t IC_STATUS_CHECK = 0xAA; memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); @@ -67,45 +53,50 @@ int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C IC_STATUS_CHECK = 0xAA; } - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:write 0xF2 failed line: %d \n",__LINE__); + E("[Himax]:write 0xF2 failed line: %d\n", __LINE__); goto work_func_send_i2c_msg_fail; } - msleep(50); - + msleep(50); + buf0[0] = 0xF2; buf0[1] = 0x00; - ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + ret = i2c_himax_master_write(client, + buf0, 2, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:write 0x92 failed line: %d \n",__LINE__); + E("[Himax]:write 0x92 failed line: %d\n", __LINE__); goto work_func_send_i2c_msg_fail; } - usleep_range(2000, 4000); - - ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); + usleep_range(1999, 2000); + + ret = i2c_himax_read(client, 0xD1, + hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", __LINE__); goto work_func_send_i2c_msg_fail; } - - if ((IC_STATUS_CHECK != hw_reset_check[0])) { - usleep_range(2000, 4000); - ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); + + if (IC_STATUS_CHECK != hw_reset_check[0]) { + usleep_range(1999, 2000); + ret = i2c_himax_read(client, 0xD1, + hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); if (ret < 0) { - E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + E("[Himax]:i2c_himax_read 0xD1 failed line: %d\n", + __LINE__); goto work_func_send_i2c_msg_fail; } - - if (hw_reset_check[0] == hw_reset_check_2[0]) { - result = 1; - } else { - result = 0; - } + + if (hw_reset_check[0] == hw_reset_check_2[0]) + result = 1; + else + result = 0; + } else { - result = 0; + result = 0; } - + return result; work_func_send_i2c_msg_fail: @@ -117,66 +108,71 @@ void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) uint8_t tmp_addr[4]; uint8_t tmp_data[4]; - if(diag_command != 0) + if (diag_command != 0) diag_command = diag_command + 5; - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = diag_command; himax_flash_write_burst(client, tmp_addr, tmp_data); } -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) { - //struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); - -// uint8_t sector = 0; -// uint8_t page = 0; + /*struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, flash_work);*/ + /*uint8_t sector = 0;*/ + /*uint8_t page = 0;*/ uint8_t tmp_addr[4]; uint8_t tmp_data[4]; uint8_t out_buffer[20]; - uint8_t in_buffer[260] = {0}; + uint8_t in_buffer[260]; int page_prog_start = 0; int i = 0; himax_sense_off(client); himax_burst_enable(client, 0); /*=============Dump Flash Start=============*/ - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*=====================================*/ + /* SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780*/ + /*=====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + for (page_prog_start = 0 ; page_prog_start < Flash_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); @@ -184,43 +180,46 @@ void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_comman } himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== + /*===================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + =====================================*/ out_buffer[0] = 0x2C; out_buffer[1] = 0x00; out_buffer[2] = 0x00; out_buffer[3] = 0x80; - i2c_himax_write(client, 0x00 ,out_buffer, 4, 3); + i2c_himax_write(client, 0x00, out_buffer, 4, 3); - //================================== - // Read access : 0x0C ==> 0x00 - //================================== + /*===================================== + Read access : 0x0C ==> 0x00 + =====================================*/ out_buffer[0] = 0x00; - i2c_himax_write(client, 0x0C ,out_buffer, 1, 3); + i2c_himax_write(client, 0x0C, out_buffer, 1, 3); - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[i + page_prog_start] = in_buffer[i]; + /*===================================== + Read 128 bytes two times + =====================================*/ + i2c_himax_read(client, 0x08, in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[i + page_prog_start] + = in_buffer[i]; - i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); - for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; + i2c_himax_read(client, 0x08 , in_buffer, 128, 3); + for (i = 0 ; i < 128 ; i++) + flash_buffer[(i + 128) + page_prog_start] + = in_buffer[i]; I("%s:Verify Progress: %x\n", __func__, page_prog_start); } /*=============Dump Flash End=============*/ - //msleep(100); - /* + /*//msleep(100); for( i=0 ; i<8 ;i++) { for(j=0 ; j<64 ; j++) @@ -239,7 +238,7 @@ int himax_chip_self_test(struct i2c_client *client) { uint8_t tmp_addr[4]; uint8_t tmp_data[128]; - int pf_value=0x00; + int pf_value = 0x00; uint8_t test_result_id = 0; int j; @@ -249,19 +248,24 @@ int himax_chip_self_test(struct i2c_client *client) himax_interface_on(client); himax_sense_off(client); - //Set criteria + /*Set criteria*/ himax_burst_enable(client, 1); - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; - tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99; - - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8); - - //start selftest - // 0x9008_805C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; + tmp_data[3] = 0x14; tmp_data[2] = 0xC8; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_data[7] = 0x13; tmp_data[6] = 0x60; + tmp_data[5] = 0x0A; tmp_data[4] = 0x99; + + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 8); + + /*start selftest*/ + /* 0x9008_805C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; himax_flash_write_burst(client, tmp_addr, tmp_data); himax_sense_on(client, 1); @@ -271,19 +275,21 @@ int himax_chip_self_test(struct i2c_client *client) himax_sense_off(client); msleep(20); - //===================================== - // Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; + /*===================================== + Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; himax_register_read(client, tmp_addr, 1, tmp_data); test_result_id = tmp_data[0]; - I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__ - ,test_result_id,tmp_data[0]); + I("%s: check test result, test_result_id=%x, test_result=%x\n", + __func__ , test_result_id, tmp_data[0]); - if (test_result_id==0xF) { + if (test_result_id == 0xF) { I("[Himax]: self-test pass\n"); pf_value = 0x1; } else { @@ -292,22 +298,28 @@ int himax_chip_self_test(struct i2c_client *client) } himax_burst_enable(client, 1); - for (j = 0;j < 10; j++){ - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; + for (j = 0 ; j < 10 ; j++) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; himax_register_read(client, tmp_addr, 1, tmp_data); I("[Himax]: 9006000C = %d\n", tmp_data[0]); - if (tmp_data[0] != 0){ - tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - } - i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES); - }else{ + if (tmp_data[0] != 0) { + tmp_data[3] = 0x90; tmp_data[2] = 0x06; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + i2c_himax_read(client, 0x08, + tmp_data, 124, HIMAX_I2C_RETRY_TIMES); + } else { break; } } @@ -324,15 +336,18 @@ void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) uint8_t tmp_data[4]; himax_burst_enable(client, 0); - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; himax_flash_write_burst(client, tmp_addr, tmp_data); } -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data) +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data) { uint8_t tmp_addr[4]; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; himax_register_read(client, tmp_addr, 1, tmp_data); } @@ -341,206 +356,232 @@ void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) uint8_t tmp_addr[4]; uint8_t tmp_data[4]; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; himax_flash_write_burst(client, tmp_addr, tmp_data); } -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data) +void himax_get_SMWP_enable(struct i2c_client *client, +uint8_t *tmp_data) { uint8_t tmp_addr[4]; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; himax_register_read(client, tmp_addr, 1, tmp_data); } int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) { uint8_t tmp_data[4]; + int err = -1; tmp_data[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + + if (i2c_himax_write(client, 0x13, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); - return -EBUSY; + return err; } - + tmp_data[0] = (0x10 | auto_add_4_byte); - if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x0D, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); - return -EBUSY; + return err; } return 0; } -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data) +void himax_register_read(struct i2c_client *client, +uint8_t *read_addr, int read_length, uint8_t *read_data) { uint8_t tmp_data[4]; int i = 0; int address = 0; - if(read_length>256) - { + if (read_length > 256) { E("%s: read len over 256!\n", __func__); return; } if (read_length > 1) himax_burst_enable(client, 1); else - himax_burst_enable(client, 0); - address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; + himax_burst_enable(client, 0); + + address = (read_addr[3] << 24) + + (read_addr[2] << 16) + + (read_addr[1] << 8) + + read_addr[0]; + i = address; - tmp_data[0] = (uint8_t)i; - tmp_data[1] = (uint8_t)(i >> 8); - tmp_data[2] = (uint8_t)(i >> 16); - tmp_data[3] = (uint8_t)(i >> 24); - if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - tmp_data[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } - - if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + if (i2c_himax_write(client, 0x00, + tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (i2c_himax_read(client, 0x08, + read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } if (read_length > 1) himax_burst_enable(client, 0); } -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data) +void himax_flash_read(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *read_data) { - uint8_t tmpbyte[2]; - - if ( i2c_himax_write(client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + uint8_t tmpbyte[2]; + + if (i2c_himax_write(client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - tmpbyte[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + tmpbyte[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x08, + &read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x09, + &read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x0A, + &read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x0B, + &read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x18, + &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; - }// No bus request + } /* No bus request*/ - if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x0F, + &tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; - }// idle state + } /* idle state*/ } -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data) +void himax_flash_write_burst(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data) { - uint8_t data_byte[8]; + uint8_t data_byte[8]; int i = 0, j = 0; - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < 8; j++) - { - data_byte[j] = write_data[j-4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; - } + for (i = 0 ; i < 4; i++) + data_byte[i] = reg_byte[i]; + + for (j = 4 ; j < 8; j++) + data_byte[j] = write_data[j-4]; + + if (i2c_himax_write(client, 0x00, + data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } } -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length) +int himax_flash_write_burst_length(struct i2c_client *client, +uint8_t *reg_byte, uint8_t *write_data, int length) { - uint8_t data_byte[256]; - int i = 0, j = 0; + uint8_t data_byte[256]; + int i = 0, j = 0, err = -1; - for (i = 0; i < 4; i++) - { - data_byte[i] = reg_byte[i]; - } - for (j = 4; j < length + 4; j++) - { - data_byte[j] = write_data[j - 4]; - } - - if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return -EBUSY; - } + for (i = 0 ; i < 4 ; i++) + data_byte[i] = reg_byte[i]; - return 0; + for (j = 4 ; j < length + 4 ; j++) + data_byte[j] = write_data[j - 4]; + + if (i2c_himax_write(client, 0x00, + data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return err; + } + return 0; } -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data) +int himax_register_write(struct i2c_client *client, +uint8_t *write_addr, int write_length, uint8_t *write_data) { - int i =0, address = 0; - int ret = 0; + int i = 0, address = 0; + int ret = 0, err = -1; - address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0]; + address = (write_addr[3] << 24) + + (write_addr[2] << 16) + + (write_addr[1] << 8) + + write_addr[0]; - for (i = address; i < address + write_length * 4; i = i + 4) - { - if (write_length > 1) - { + for (i = address ; i < address + write_length * 4; + i = i + 4) { + if (write_length > 1) { ret = himax_burst_enable(client, 1); - if(ret) - return ret; - } - else - { + if (ret) + return err; + } else { ret = himax_burst_enable(client, 0); - if(ret) - return ret; + if (ret) + return err; } - ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4); - if(ret < 0) - return ret; + ret = himax_flash_write_burst_length(client, + write_addr, write_data, write_length * 4); + if (ret < 0) + return err; } return 0; @@ -550,50 +591,62 @@ void himax_sense_off(struct i2c_client *client) { uint8_t wdt_off = 0x00; uint8_t tmp_addr[4]; - uint8_t tmp_data[5]; + uint8_t tmp_data[5]; himax_burst_enable(client, 0); - while(wdt_off == 0x00) - { - // 0x9000_800C ==> 0x0000_AC53 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53; + while (wdt_off == 0x00) { + /* 0x9000_800C ==> 0x0000_AC53*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0xAC; tmp_data[0] = 0x53; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53 - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + /*=====================================*/ + /* Read Watch Dog disable password : + 0x9000_800C ==> 0x0000_AC53 */ + /*=====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; himax_register_read(client, tmp_addr, 1, tmp_data); - - //Check WDT - if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) + + /*Check WDT*/ + if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC + && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) wdt_off = 0x01; else wdt_off = 0x00; } - // VCOM //0x9008_806C ==> 0x0000_0001 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + /* VCOM //0x9008_806C ==> 0x0000_0001*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; himax_flash_write_burst(client, tmp_addr, tmp_data); msleep(20); - // 0x9000_0010 ==> 0x0000_00DA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA; + /* 0x9000_0010 ==> 0x0000_00DA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xDA; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + /*===================================== + Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + I("%s: CPU clock off password data[0]=%x", + __func__, tmp_data[0]); + I(" data[1]=%x data[2]=%x data[3]=%x\n", + tmp_data[1], tmp_data[2], tmp_data[3]); } @@ -602,11 +655,12 @@ void himax_interface_on(struct i2c_client *client) uint8_t tmp_addr[4]; uint8_t tmp_data[5]; - //=========================================== - // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 - //=========================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail + /*===================================== + Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + himax_flash_read(client, tmp_addr, tmp_data); /*avoid RD/WR fail*/ } bool wait_wip(struct i2c_client *client, int Timing) @@ -614,55 +668,64 @@ bool wait_wip(struct i2c_client *client, int Timing) uint8_t tmp_addr[4]; uint8_t tmp_data[4]; uint8_t in_buffer[10]; - //uint8_t out_buffer[20]; + /*uint8_t out_buffer[20];*/ int retry_cnt = 0; - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); in_buffer[0] = 0x01; - do - { - //===================================== - // SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03; + do { + /*===================================== + SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x42; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x03; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // SPI Command : 0x8000_0024 ==> 0x0000_0005 - // read 0x8000_002C for 0x01, means wait success - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05; + /*===================================== + SPI Command : 0x8000_0024 ==> 0x0000_0005 + read 0x8000_002C for 0x01, means wait success + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x05; himax_flash_write_burst(client, tmp_addr, tmp_data); - in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF; - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + in_buffer[0] = in_buffer[1] = + in_buffer[2] = in_buffer[3] = 0xFF; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; himax_register_read(client, tmp_addr, 1, in_buffer); - + if ((in_buffer[0] & 0x01) == 0x00) return true; retry_cnt++; - - if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00) - I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, - retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]); - if (retry_cnt > 100) - { + if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 + || in_buffer[2] != 0x00 || in_buffer[3] != 0x00){ + I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, ", + __func__, retry_cnt, in_buffer[0]); + I("buffer[1]=%d, buffer[2]=%d, buffer[3]=%d\n", + in_buffer[1], in_buffer[2], in_buffer[3]); + } + if (retry_cnt > 100) { E("%s: Wait wip error!\n", __func__); - return false; - } + return false; + } msleep(Timing); - }while ((in_buffer[0] & 0x01) == 0x01); + } while ((in_buffer[0] & 0x01) == 0x01); return true; } @@ -673,74 +736,93 @@ void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) himax_interface_on(client); himax_burst_enable(client, 0); - //CPU reset - // 0x9000_0014 ==> 0x0000_00CA - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA; + /*CPU reset*/ + /* 0x9000_0014 ==> 0x0000_00CA*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xCA; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + /*===================================== + Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); - // 0x9000_0014 ==> 0x0000_0000 - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /* 0x9000_0014 ==> 0x0000_0000*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 - //===================================== - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + /*===================================== + Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 + =====================================*/ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; himax_register_read(client, tmp_addr, 1, tmp_data); - I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ - ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); - - //===================================== - // Reset TCON - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - usleep_range(10000, 20000); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - if (FlashMode == 0x00) //SRAM - { - //===================================== - // Re-map - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x ", + __func__, tmp_data[0], tmp_data[1]); + I("data[2]=%x data[3]=%x\n", + tmp_data[2], tmp_data[3]); + + /*===================================== + Reset TCON + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + usleep_range(9999, 10000); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; + tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + if (FlashMode == 0x00) { /*SRAM*/ + /*===================================== + Re-map + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xF1; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); I("%s:83100_Chip_Re-map ON\n", __func__); - } - else - { - //===================================== - // Re-map off - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + } else { + /*===================================== + Re-map off + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); I("%s:83100_Chip_Re-map OFF\n", __func__); } - //===================================== - // CPU clock on - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + /*===================================== + CPU clock on + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 4); } @@ -751,36 +833,45 @@ void himax_chip_erase(struct i2c_client *client) himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Chip Erase - // Erase Command : 0x8000_0024 ==> 0x0000_00C7 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7; + /*===================================== + Chip Erase + Erase Command : 0x8000_0024 ==> 0x0000_00C7 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0xC7; himax_flash_write_burst(client, tmp_addr, tmp_data); - + msleep(2000); - + if (!wait_wip(client, 100)) E("%s:83100_Chip_Erase Fail\n", __func__); @@ -793,53 +884,64 @@ bool himax_block_erase(struct i2c_client *client) himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; himax_flash_write_burst(client, tmp_addr, tmp_data); - //===================================== - // Block Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0052 //BE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /*===================================== + Block Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0052 //BE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x52; himax_flash_write_burst(client, tmp_addr, tmp_data); msleep(1000); - if (!wait_wip(client, 100)) - { + if (!wait_wip(client, 100)) { E("%s:83100_Erase Fail\n", __func__); return false; - } - else - { + } else { return true; } @@ -853,97 +955,110 @@ bool himax_sector_erase(struct i2c_client *client, int start_addr) himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000) - { - //===================================== - // Chip Erase - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; - himax_flash_write_burst(client, tmp_addr, tmp_data); - - //===================================== - // Sector Erase - // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr - // 0x8000_0020 ==> 0x6700_0000 //control - // 0x8000_0024 ==> 0x0000_0020 //SE - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - himax_flash_write_burst(client, tmp_addr, tmp_data); + for (page_prog_start = start_addr; + page_prog_start < start_addr + 0x0F000; + page_prog_start = page_prog_start + 0x1000) { + /*===================================== + Chip Erase + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst(client, tmp_addr, tmp_data); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20; - himax_flash_write_burst(client, tmp_addr, tmp_data); + /*===================================== + Sector Erase + Erase Command : + 0x8000_0028 ==> 0x0000_0000 //SPI addr + 0x8000_0020 ==> 0x6700_0000 //control + 0x8000_0024 ==> 0x0000_0020 //SE + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); - msleep(200); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x20; + himax_flash_write_burst(client, tmp_addr, tmp_data); - if (!wait_wip(client, 100)) - { - E("%s:83100_Erase Fail\n", __func__); - return false; - } - } - return true; + msleep(200); + + if (!wait_wip(client, 100)) { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + } + return true; } void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) { int i = 0; uint8_t tmp_addr[4]; - uint8_t tmp_data[128]; - int FW_length = 0x4000; // 0x4000 = 16K bin file - - //himax_sense_off(client); + uint8_t tmp_data[64]; + int FW_length = 0x4000; /* 0x4000 = 16K bin file */ + + /*himax_sense_off(client);*/ - for (i = 0; i < FW_length; i = i + 128) - { + for (i = 0; i < FW_length; i = i + 64) { himax_burst_enable(client, 1); - if (i < 0x100) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = 0x00; + if (i < 0x100) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - tmp_addr[3] = 0x08; - tmp_addr[2] = 0x00; - tmp_addr[1] = (i >> 8); + } else if (i >= 0x100 && i < 0x10000) { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = (i >> 8); tmp_addr[0] = i; } - memcpy(&tmp_data[0], &FW_content[i], 128); - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128); + memcpy(&tmp_data[0], &FW_content[i], 64); + himax_flash_write_burst_length(client, tmp_addr, tmp_data, 64); } @@ -951,182 +1066,197 @@ void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) E("%s:83100_Sram_Write Fail\n", __func__); } -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size) +bool himax_sram_verify(struct i2c_client *client, +uint8_t *FW_File, int FW_Size) { int i = 0; uint8_t out_buffer[20]; uint8_t in_buffer[128]; uint8_t *get_fw_content; - get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL); - if (!get_fw_content) - return false; + get_fw_content = kzalloc(0x4000 * sizeof(uint8_t), GFP_KERNEL); - for (i = 0; i < 0x4000; i = i + 128) - { + for (i = 0 ; i < 0x4000 ; i = i + 128) { himax_burst_enable(client, 1); - //================================== - // AHB_I2C Burst Read - //================================== - if (i < 0x100) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = 0x00; + /*===================================== + AHB_I2C Burst Read + =====================================*/ + if (i < 0x100) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = 0x00; out_buffer[0] = i; - } - else if (i >= 0x100 && i < 0x10000) - { - out_buffer[3] = 0x08; - out_buffer[2] = 0x00; - out_buffer[1] = (i >> 8); + } else if (i >= 0x100 && i < 0x10000) { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = (i >> 8); out_buffer[0] = i; } - if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, out_buffer, + 4, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return false; } - out_buffer[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + out_buffer[0] = 0x00; + if (i2c_himax_write(client, 0x0C, out_buffer, + 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return false; } - if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_read(client, 0x08, in_buffer, + 128, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return false; } memcpy(&get_fw_content[i], &in_buffer[0], 128); } - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != get_fw_content[i]) - { - E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]); - return false; - } + for (i = 0 ; i < FW_Size ; i++) { + if (FW_File[i] != get_fw_content[i]) { + E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", + __func__, i, get_fw_content[i], FW_File[i]); + return false; } + } kfree(get_fw_content); return true; } -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size) +void himax_flash_programming(struct i2c_client *client, +uint8_t *FW_content, int FW_Size) { int page_prog_start = 0; int program_length = 48; int i = 0, j = 0, k = 0; uint8_t tmp_addr[4]; uint8_t tmp_data[4]; - uint8_t buring_data[256]; // Read for flash data, 128K - // 4 bytes for 0x80002C padding + /* // Read for flash data, 128K //4 bytes for 0x80002C padding */ + uint8_t buring_data[256]; - //himax_interface_on(client); + /*himax_interface_on(client);*/ himax_burst_enable(client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_flash_write_burst(client, tmp_addr, tmp_data); - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //msleep(5); - //===================================== - // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 - // 2. 0x8000_0024 ==> 0x0000_0006 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + for (page_prog_start = 0 ; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*msleep(5);*/ + /*===================================== + Write Enable : + 1. 0x8000_0020 ==> 0x4700_0000 + 2. 0x8000_0024 ==> 0x0000_0006 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x06; himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================= - // SPI Transfer Control - // Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00; - // data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000 - // Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64 + /*===================================== + SPI Transfer Control + Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 + Set read start address : 0x8000_0028 ==> 0x0000_0000 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x61; tmp_data[2] = 0x0F; + tmp_data[1] = 0xF0; tmp_data[0] = 0x00; + /*data bytes should be 0x6100_0000 + + ((word_number)*4-1)*4096 = 0x6100_0000 + + 0xFF000 = 0x610F_F000 + Programmable size = 1 page = 256 bytes, + word_number = 256 byte / 4 = 64*/ himax_flash_write_burst(client, tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000 + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + /* tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + // Flash start address 1st : 0x0000_0000 */ - if (page_prog_start < 0x100) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = 0x00; + if (page_prog_start < 0x100) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { - tmp_data[3] = 0x00; - tmp_data[2] = 0x00; - tmp_data[1] = (uint8_t)(page_prog_start >> 8); + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { - tmp_data[3] = 0x00; - tmp_data[2] = (uint8_t)(page_prog_start >> 16); - tmp_data[1] = (uint8_t)(page_prog_start >> 8); + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; } - - himax_flash_write_burst(client, tmp_addr, tmp_data); + himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================= - // Send 16 bytes data : 0x8000_002C ==> 16 bytes data - //================================= + /*===================================== + Send 16 bytes data : 0x8000_002C ==> 16 bytes data + =====================================*/ buring_data[0] = 0x2C; buring_data[1] = 0x00; buring_data[2] = 0x00; buring_data[3] = 0x80; - - for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++) /// <------ bin file - { + + for (i = /*0*/page_prog_start, j = 0; + i < 16 + page_prog_start/**/; + i++, j++) { /* <------ bin file*/ + buring_data[j + 4] = FW_content[i]; } - - if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, buring_data, + 20, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - //================================= - // Write command : 0x8000_0024 ==> 0x0000_0002 - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02; + /*===================================== + Write command : 0x8000_0024 ==> 0x0000_0002 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x02; himax_flash_write_burst(client, tmp_addr, tmp_data); - //================================= - // Send 240 bytes data : 0x8000_002C ==> 240 bytes data - //================================= + /*===================================== + Send 240 bytes data : 0x8000_002C ==> 240 bytes data + =====================================*/ - for (j = 0; j < 5; j++) - { - for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++) /// <------ bin file - { - buring_data[k+4] = FW_content[i];//(byte)i; + for (j = 0; j < 5; j++) { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; + i < (page_prog_start + 16 + (j * 48)) + program_length; + i++, k++) { /*<------ bin file*/ + buring_data[k+4] = FW_content[i];/*(byte)i;*/ } - if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, buring_data, + program_length + 4, + HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } @@ -1145,52 +1275,61 @@ bool himax_check_chip_version(struct i2c_client *client) uint8_t ret_data = 0x00; int i = 0; int ret = 0; + himax_sense_off(client); - for (i = 0; i < 5; i++) - { - // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + + for (i = 0 ; i < 5 ; i++) { + /* 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) + (Lock register R/W from driver) */ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x01; ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) + if (ret) return false; - // 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000) - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /* 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000)*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; ret = himax_register_write(client, tmp_addr, 1, tmp_data); - if(ret) + if (ret) return false; - // 3. Read driver ID register RF4H 1 byte (0x8001_F401) - // Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484 - tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; + /* 3. Read driver ID register RF4H 1 byte (0x8001_F401) + // Driver register RF4H 1 byte value = 0x84H, + read back value will become 0x84848484 */ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; + tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; himax_register_read(client, tmp_addr, 1, tmp_data); ret_data = tmp_data[0]; I("%s:Read driver IC ID = %X\n", __func__, ret_data); - if (ret_data == 0x84) - { + if (ret_data == 0x84) { IC_TYPE = HX_83100_SERIES_PWON; - //himax_sense_on(client, 0x01); + /*himax_sense_on(client, 0x01);*/ ret_data = true; break; - } - else - { + + } else { ret_data = false; E("%s:Read driver ID register Fail:\n", __func__); } } - // 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver) - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + /* 4. After read finish, set DDREG_Req = 0 + (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver)*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; himax_register_write(client, tmp_addr, 1, tmp_data); - //himax_sense_on(client, 0x01); + /*himax_sense_on(client, 0x01);*/ return ret_data; } -#if 1 +/*#if 1*/ int himax_check_CRC(struct i2c_client *client, int mode) { bool burnFW_success = false; @@ -1200,52 +1339,70 @@ int himax_check_CRC(struct i2c_client *client, int mode) int CRC_value = 0; memset(tmp_data, 0x00, sizeof(tmp_data)); + if (i_TP_CRC_FW_60K == NULL) { + I("%s: i_TP_CRC_FW_60K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_64K == NULL) { + I("%s: i_TP_CRC_FW_64K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_124K == NULL) { + I("%s: i_TP_CRC_FW_124K = NULL\n", __func__); + return 0; + } else if (i_TP_CRC_FW_128K == NULL) { + I("%s: i_TP_CRC_FW_128K = NULL\n", __func__); + return 0; + } - if (1) - { - if(mode == fw_image_60k) - { - himax_sram_write(client, (i_TP_CRC_FW_60K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000); - } - else if(mode == fw_image_64k) - { - himax_sram_write(client, (i_TP_CRC_FW_64K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000); - } - else if(mode == fw_image_124k) - { - himax_sram_write(client, (i_TP_CRC_FW_124K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000); + if (1) { + if (mode == fw_image_60k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_60K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_60K->data, 0x4000); + } else if (mode == fw_image_64k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_64K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_64K->data, 0x4000); + } else if (mode == fw_image_124k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_124K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_124K->data, 0x4000); + } else if (mode == fw_image_128k) { + himax_sram_write(client, + (unsigned char *)i_TP_CRC_FW_128K->data); + burnFW_success = himax_sram_verify(client, + (unsigned char *)i_TP_CRC_FW_128K->data, 0x4000); } - else if(mode == fw_image_128k) - { - himax_sram_write(client, (i_TP_CRC_FW_128K)); - burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000); - } - if (burnFW_success) - { - I("%s: Start to do CRC FW mode=%d \n", __func__,mode); - himax_sense_on(client, 0x00); // run CRC firmware + if (burnFW_success) { + I("%s: Start to do CRC FW mode=%d\n", __func__, mode); + himax_sense_on(client, 0x00); /* run CRC firmware*/ - while(true) - { + while (true) { msleep(100); - - tmp_addr[3] = 0x90; - tmp_addr[2] = 0x08; - tmp_addr[1] = 0x80; + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; - himax_register_read(client, tmp_addr, 1, tmp_data); - - I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3], - tmp_data[2],tmp_data[1],tmp_data[0]); - - if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) - { - } - else + himax_register_read(client, + tmp_addr, 1, tmp_data); + + I("%s: CRC from firmware is %x, %x, %x, %x\n", + __func__, tmp_data[3], tmp_data[2], + tmp_data[1], tmp_data[0]); +/* + if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) { + } else break; + */ + if (!(tmp_data[3] == 0xFF + && tmp_data[2] == 0xFF + && tmp_data[1] == 0xFF + && tmp_data[0] == 0xFF)) { + break; + } } CRC_value = tmp_data[3]; @@ -1259,30 +1416,32 @@ int himax_check_CRC(struct i2c_client *client, int mode) tmp_value = tmp_data[0] << 24; CRC_value += tmp_value; - I("%s: CRC Value is %x \n", __func__, CRC_value); + I("%s: CRC Value is %x\n", __func__, CRC_value); - //Close Remapping - //===================================== - // Re-map close - //===================================== - tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; - himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); - return CRC_value; - } - else - { + /*Close Remapping*/ + /*===================================== + Re-map close + =====================================*/ + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_length(client, + tmp_addr, tmp_data, 4); + return CRC_value; + + } else { E("%s: SRAM write fail\n", __func__); return 0; - } - } - else - I("%s: NO CRC Check File \n", __func__); + } + } else + I("%s: NO CRC Check File\n", __func__); return 0; } -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode) +bool Calculate_CRC_with_AP(unsigned char *FW_content, +int CRC_from_FW, int mode) { uint8_t tmp_data[4]; int i, j; @@ -1291,42 +1450,35 @@ bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode int CRC = 0xFFFFFFFF; int PolyNomial = 0x82F63B78; int length = 0; - + if (mode == fw_image_128k) length = 0x8000; else if (mode == fw_image_124k) length = 0x7C00; else if (mode == fw_image_64k) length = 0x4000; - else //if (mode == fw_image_60k) + else /*if (mode == fw_image_60k)*/ length = 0x3C00; - for (i = 0; i < length; i++) - { - fw_data = FW_content[i * 4 ]; - - for (j = 1; j < 4; j++) - { + for (i = 0 ; i < length ; i++) { + fw_data = FW_content[i * 4]; + + for (j = 1 ; j < 4 ; j++) { fw_data_2 = FW_content[i * 4 + j]; fw_data += (fw_data_2) << (8 * j); } CRC = fw_data ^ CRC; - for (j = 0; j < 32; j++) - { + for (j = 0 ; j < 32 ; j++) { if ((CRC % 2) != 0) - { - CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; - } + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; else - { - CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF); - } + CRC = (((CRC >> 1) ^ 0x7FFFFFFF) & 0x7FFFFFFF); } } - I("%s: CRC calculate from bin file is %x \n", __func__, CRC); + I("%s: CRC calculate from bin file is %x\n", __func__, CRC); tmp_data[0] = (uint8_t)(CRC >> 24); tmp_data[1] = (uint8_t)(CRC >> 16); @@ -1334,58 +1486,129 @@ bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode tmp_data[3] = (uint8_t) CRC; CRC = tmp_data[0]; - CRC += tmp_data[1] << 8; + CRC += tmp_data[1] << 8; CRC += tmp_data[2] << 16; CRC += tmp_data[3] << 24; - I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC); - I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW); + I("%s: CRC calculate from bin file REVERSE %x\n", __func__, CRC); + I("%s: CRC calculate from FWis %x\n", __func__, CRC_from_FW); if (CRC_from_FW == CRC) return true; else return false; } -#endif +/*#endif*/ -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int himax_load_CRC_bin_file(struct i2c_client *client) +{ + int err = 0; + char *CRC_60_firmware_name = "HX_CRC_60.bin"; + char *CRC_64_firmware_name = "HX_CRC_64.bin"; + char *CRC_124_firmware_name = "HX_CRC_124.bin"; + char *CRC_128_firmware_name = "HX_CRC_128.bin"; + + I("%s,Entering\n", __func__); + if (i_TP_CRC_FW_60K == NULL) { + I("load file name = %s\n", CRC_60_firmware_name); + err = request_firmware(&i_TP_CRC_FW_60K, + CRC_60_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -1; + goto request_60k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_60K\n", __func__); + + if (i_TP_CRC_FW_64K == NULL) { + I("load file name = %s\n", CRC_64_firmware_name); + err = request_firmware(&i_TP_CRC_FW_64K, + CRC_64_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -2; + goto request_64k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_64K\n", __func__); + + if (i_TP_CRC_FW_124K == NULL) { + I("load file name = %s\n", CRC_124_firmware_name); + err = request_firmware(&i_TP_CRC_FW_124K, + CRC_124_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -3; + goto request_124k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_124K\n", __func__); + + if (i_TP_CRC_FW_128K == NULL) { + I("load file name = %s\n", CRC_128_firmware_name); + err = request_firmware(&i_TP_CRC_FW_128K, + CRC_128_firmware_name, private_ts->dev); + if (err < 0) { + E("%s,fail in line%d error code=%d\n", + __func__, __LINE__, err); + err = -4; + goto request_128k_fw_fail; + } + } else + I("%s already load i_TP_CRC_FW_128K\n", __func__); + + return err; + +request_128k_fw_fail: + release_firmware(i_TP_CRC_FW_124K); +request_124k_fw_fail: + release_firmware(i_TP_CRC_FW_64K); +request_64k_fw_fail: + release_firmware(i_TP_CRC_FW_60K); +request_60k_fw_fail: + return err; +} +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; - } + if (len != 0x10000) {/*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } himax_sense_off(client); msleep(500); himax_interface_on(client); - if (!himax_sector_erase(client, 0x00000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } + if (!himax_sector_erase(client, 0x00000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } himax_flash_programming(client, fw, 0x0F000); - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - CRC_from_FW = himax_check_CRC(client,fw_image_60k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_60k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_60k); + /*himax_sense_on(client, 0x01);*/ return burnFW_success; } -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x10000) //64k - { - E("%s: The file size is not 64K bytes\n", __func__); - return false; + if (len != 0x10000) { /*64k*/ + E("%s: The file size is not 64K bytes\n", __func__); + return false; } himax_sense_off(client); msleep(500); @@ -1393,62 +1616,58 @@ int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char himax_chip_erase(client); himax_flash_programming(client, fw, len); - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - CRC_from_FW = himax_check_CRC(client,fw_image_64k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_64k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_64k); + /*himax_sense_on(client, 0x01);*/ return burnFW_success; } -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; } himax_sense_off(client); msleep(500); himax_interface_on(client); - if (!himax_block_erase(client)) - { - E("%s:Block erase fail!Please restart the IC.\n", __func__); - return false; - } - - if (!himax_sector_erase(client, 0x10000)) - { - E("%s:Sector erase fail!Please restart the IC.\n", __func__); - return false; - } + if (!himax_block_erase(client)) { + E("%s:Block erase fail!Please restart the IC.\n", __func__); + return false; + } + if (!himax_sector_erase(client, 0x10000)) { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } himax_flash_programming(client, fw, 0x1F000); + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; - - CRC_from_FW = himax_check_CRC(client,fw_image_124k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_124k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_124k); + /*himax_sense_on(client, 0x01);*/ return burnFW_success; } -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, +unsigned char *fw, int len, bool change_iref) { int CRC_from_FW = 0; int burnFW_success = 0; - if (len != 0x20000) //128k - { - E("%s: The file size is not 128K bytes\n", __func__); - return false; + if (len != 0x20000) { /*128k*/ + E("%s: The file size is not 128K bytes\n", __func__); + return false; } himax_sense_off(client); msleep(500); @@ -1457,13 +1676,13 @@ int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned cha himax_flash_programming(client, fw, len); - //burnFW_success = himax_83100_Verify(fw, len); - //if(burnFW_success==false) - // return burnFW_success; + /*burnFW_success = himax_83100_Verify(fw, len); + if(burnFW_success==false) + return burnFW_success;*/ - CRC_from_FW = himax_check_CRC(client,fw_image_128k); - burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k); - //himax_sense_on(client, 0x01); + CRC_from_FW = himax_check_CRC(client, fw_image_128k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW, fw_image_128k); + /*himax_sense_on(client, 0x01); */ return burnFW_success; } @@ -1472,10 +1691,9 @@ void himax_touch_information(struct i2c_client *client) uint8_t cmd[4]; char data[12] = {0}; - I("%s:IC_TYPE =%d\n", __func__,IC_TYPE); + I("%s:IC_TYPE =%d\n", __func__, IC_TYPE); - if(IC_TYPE == HX_83100_SERIES_PWON) - { + if (IC_TYPE == HX_83100_SERIES_PWON) { cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; himax_register_read(client, cmd, 1, data); @@ -1486,11 +1704,11 @@ void himax_touch_information(struct i2c_client *client) cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; himax_register_read(client, cmd, 1, data); - if((data[1] & 0x04) == 0x04) { + if ((data[1] & 0x04) == 0x04) ic_data->HX_XY_REVERSE = true; - } else { + else ic_data->HX_XY_REVERSE = false; - } + ic_data->HX_Y_RES = data[3]*256; cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; himax_register_read(client, cmd, 1, data); @@ -1498,32 +1716,35 @@ void himax_touch_information(struct i2c_client *client) ic_data->HX_X_RES = data[1]*256 + data[2]; cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; himax_register_read(client, cmd, 1, data); - if((data[0] & 0x01) == 1) { + if ((data[0] & 0x01) == 1) ic_data->HX_INT_IS_EDGE = true; - } else { + else ic_data->HX_INT_IS_EDGE = false; - } - if (ic_data->HX_RX_NUM > 40) + + if (ic_data->HX_RX_NUM > 40) ic_data->HX_RX_NUM = 29; - if (ic_data->HX_TX_NUM > 20) + if (ic_data->HX_TX_NUM > 20) ic_data->HX_TX_NUM = 16; - if (ic_data->HX_MAX_PT > 10) + if (ic_data->HX_MAX_PT > 10) ic_data->HX_MAX_PT = 10; - if (ic_data->HX_Y_RES > 2000) + if (ic_data->HX_Y_RES > 2000) ic_data->HX_Y_RES = 1280; - if (ic_data->HX_X_RES > 2000) + if (ic_data->HX_X_RES > 2000) ic_data->HX_X_RES = 720; #ifdef HX_EN_MUT_BUTTON cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; himax_register_read(client, cmd, 1, data); ic_data->HX_BT_NUM = data[3]; #endif - I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); - I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES); - I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE); - } - else - { + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d\n", + __func__, ic_data->HX_RX_NUM, + ic_data->HX_TX_NUM, ic_data->HX_MAX_PT); + I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d\n", + __func__, ic_data->HX_XY_REVERSE, + ic_data->HX_Y_RES, ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d\n", + __func__, ic_data->HX_INT_IS_EDGE); + } else { ic_data->HX_RX_NUM = 0; ic_data->HX_TX_NUM = 0; ic_data->HX_BT_NUM = 0; @@ -1538,35 +1759,34 @@ void himax_touch_information(struct i2c_client *client) void himax_read_FW_ver(struct i2c_client *client) { uint8_t cmd[4]; - uint8_t data[64] = {0}; + uint8_t data[64]; - //===================================== - // Read FW version : 0x0000_E303 - //===================================== + /*===================================== + Read FW version : 0x0000_E303 + =====================================*/ cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; himax_register_read(client, cmd, 1, data); - ic_data->vendor_config_ver = data[3]<<8; + ic_data->vendor_config_ver = data[3] << 8; cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; himax_register_read(client, cmd, 1, data); ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; - I("CFG_VER : %X \n",ic_data->vendor_config_ver); + I("CFG_VER : %X\n", ic_data->vendor_config_ver); cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; himax_register_read(client, cmd, 1, data); ic_data->vendor_fw_ver = data[0]<<8 | data[1]; - I("FW_VER : %X \n",ic_data->vendor_fw_ver); - + I("FW_VER : %X\n", ic_data->vendor_fw_ver); - return; } bool himax_ic_package_check(struct i2c_client *client) { -#if 0 +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH uint8_t cmd[3]; uint8_t data[3]; @@ -1574,260 +1794,284 @@ bool himax_ic_package_check(struct i2c_client *client) memset(data, 0x00, sizeof(data)); if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) - return false ; + return false; if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) return false; - if((data[0] == 0x85 && data[1] == 0x29)) - { - IC_TYPE = HX_85XX_F_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 64901; //0xFD85 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 64902; //0xFD86 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 64928; //0xFDA0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 64940; //0xFDAC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x F\n"); - } - if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) - { - IC_TYPE = HX_85XX_E_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x E\n"); - } - else if((data[0] == 0x85 && data[1] == 0x31)) - { - IC_TYPE = HX_85XX_ES_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; //0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 - CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC - CFG_VER_MIN_FLASH_LENG = 12; - I("Himax IC package 852x ES\n"); - } - else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) { - IC_TYPE = HX_85XX_D_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 160; // 0x00A0 + if ((data[0] == 0x85 && data[1] == 0x29)) { + IC_TYPE = HX_85XX_F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 64901; /*0xFD85*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 64902; /*0xFD86*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 64928; /*0xFDA0*/ CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 172; // 0x00AC + CFG_VER_MIN_FLASH_ADDR = 64940; /*0xFDAC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x F\n"); + } + if ((data[0] == 0x85 && data[1] == 0x30) + || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) { + IC_TYPE = HX_85XX_E_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x E\n"); + } else if ((data[0] == 0x85 && data[1] == 0x31)) { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /*0x00AC*/ + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x ES\n"); + } else if ((data[0] == 0x85 && data[1] == 0x28) + || (cmd[0] == 0x04 && cmd[1] == 0x85 + && (cmd[2] == 0x26 || cmd[2] == 0x27 + || cmd[2] == 0x28))) { + IC_TYPE = HX_85XX_D_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; /*0x00A0*/ + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; /* 0x00AC*/ CFG_VER_MIN_FLASH_LENG = 12; I("Himax IC package 852x D\n"); - } else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 && - (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) { - IC_TYPE = HX_85XX_C_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 135; // 0x0087 + } else if ((data[0] == 0x85 && data[1] == 0x23) || + (cmd[0] == 0x03 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || + cmd[2] == 0x28 || cmd[2] == 0x29))) { + IC_TYPE = HX_85XX_C_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; /*0x0086*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 135; /*0x0087*/ CFG_VER_MAJ_FLASH_LENG = 12; - CFG_VER_MIN_FLASH_ADDR = 147; // 0x0093 + CFG_VER_MIN_FLASH_ADDR = 147; /*0x0093*/ CFG_VER_MIN_FLASH_LENG = 12; I("Himax IC package 852x C\n"); } else if ((data[0] == 0x85 && data[1] == 0x26) || - (cmd[0] == 0x02 && cmd[1] == 0x85 && - (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { + (cmd[0] == 0x02 && cmd[1] == 0x85 && + (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { IC_TYPE = HX_85XX_B_SERIES_PWON; IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 728; // 0x02D8 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 692; // 0x02B4 + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 133; /*0x0085*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 728; /*0x02D8*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 692; /*0x02B4*/ CFG_VER_MAJ_FLASH_LENG = 3; - CFG_VER_MIN_FLASH_ADDR = 704; // 0x02C0 + CFG_VER_MIN_FLASH_ADDR = 704; /*0x02C0*/ CFG_VER_MIN_FLASH_LENG = 3; I("Himax IC package 852x B\n"); } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && - cmd[1] == 0x85 && cmd[2] == 0x19)) { + cmd[1] == 0x85 && cmd[2] == 0x19)) { IC_TYPE = HX_85XX_A_SERIES_PWON; IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; I("Himax IC package 852x A\n"); } else { E("Himax IC package incorrect!!\n"); - }*/ + } #else - IC_TYPE = HX_83100_SERIES_PWON; - IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; - //Himax: Set FW and CFG Flash Address - FW_VER_MAJ_FLASH_ADDR = 57384; //0xE028 - FW_VER_MAJ_FLASH_LENG = 1; - FW_VER_MIN_FLASH_ADDR = 57385; //0xE029 - FW_VER_MIN_FLASH_LENG = 1; - CFG_VER_MAJ_FLASH_ADDR = 58115; //0xE303 - CFG_VER_MAJ_FLASH_LENG = 1; - CFG_VER_MIN_FLASH_ADDR = 58116; //0xE304 - CFG_VER_MIN_FLASH_LENG = 1; + IC_TYPE = HX_83100_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + /*Himax: Set FW and CFG Flash Address*/ + FW_VER_MAJ_FLASH_ADDR = 57384; /*0xE028*/ + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 57385; /*0xE029*/ + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 58115; /*0xE303*/ + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 58116; /*0xE304*/ + CFG_VER_MIN_FLASH_LENG = 1; I("Himax IC package 83100_in\n"); #endif return true; } -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length) +void himax_read_event_stack(struct i2c_client *client, +uint8_t *buf, uint8_t length) { uint8_t cmd[4]; - cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); + cmd[3] = 0x90; cmd[2] = 0x06; + cmd[1] = 0x00; cmd[0] = 0x00; + if (i2c_himax_write(client, 0x00, + cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); } - cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); + cmd[0] = 0x00; + if (i2c_himax_write(client, 0x0C, + cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); } - i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); + i2c_himax_read(client, 0x08, + buf, length, HIMAX_I2C_RETRY_TIMES); } -#if 0 -static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data) +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Write(uint8_t *reg_byte, uint8_t *write_data) { uint8_t tmpbyte[2]; - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x03, ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x05, &write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x06, &write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, + 0x07, &write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if (isBusrtOn == false) - { - tmpbyte[0] = 0x01; - if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { - E("%s: i2c access fail!\n", __func__); - return; + if (isBusrtOn == false) { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; } - } + } } #endif -#if 0 -static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data) +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH +static void himax_83100_Flash_Burst_Write +(uint8_t *reg_byte, uint8_t *write_data) { - //uint8_t tmpbyte[2]; + /*uint8_t tmpbyte[2];*/ int i = 0; - if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x00, + ®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x01, + ®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x02, + ®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x03, + ®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - // Write 256 bytes with continue burst mode - for (i = 0; i < 256; i = i + 4) - { - if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + /*Write 256 bytes with continue burst mode*/ + for (i = 0 ; i < 256 ; i = i + 4) { + if (i2c_himax_write(private_ts->client, + 0x04, &write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x05, + &write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x06, + &write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(private_ts->client, 0x07, + &write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); return; } - } + } - //if (isBusrtOn == false) - //{ - // tmpbyte[0] = 0x01; - // if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) { - // E("%s: i2c access fail!\n", __func__); - // return; - // } - //} + /*if (isBusrtOn == false) + { + tmpbyte[0] = 0x01; + if (i2c_himax_write(private_ts->client, + 0x0C, &tmpbyte[0], 1, 3) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }*/ } #endif -#if 0 +/*#if 0*/ +#ifdef HX_EN_CHECK_PATCH static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) { uint8_t tmp_addr[4]; @@ -1835,49 +2079,51 @@ static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) uint8_t out_buffer[20]; uint8_t in_buffer[260]; - int fail_addr=0, fail_cnt=0; + int fail_addr = 0, fail_cnt = 0; int page_prog_start = 0; int i = 0; himax_interface_on(private_ts->client); himax_burst_enable(private_ts->client, 0); - //===================================== - // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 - //===================================== - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; - tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + /*===================================== + SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; + tmp_data[1] = 0x07; tmp_data[0] = 0x80; himax_83100_Flash_Write(tmp_addr, tmp_data); - for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) - { - //================================= - // SPI Transfer Control - // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF - // Set read start address : 0x8000_0028 ==> 0x0000_0000 - // Set command : 0x8000_0024 ==> 0x0000_003B - //================================= - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; - tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + for (page_prog_start = 0; page_prog_start < FW_Size; + page_prog_start = page_prog_start + 256) { + /*===================================== + SPI Transfer Control + Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + Set read start address : 0x8000_0028 ==> 0x0000_0000 + Set command : 0x8000_0024 ==> 0x0000_003B + =====================================*/ + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; + tmp_data[1] = 0x02; tmp_data[0] = 0xFF; himax_83100_Flash_Write(tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; - if (page_prog_start < 0x100) - { + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) - { + } else if (page_prog_start >= 0x100 + && page_prog_start < 0x10000) { tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; - } - else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) - { + } else if (page_prog_start >= 0x10000 + && page_prog_start < 0x1000000) { tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); @@ -1885,65 +2131,73 @@ static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) } himax_83100_Flash_Write(tmp_addr, tmp_data); - tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x00; tmp_data[0] = 0x3B; himax_83100_Flash_Write(tmp_addr, tmp_data); - //================================== - // AHB_I2C Burst Read - // Set SPI data register : 0x8000_002C ==> 0x00 - //================================== + /*================================== + AHB_I2C Burst Read + Set SPI data register : 0x8000_002C ==> 0x00 + ==================================*/ out_buffer[0] = 0x2C; out_buffer[1] = 0x00; out_buffer[2] = 0x00; out_buffer[3] = 0x80; - i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES); + i2c_himax_write(private_ts->client, 0x00, + out_buffer, 4, HIMAX_I2C_RETRY_TIMES); - //================================== - // Read access : 0x0C ==> 0x00 - //================================== + /*================================== + Read access : 0x0C ==> 0x00 + ==================================*/ out_buffer[0] = 0x00; - i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES); - - //================================== - // Read 128 bytes two times - //================================== - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + i2c_himax_write(private_ts->client, 0x0C, + out_buffer, 1, HIMAX_I2C_RETRY_TIMES); + + /*================================== + Read 128 bytes two times + ==================================*/ + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); for (i = 0; i < 128; i++) flash_buffer[i + page_prog_start] = in_buffer[i]; - i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + i2c_himax_read(private_ts->client, 0x08, + in_buffer, 128, HIMAX_I2C_RETRY_TIMES); for (i = 0; i < 128; i++) - flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; - - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; - //himax_register_read(tmp_addr, 32, out in_buffer); - //for (int i = 0; i < 128; i++) - // flash_buffer[i + page_prog_start] = in_buffer[i]; - + flash_buffer[(i + 128) + + page_prog_start] = in_buffer[i]; + + /*tmp_addr[3] = 0x80; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(tmp_addr, 32, out in_buffer); + for (int i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + */ I("%s:Verify Progress: %x\n", __func__, page_prog_start); } fail_cnt = 0; - for (i = 0; i < FW_Size; i++) - { - if (FW_File[i] != flash_buffer[i]) - { + for (i = 0; i < FW_Size; i++) { + if (FW_File[i] != flash_buffer[i]) { if (fail_cnt == 0) fail_addr = i; fail_cnt++; - //E("%s Fail Block:%x\n", __func__, i); - //return false; + /*E("%s Fail Block:%x\n", __func__, i); + return false;*/ } } - if (fail_cnt > 0) - { - E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt); + if (fail_cnt > 0) { + E("%s:Start Fail Block:%x and fail block count=%x\n", + __func__, fail_addr, fail_cnt); return false; } @@ -1959,56 +2213,60 @@ void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) int cnt = 0; unsigned char tmp_addr[4]; unsigned char tmp_data[4]; - uint8_t max_i2c_size = 32; + uint8_t max_i2c_size = 32; int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; int total_size_4bytes = total_size / 4; int total_read_times = 0; unsigned long address = 0x08000468; - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; + + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; + tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; himax_flash_write_burst(client, tmp_addr, tmp_data); - do - { + do { cnt++; himax_register_read(client, tmp_addr, 1, tmp_data); - usleep_range(10000, 20000); + usleep_range(9999, 10000); } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; - if (total_size_4bytes % max_i2c_size == 0) - { + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; + if (total_size_4bytes % max_i2c_size == 0) total_read_times = total_size_4bytes / max_i2c_size; - } else - { total_read_times = total_size_4bytes / max_i2c_size + 1; - } - for (i = 0; i < (total_read_times); i++) - { - if ( total_size_4bytes >= max_i2c_size) - { - himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]); + + for (i = 0 ; i < (total_read_times) ; i++) { + if (total_size_4bytes >= max_i2c_size) { + himax_register_read(client, tmp_addr, + max_i2c_size, + &info_data[i*max_i2c_size*4]); total_size_4bytes = total_size_4bytes - max_i2c_size; + } else { + himax_register_read(client, tmp_addr, + total_size_4bytes % max_i2c_size, + &info_data[i*max_i2c_size*4]); } - else - { - himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]); - } - address += max_i2c_size*4; - tmp_addr[1] = (uint8_t)((address>>8)&0x00FF); - tmp_addr[0] = (uint8_t)((address)&0x00FF); - } - tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; - tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44; + address += max_i2c_size * 4; + tmp_addr[1] = (uint8_t)((address>>8) & 0x00FF); + tmp_addr[0] = (uint8_t)((address) & 0x00FF); + } + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; + tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x11; tmp_data[2] = 0x22; + tmp_data[1] = 0x33; tmp_data[0] = 0x44; himax_flash_write_burst(client, tmp_addr, tmp_data); } -//ts_work -int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){ +/*ts_work*/ +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max) +{ int RawDataLen; - if (raw_cnt_rmd != 0x00) { - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; - }else{ - RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; - } + + if (raw_cnt_rmd != 0x00) + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 3) * 4) - 1; + else + RawDataLen = 124 - ((HX_MAX_PT + raw_cnt_max + 2) * 4) - 1; + return RawDataLen; } @@ -2016,40 +2274,40 @@ bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) { uint8_t cmd[4]; - if(length > 56) + if (length > 56) length = 124; - //===================== - //AHB I2C Burst Read - //===================== + /*===================== + AHB I2C Burst Read + =====================*/ cmd[0] = 0x31; - if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x13, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } cmd[0] = 0x10; - if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x0D, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } - //===================== - //Read event stack - //===================== + /*===================== + Read event stack + =====================*/ cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x00, cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } cmd[0] = 0x00; - if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + if (i2c_himax_write(client, 0x0C, cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { E("%s: i2c access fail!\n", __func__); goto err_workqueue_out; } - i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES); + i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); return 1; - - err_workqueue_out: + +err_workqueue_out: return 0; } @@ -2057,62 +2315,67 @@ bool post_read_event_stack(struct i2c_client *client) { return 1; } -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value +bool diag_check_sum(uint8_t hx_touch_info_size, +uint8_t *buf) /*return checksum value*/ { uint16_t check_sum_cal = 0; int i; - //Check 124th byte CRC - for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2) - { - check_sum_cal += (buf[i+1]*256 + buf[i]); - } - if (check_sum_cal % 0x10000 != 0) - { - I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size); + /*Check 124th byte CRC*/ + for (i = hx_touch_info_size, check_sum_cal = 0 ; i < 124 ; i = i + 2) + check_sum_cal += (buf[i + 1] * 256 + buf[i]); + + if (check_sum_cal % 0x10000 != 0) { + I("%s:diag chksum fail!check_sum_cal=%X,hx_touchinfo_sz=%d,\n", + __func__, check_sum_cal, hx_touch_info_size); return 0; } return 1; } - -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) +void diag_parse_raw_data(int hx_touch_info_size, +int RawDataLen, int mul_num, int self_num, uint8_t *buf, +uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) { int RawDataLen_word; int index = 0; - int temp1, temp2,i; - - if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 ) - { - RawDataLen_word = RawDataLen/2; - index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word; - //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); - for (i = 0; i < RawDataLen_word; i++) - { + int temp1, temp2, i; + + if (buf[hx_touch_info_size] == 0x3A && + buf[hx_touch_info_size + 1] == 0xA3 && + buf[hx_touch_info_size + 2] > 0 && + buf[hx_touch_info_size + 3] == diag_cmd + 5) { + RawDataLen_word = RawDataLen / 2; + index = (buf[hx_touch_info_size + 2] - 1) * RawDataLen_word; + /*I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num);*/ + for (i = 0; i < RawDataLen_word; i++) { temp1 = index + i; - if (temp1 < mul_num) - { //mutual - mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4]; //4: RawData Header, 1:HSB - } - else - {//self + if (temp1 < mul_num) { /*mutual*/ + /*4: RawData Header, 1:HSB */ + mutual_data[index + i] + = buf[i*2 + hx_touch_info_size + 4 + 1] + * 256 + + buf[i * 2 + hx_touch_info_size + 4]; + } else { /*self*/ temp1 = i + index; temp2 = self_num + mul_num; - + if (temp1 >= temp2) - { break; - } - self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4]; //4: RawData Header - self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1]; + /*4: RawData Header*/ + self_data[i + index - mul_num] + = buf[i * 2 + hx_touch_info_size + 4]; + self_data[i + index - mul_num + 1] + = buf[i * 2 + hx_touch_info_size + 4 + 1]; } } - } - else - { + } else { I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); - I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", + index, buf[56], buf[57], buf[58], buf[59], + mul_num, self_num); } } diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h index 18cd12b8b36fe3d387537adcbaf1b886c1eca0ed..ce7d0d49c362d102e45d8a2a97f12e53fde2747c 100644 --- a/drivers/input/touchscreen/hxchipset/himax_ic.h +++ b/drivers/input/touchscreen/hxchipset/himax_ic.h @@ -18,7 +18,6 @@ #include - #define HX_85XX_A_SERIES_PWON 1 #define HX_85XX_B_SERIES_PWON 2 #define HX_85XX_C_SERIES_PWON 3 @@ -40,43 +39,110 @@ enum fw_image_type { }; int himax_hand_shaking(struct i2c_client *client); -void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable); -void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data); -void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable); -void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data); +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable); +void himax_get_SMWP_enable(struct i2c_client *client, uint8_t *tmp_data); +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable); +void himax_get_HSEN_enable(struct i2c_client *client, uint8_t *tmp_data); void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); -void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); + +void himax_flash_dump_func(struct i2c_client *client, +uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); + int himax_chip_self_test(struct i2c_client *client); -int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN -void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100 -void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read -void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst -int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth -int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100 -void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff -void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on + +/*himax_83100_BURST_INC0_EN*/ +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); + +/*RegisterRead83100*/ +void himax_register_read(struct i2c_client *client, + uint8_t *read_addr, int read_length, uint8_t *read_data); + +/*himax_83100_Flash_Read*/ +void himax_flash_read(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *read_data); + +/*himax_83100_Flash_Write_Burst*/ +void himax_flash_write_burst(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data); + +/*himax_83100_Flash_Write_Burst_length*/ +int himax_flash_write_burst_length(struct i2c_client *client, + uint8_t *reg_byte, uint8_t *write_data, int length); + +/*RegisterWrite83100*/ +int himax_register_write(struct i2c_client *client, + uint8_t *write_addr, int write_length, uint8_t *write_data); + +/*himax_83100_SenseOff*/ +void himax_sense_off(struct i2c_client *client); +/*himax_83100_Interface_on*/ +void himax_interface_on(struct i2c_client *client); bool wait_wip(struct i2c_client *client, int Timing); -void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn -void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase -bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase -bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase -void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write -bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify -void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming -bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion -int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC -bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode); -int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); -int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); + +/*himax_83100_SenseOn*/ +void himax_sense_on(struct i2c_client *client, + uint8_t FlashMode); + +/*himax_83100_Chip_Erase*/ +void himax_chip_erase(struct i2c_client *client); +/*himax_83100_Block_Erase*/ +bool himax_block_erase(struct i2c_client *client); + +/*himax_83100_Sector_Erase*/ +bool himax_sector_erase(struct i2c_client *client, int start_addr); + +/*himax_83100_Sram_Write*/ +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); + +/*himax_83100_Sram_Verify*/ +bool himax_sram_verify(struct i2c_client *client, + uint8_t *FW_File, int FW_Size); + +/*himax_83100_Flash_Programming*/ +void himax_flash_programming(struct i2c_client *client, + uint8_t *FW_content, int FW_Size); + +/*himax_83100_CheckChipVersion*/ +bool himax_check_chip_version(struct i2c_client *client); + +/*himax_83100_Check_CRC*/ +int himax_check_CRC(struct i2c_client *client, int mode); + +bool Calculate_CRC_with_AP(unsigned char *FW_content, + int CRC_from_FW, int mode); + +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, + unsigned char *fw, int len, bool change_iref); + void himax_touch_information(struct i2c_client *client); void himax_read_FW_ver(struct i2c_client *client); bool himax_ic_package_check(struct i2c_client *client); -void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length); + +void himax_read_event_stack(struct i2c_client *client, + uint8_t *buf, uint8_t length); + int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); bool post_read_event_stack(struct i2c_client *client); -bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value -void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); -void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); \ No newline at end of file + +/*return checksum value*/ +bool diag_check_sum(uint8_t hx_touch_info_size, uint8_t *buf_ts); + +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, + int mul_num, int self_num, uint8_t *buf_ts, + uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; + +int himax_load_CRC_bin_file(struct i2c_client *client); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c index 7e8a1d6572c5121d42a030d3ff7a8d0cb39e8108..309bb5e01073f7fb8e13e1e9dead372135a9ef0a 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.c +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -16,6 +16,13 @@ #include "himax_platform.h" #include "himax_common.h" +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#endif + int irq_enable_count = 0; #ifdef HX_SMART_WAKEUP #define TS_WAKE_LOCK_TIMEOUT (2 * HZ) @@ -25,16 +32,7 @@ int irq_enable_count = 0; #define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" #define PINCTRL_STATE_RELEASE "pmx_ts_release" -extern struct himax_ic_data* ic_data; -extern void himax_ts_work(struct himax_ts_data *ts); -extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); -extern int himax_ts_init(struct himax_ts_data *ts); - -extern int tp_rst_gpio; - -#ifdef HX_TP_PROC_DIAG -extern uint8_t getDiagCommand(void); -#endif +/*extern int himax_ts_init(struct himax_ts_data *ts);*/ void himax_vk_parser(struct device_node *dt, struct himax_i2c_platform_data *pdata) @@ -49,30 +47,34 @@ void himax_vk_parser(struct device_node *dt, if (node == NULL) { I(" DT-No vk info in DT"); return; + } else { while ((pp = of_get_next_child(node, pp))) cnt++; if (!cnt) return; - vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); - if (!vk) - return; + vk = kcalloc(cnt, sizeof(*vk), GFP_KERNEL); pp = NULL; while ((pp = of_get_next_child(node, pp))) { if (of_property_read_u32(pp, "idx", &data) == 0) vk[i].index = data; - if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { - vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; - vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; + if (of_property_read_u32_array(pp, "range", + coords, 4) == 0) { + vk[i].x_range_min = coords[0], + vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], + vk[i].y_range_max = coords[3]; } else I(" range faile"); i++; } pdata->virtual_key = vk; for (i = 0; i < cnt; i++) - I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, - pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); + I(" vk[%d] idx:%d x_min:%d, y_max:%d", + i, pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, + pdata->virtual_key[i].y_range_max); } } @@ -89,25 +91,31 @@ int himax_parse_dt(struct himax_ts_data *ts, if (prop) { coords_size = prop->length / sizeof(u32); if (coords_size != 4) - D(" %s:Invalid panel coords size %d", __func__, coords_size); + D(" %s:Invalid panel coords size %d", + __func__, coords_size); } - if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { + if (of_property_read_u32_array(dt, "himax,panel-coords", + coords, coords_size) == 0) { pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; - I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, - pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", + __func__, pdata->abs_x_min, pdata->abs_x_max, + pdata->abs_y_min, pdata->abs_y_max); } prop = of_find_property(dt, "himax,display-coords", NULL); if (prop) { coords_size = prop->length / sizeof(u32); if (coords_size != 4) - D(" %s:Invalid display coords size %d", __func__, coords_size); + D(" %s:Invalid display coords size %d", + __func__, coords_size); } - rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); + rc = of_property_read_u32_array(dt, "himax,display-coords", + coords, coords_size); if (rc && (rc != -EINVAL)) { - D(" %s:Fail to read display-coords %d\n", __func__, rc); + D(" %s:Fail to read display-coords %d\n", + __func__, rc); return rc; } pdata->screenWidth = coords[1]; @@ -116,19 +124,19 @@ int himax_parse_dt(struct himax_ts_data *ts, pdata->screenHeight); pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); - if (!gpio_is_valid(pdata->gpio_irq)) { + if (!gpio_is_valid(pdata->gpio_irq)) I(" DT:gpio_irq value is not valid\n"); - } pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); - if (!gpio_is_valid(pdata->gpio_reset)) { + if (!gpio_is_valid(pdata->gpio_reset)) I(" DT:gpio_rst value is not valid\n"); - } + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); - if (!gpio_is_valid(pdata->gpio_3v3_en)) { + if (!gpio_is_valid(pdata->gpio_3v3_en)) I(" DT:gpio_3v3_en value is not valid\n"); - } - I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", + pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); if (of_property_read_u32(dt, "report_type", &data) == 0) { pdata->protocol_type = data; @@ -140,7 +148,8 @@ int himax_parse_dt(struct himax_ts_data *ts, return 0; } -int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +int i2c_himax_read(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) { int retry; struct i2c_msg msg[] = { @@ -157,7 +166,7 @@ int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, ui .buf = data, } }; - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 2) == 2) break; @@ -166,13 +175,16 @@ int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, ui if (retry == toRetry) { E("%s: i2c_read_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } -int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +int i2c_himax_write(struct i2c_client *client, +uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) { int retry/*, loop_i*/; uint8_t buf[length + 1]; @@ -188,7 +200,7 @@ int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, u buf[0] = command; memcpy(buf+1, data, length); - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) break; @@ -198,13 +210,16 @@ int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, u if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } -int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +int i2c_himax_read_command(struct i2c_client *client, +uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) { int retry; struct i2c_msg msg[] = { @@ -215,7 +230,7 @@ int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *d .buf = data, } }; - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) break; @@ -224,17 +239,21 @@ int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *d if (retry == toRetry) { E("%s: i2c_read_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } -int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) +int i2c_himax_write_command(struct i2c_client *client, +uint8_t command, uint8_t toRetry) { return i2c_himax_write(client, command, NULL, 0, toRetry); } -int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) +int i2c_himax_master_write(struct i2c_client *client, +uint8_t *data, uint8_t length, uint8_t toRetry) { int retry/*, loop_i*/; uint8_t buf[length]; @@ -249,7 +268,7 @@ int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t len }; memcpy(buf, data, length); - + mutex_lock(&private_ts->rw_lock); for (retry = 0; retry < toRetry; retry++) { if (i2c_transfer(client->adapter, msg, 1) == 1) break; @@ -259,8 +278,10 @@ int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t len if (retry == toRetry) { E("%s: i2c_write_block retry over %d\n", __func__, toRetry); + mutex_unlock(&private_ts->rw_lock); return -EIO; } + mutex_unlock(&private_ts->rw_lock); return 0; } @@ -287,62 +308,51 @@ uint8_t himax_int_gpio_read(int pinnum) } #if defined(CONFIG_HMX_DB) -static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +static int himax_regulator_configure(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { - int retval; - pdata->vcc_dig = regulator_get(&client->dev, - "vdd"); - if (IS_ERR(pdata->vcc_dig)) - { - E("%s: Failed to get regulator vdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_dig); - return retval; - } - pdata->vcc_ana = regulator_get(&client->dev, - "avdd"); - if (IS_ERR(pdata->vcc_ana)) - { - E("%s: Failed to get regulator avdd\n", - __func__); - retval = PTR_ERR(pdata->vcc_ana); - regulator_put(pdata->vcc_ana); - return retval; - } - - return 0; + int retval; + + pdata->vcc_dig = regulator_get(&client->dev, "vdd"); + if (IS_ERR(pdata->vcc_dig)) { + E("%s: Failed to get regulator vdd\n", __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + pdata->vcc_ana = regulator_get(&client->dev, "avdd"); + if (IS_ERR(pdata->vcc_ana)) { + E("%s: Failed to get regulator avdd\n", __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_ana); + return retval; + } + + return 0; }; -static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) +static int himax_power_on(struct himax_i2c_platform_data *pdata, +bool on) { - int retval; - - if (on) - { - retval = regulator_enable(pdata->vcc_dig); - if (retval) - { - E("%s: Failed to enable regulator vdd\n", - __func__); - return retval; - } - msleep(100); - retval = regulator_enable(pdata->vcc_ana); - if (retval) - { - E("%s: Failed to enable regulator avdd\n", - __func__); - regulator_disable(pdata->vcc_dig); - return retval; - } - } - else - { - regulator_disable(pdata->vcc_dig); - regulator_disable(pdata->vcc_ana); - } - - return 0; + int retval; + + if (on) { + retval = regulator_enable(pdata->vcc_dig); + if (retval) { + E("%s: Failed to enable regulator vdd\n", __func__); + return retval; + } + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + if (retval) { + E("%s: Failed to enable regulator avdd\n", __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } else { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + return 0; } int himax_ts_pinctrl_init(struct himax_ts_data *ts) @@ -353,41 +363,35 @@ int himax_ts_pinctrl_init(struct himax_ts_data *ts) ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { retval = PTR_ERR(ts->ts_pinctrl); - dev_dbg(&ts->client->dev, - "Target does not use pinctrl %d\n", retval); + dev_dbg(&ts->client->dev, "Target does not use pinctrl %d\n", + retval); goto err_pinctrl_get; } - ts->pinctrl_state_active - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_ACTIVE); + ts->pinctrl_state_active = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { retval = PTR_ERR(ts->pinctrl_state_active); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_ACTIVE, retval); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); goto err_pinctrl_lookup; } - ts->pinctrl_state_suspend - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_SUSPEND); + ts->pinctrl_state_suspend = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { retval = PTR_ERR(ts->pinctrl_state_suspend); - dev_err(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_SUSPEND, retval); + dev_err(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); goto err_pinctrl_lookup; } - ts->pinctrl_state_release - = pinctrl_lookup_state(ts->ts_pinctrl, - PINCTRL_STATE_RELEASE); + ts->pinctrl_state_release = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { retval = PTR_ERR(ts->pinctrl_state_release); - dev_dbg(&ts->client->dev, - "Can not lookup %s pinstate %d\n", - PINCTRL_STATE_RELEASE, retval); + dev_dbg(&ts->client->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); } return 0; @@ -399,185 +403,161 @@ int himax_ts_pinctrl_init(struct himax_ts_data *ts) return retval; } -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { - int error; + int error; - error = himax_regulator_configure(client, pdata); - if (error) - { - E("Failed to intialize hardware\n"); - goto err_regulator_not_on; - } + error = himax_regulator_configure(client, pdata); + if (error) { + E("Failed to initialize hardware\n"); + goto err_regulator_not_on; + } #ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - /* configure touchscreen reset out gpio */ - error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_reset); - goto err_regulator_on; - } - - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_reset_req; - } - } + if (gpio_is_valid(pdata->gpio_reset)) { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } #endif - error = himax_power_on(pdata, true); - if (error) - { - E("Failed to power on hardware\n"); - goto err_gpio_reset_req; - } + error = himax_power_on(pdata, true); + if (error) { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } #ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n", - pdata->gpio_irq); - goto err_power_on; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_irq); - goto err_gpio_irq_req; - } - client->irq = gpio_to_irq(pdata->gpio_irq); - } - else - { - E("irq gpio not provided\n"); - goto err_power_on; - } + /* configure touchscreen irq gpio */ + if (gpio_is_valid(pdata->gpio_irq)) { + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + goto err_power_on; + } #endif - - msleep(20); + msleep(20); #ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - goto err_gpio_irq_req; - } - } + if (gpio_is_valid(pdata->gpio_reset)) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } #endif - return 0; + return 0; #ifdef HX_RST_PIN_FUNC - err_gpio_irq_req: +err_gpio_irq_req: #endif #ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - gpio_free(pdata->gpio_irq); - err_power_on: + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); +err_power_on: #endif - himax_power_on(pdata, false); - err_gpio_reset_req: + himax_power_on(pdata, false); +err_gpio_reset_req: #ifdef HX_RST_PIN_FUNC - if (gpio_is_valid(pdata->gpio_reset)) - gpio_free(pdata->gpio_reset); - err_regulator_on: + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); +err_regulator_on: #endif - err_regulator_not_on: +err_regulator_not_on: - return error; + return error; } #else -int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +int himax_gpio_power_config(struct i2c_client *client, +struct himax_i2c_platform_data *pdata) { - int error=0; - + int error = 0; + #ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_request(pdata->gpio_reset, "himax-reset"); - if (error < 0) - { - E("%s: request reset pin failed\n", __func__); - return error; - } - error = gpio_direction_output(pdata->gpio_reset, 0); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } + if (pdata->gpio_reset >= 0) { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0) { + E("%s: request reset pin failed\n", __func__); + return error; } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } #endif - if (pdata->gpio_3v3_en >= 0) - { - error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); - if (error < 0) - { - E("%s: request 3v3_en pin failed\n", __func__); - return error; - } - gpio_direction_output(pdata->gpio_3v3_en, 1); - I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + if (pdata->gpio_3v3_en >= 0) { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) { + E("%s: request 3v3_en pin failed\n", __func__); + return error; } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } #ifdef HX_IRQ_PIN_FUNC - if (gpio_is_valid(pdata->gpio_irq)) - { - /* configure touchscreen irq gpio */ - error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); - if (error) - { - E("unable to request gpio [%d]\n",pdata->gpio_irq); - return error; - } - error = gpio_direction_input(pdata->gpio_irq); - if (error) - { - E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); - return error; - } - client->irq = gpio_to_irq(pdata->gpio_irq); + if (gpio_is_valid(pdata->gpio_irq)) { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) { + E("unable to request gpio [%d]\n", pdata->gpio_irq); + return error; } - else - { - E("irq gpio not provided\n"); + error = gpio_direction_input(pdata->gpio_irq); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); return error; } + client->irq = gpio_to_irq(pdata->gpio_irq); + } else { + E("irq gpio not provided\n"); + return error; + } #endif - msleep(20); - + msleep(20); + #ifdef HX_RST_PIN_FUNC - if (pdata->gpio_reset >= 0) - { - error = gpio_direction_output(pdata->gpio_reset, 1); - if (error) - { - E("unable to set direction for gpio [%d]\n", - pdata->gpio_reset); - return error; - } + if (pdata->gpio_reset >= 0) { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; } - msleep(20); -#endif - - return error; } + msleep(20); +#endif + + return error; +} #endif static void himax_ts_isr_func(struct himax_ts_data *ts) @@ -595,34 +575,40 @@ irqreturn_t himax_ts_thread(int irq, void *ptr) if (ts->debug_log_level & BIT(2)) { getnstimeofday(&timeStart); - usleep_range(5000, 7000); - //I(" Irq start time = %ld.%06ld s\n", - // timeStart.tv_sec, timeStart.tv_nsec/1000); + usleep_range(4999, 5000); + /*I(" Irq start time = %ld.%06ld s\n", + timeStart.tv_sec, timeStart.tv_nsec/1000);*/ } #ifdef HX_SMART_WAKEUP - if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) { - wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + if (atomic_read(&ts->suspend_mode) + && (!FAKE_POWER_KEY_SEND) + && (ts->SMWP_enable) + && (!diag_cmd)) { + __pm_wakeup_event(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); msleep(200); himax_wake_check_func(); return IRQ_HANDLED; } #endif himax_ts_isr_func((struct himax_ts_data *)ptr); - if(ts->debug_log_level & BIT(2)) { - getnstimeofday(&timeEnd); - timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) - -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); - //I("Irq finish time = %ld.%06ld s\n", - // timeEnd.tv_sec, timeEnd.tv_nsec/1000); - //I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec + = (timeEnd.tv_sec * 1000000000 + timeEnd.tv_nsec) + - (timeStart.tv_sec * 1000000000 + timeStart.tv_nsec); + /*I("Irq finish time = %ld.%06ld s\n", + timeEnd.tv_sec, timeEnd.tv_nsec/1000); + I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000);*/ } return IRQ_HANDLED; } static void himax_ts_work_func(struct work_struct *work) { - struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); + struct himax_ts_data *ts = + container_of(work, struct himax_ts_data, work); + himax_ts_work(ts); } @@ -634,24 +620,26 @@ int himax_ts_register_interrupt(struct i2c_client *client) int ret = 0; ts->irq_enabled = 0; - //Work functon + /*Work functon*/ if (client->irq) {/*INT mode*/ ts->use_irq = 1; - if(ic_data->HX_INT_IS_EDGE) - { - I("%s edge triiger falling\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); - } - else - { - I("%s level trigger low\n ",__func__); - ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + if (ic_data->HX_INT_IS_EDGE) { + I("%s edge triiger falling\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, client->name, ts); + } else { + I("%s level trigger low\n ", __func__); + ret = request_threaded_irq(client->irq, + NULL, himax_ts_thread, IRQF_TRIGGER_LOW + | IRQF_ONESHOT, client->name, ts); } if (ret == 0) { ts->irq_enabled = 1; irq_enable_count = 1; tp_irq = client->irq; - I("%s: irq enabled at qpio: %d\n", __func__, client->irq); + I("%s: irq enabled at qpio: %d\n", + __func__, client->irq); #ifdef HX_SMART_WAKEUP irq_set_irq_wake(client->irq, 1); #endif @@ -662,8 +650,8 @@ int himax_ts_register_interrupt(struct i2c_client *client) } else { I("%s: client->irq is empty, use polling mode.\n", __func__); } - - if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + /*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + if (!ts->use_irq) { ts->himax_wq = create_singlethread_workqueue("himax_touch"); INIT_WORK(&ts->work, himax_ts_work_func); @@ -680,7 +668,7 @@ static int himax_common_suspend(struct device *dev) { struct himax_ts_data *ts = dev_get_drvdata(dev); - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); himax_chip_common_suspend(ts); return 0; @@ -690,7 +678,7 @@ static int himax_common_resume(struct device *dev) { struct himax_ts_data *ts = dev_get_drvdata(dev); - I("%s: enter \n", __func__); + I("%s: enter\n", __func__); himax_chip_common_resume(ts); return 0; @@ -702,23 +690,28 @@ int fb_notifier_callback(struct notifier_block *self, { struct fb_event *evdata = data; int *blank; - struct himax_ts_data *ts= - container_of(self, struct himax_ts_data, fb_notif); + struct himax_ts_data *ts + = container_of(self, struct himax_ts_data, fb_notif); + int ERR = 1; I(" %s\n", __func__); - if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && - ts->client) { + if (evdata && evdata->data && event + == FB_EVENT_BLANK && ts && ts->client) { blank = evdata->data; mutex_lock(&ts->fb_mutex); switch (*blank) { case FB_BLANK_UNBLANK: if (!ts->probe_done) { - himax_ts_init(ts); - ts->probe_done = true; - } else { + if (himax_ts_init(ts) == true) { + I("himax_ts_init return OK\n"); + ts->probe_done = true; + } else { + I("himax_ts_init return Fail\n"); + return -ERR; + } + } else himax_common_resume(&ts->client->dev); - } break; case FB_BLANK_POWERDOWN: @@ -748,7 +741,7 @@ static const struct dev_pm_ops himax_common_pm_ops = { }; #ifdef CONFIG_OF -static const struct of_device_id himax_match_table[] = { +static struct of_device_id himax_match_table[] = { {.compatible = "himax,hxcommon" }, {}, }; @@ -770,16 +763,10 @@ static struct i2c_driver himax_common_driver = { }, }; -static void __init himax_common_init_async(void *unused, async_cookie_t cookie) -{ - I("%s:Enter \n", __func__); - i2c_add_driver(&himax_common_driver); -} - static int __init himax_common_init(void) { I("Himax common touch panel driver init\n"); - async_schedule(himax_common_init_async, NULL); + i2c_add_driver(&himax_common_driver); return 0; } @@ -792,5 +779,5 @@ module_init(himax_common_init); module_exit(himax_common_exit); MODULE_DESCRIPTION("Himax_common driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h index 1223685683aa081af63e3a4cc4f44b7f8995436b..6871e53cd1f21851664cce102460095b53e04057 100644 --- a/drivers/input/touchscreen/hxchipset/himax_platform.h +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -22,6 +22,7 @@ #include #include #include + #if defined(CONFIG_HMX_DB) #include #endif @@ -31,15 +32,11 @@ #define HIMAX_I2C_RETRY_TIMES 10 #if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) -#define D(x...) pr_debug("[HXTP] " x) -#define I(x...) pr_info("[HXTP] " x) -#define W(x...) pr_warning("[HXTP][WARNING] " x) -#define E(x...) pr_err("[HXTP][ERROR] " x) -#define DIF(x...) \ -do {\ - if (debug_flag) \ - pr_debug("[HXTP][DEBUG] " x) \ -} while(0) +#define D(x...) pr_info("[HXTP][DEBUG] " x) +#define I(x...) pr_info("[HXTP][INFO] " x) +#define W(x...) pr_info("[HXTP][WARNING] " x) +#define E(x...) pr_info("[HXTP][ERROR] " x) +#define DIF(x...) do { if (debug_flag) pr_info("[HXTP][DEBUG] " x) } while (0) #else #define D(x...) #define I(x...) @@ -53,24 +50,24 @@ do {\ #define HX_VTG_MIN_UV 2700000 #define HX_VTG_MAX_UV 3300000 #define HX_ACTIVE_LOAD_UA 15000 -#define HX_LPM_LOAD_UA 10 +#define HX_LPM_LOAD_UA 10 /* Digital voltage @1.8 V */ #define HX_VTG_DIG_MIN_UV 1800000 #define HX_VTG_DIG_MAX_UV 1800000 #define HX_ACTIVE_LOAD_DIG_UA 10000 -#define HX_LPM_LOAD_DIG_UA 10 +#define HX_LPM_LOAD_DIG_UA 10 #define HX_I2C_VTG_MIN_UV 1800000 #define HX_I2C_VTG_MAX_UV 1800000 -#define HX_I2C_LOAD_UA 10000 -#define HX_I2C_LPM_LOAD_UA 10 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 #endif -#define HIMAX_common_NAME "himax_tp" +#define HIMAX_common_NAME "himax_tp" #define HIMAX_I2C_ADDR 0x48 #define INPUT_DEV_NAME "himax-touchscreen" -struct himax_i2c_platform_data { +struct himax_i2c_platform_data { int abs_x_min; int abs_x_max; int abs_x_fuzz; @@ -108,28 +105,53 @@ struct himax_i2c_platform_data { int irq_gpio; u32 irq_gpio_flags; - struct regulator *vcc_ana; //For Dragon Board - struct regulator *vcc_dig; //For Dragon Board - struct regulator *vcc_i2c; //For Dragon Board -#endif + struct regulator *vcc_ana; /*For Dragon Board*/ + struct regulator *vcc_dig; /*For Dragon Board*/ + struct regulator *vcc_i2c; /*For Dragon Board*/ +#endif }; extern int irq_enable_count; -extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); -extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); -extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); -extern void himax_int_enable(int irqnum, int enable); -extern int himax_ts_register_interrupt(struct i2c_client *client); -extern void himax_rst_gpio_set(int pinnum, uint8_t value); -extern uint8_t himax_int_gpio_read(int pinnum); - -extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); +int i2c_himax_read(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write(struct i2c_client *client, + uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_write_command(struct i2c_client *client, + uint8_t command, uint8_t toRetry); + +int i2c_himax_master_write(struct i2c_client *client, + uint8_t *data, uint8_t length, uint8_t toRetry); + +int i2c_himax_read_command(struct i2c_client *client, + uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); + +void himax_int_enable(int irqnum, int enable); +int himax_ts_register_interrupt(struct i2c_client *client); +void himax_rst_gpio_set(int pinnum, uint8_t value); +uint8_t himax_int_gpio_read(int pinnum); + +int himax_gpio_power_config(struct i2c_client *client, + struct himax_i2c_platform_data *pdata); #if defined(CONFIG_FB) -extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +extern int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); #endif +extern struct himax_ts_data *private_ts; +extern struct himax_ic_data *ic_data; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int tp_rst_gpio; + +#ifdef HX_TP_PROC_DIAG +extern uint8_t getDiagCommand(void); +#endif + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +int himax_ts_pinctrl_init(struct himax_ts_data *ts); #endif diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 3359afbb1c77619b0e97945f81934638e3f9688f..a83616951d47563a970506f5e05a67b2dabe1987 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -4864,6 +4864,10 @@ static int arm_smmu_device_remove(struct platform_device *pdev) arm_smmu_exit_power_resources(smmu->pwr); + spin_lock(&arm_smmu_devices_lock); + list_del(&smmu->list); + spin_unlock(&arm_smmu_devices_lock); + return 0; } diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 6b714571b6834ebee357502847961a6dce3c6a4b..08fcdbfa721d48259e5d125b37fcedd44f072570 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -213,11 +213,10 @@ static void gic_redist_wait_for_rwp(void) } #ifdef CONFIG_ARM64 -static DEFINE_STATIC_KEY_FALSE(is_cavium_thunderx); static u64 __maybe_unused gic_read_iar(void) { - if (static_branch_unlikely(&is_cavium_thunderx)) + if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_23154)) return gic_read_iar_cavium_thunderx(); else return gic_read_iar_common(); @@ -1334,14 +1333,6 @@ static const struct irq_domain_ops partition_domain_ops = { .select = gic_irq_domain_select, }; -static void gicv3_enable_quirks(void) -{ -#ifdef CONFIG_ARM64 - if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_23154)) - static_branch_enable(&is_cavium_thunderx); -#endif -} - static int __init gic_init_bases(void __iomem *dist_base, struct redist_region *rdist_regs, u32 nr_redist_regions, @@ -1364,8 +1355,6 @@ static int __init gic_init_bases(void __iomem *dist_base, gic_data.nr_redist_regions = nr_redist_regions; gic_data.redist_stride = redist_stride; - gicv3_enable_quirks(); - /* * Find out how many interrupts are supported. * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index d91dd580e9781bc73704d3ad41c009265e227320..37aaea88a6adc05ab599bea9af566d41be3c100d 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -387,10 +387,10 @@ void divasa_xdi_driver_unload(void) ** Receive and process command from user mode utility */ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *mptr, divas_xdi_copy_from_user_fn_t cp_fn) { - diva_xdi_um_cfg_cmd_t msg; + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = NULL; diva_os_spin_lock_magic_t old_irql; struct list_head *tmp; @@ -400,21 +400,21 @@ void *diva_xdi_open_adapter(void *os_handle, const void __user *src, length, sizeof(diva_xdi_um_cfg_cmd_t))) return NULL; } - if ((*cp_fn) (os_handle, &msg, src, sizeof(msg)) <= 0) { + if ((*cp_fn) (os_handle, msg, src, sizeof(*msg)) <= 0) { DBG_ERR(("A: A(?) open, write error")) return NULL; } diva_os_enter_spin_lock(&adapter_lock, &old_irql, "open_adapter"); list_for_each(tmp, &adapter_queue) { a = list_entry(tmp, diva_os_xdi_adapter_t, link); - if (a->controller == (int)msg.adapter) + if (a->controller == (int)msg->adapter) break; a = NULL; } diva_os_leave_spin_lock(&adapter_lock, &old_irql, "open_adapter"); if (!a) { - DBG_ERR(("A: A(%d) open, adapter not found", msg.adapter)) + DBG_ERR(("A: A(%d) open, adapter not found", msg->adapter)) } return (a); @@ -436,8 +436,10 @@ void diva_xdi_close_adapter(void *adapter, void *os_handle) int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn) + int length, void *mptr, + divas_xdi_copy_from_user_fn_t cp_fn) { + diva_xdi_um_cfg_cmd_t *msg = (diva_xdi_um_cfg_cmd_t *)mptr; diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) adapter; void *data; @@ -458,7 +460,13 @@ diva_xdi_write(void *adapter, void *os_handle, const void __user *src, return (-2); } - length = (*cp_fn) (os_handle, data, src, length); + if (msg) { + *(diva_xdi_um_cfg_cmd_t *)data = *msg; + length = (*cp_fn) (os_handle, (char *)data + sizeof(*msg), + src + sizeof(*msg), length - sizeof(*msg)); + } else { + length = (*cp_fn) (os_handle, data, src, length); + } if (length > 0) { if ((*(a->interface.cmd_proc)) (a, (diva_xdi_um_cfg_cmd_t *) data, length)) { diff --git a/drivers/isdn/hardware/eicon/diva.h b/drivers/isdn/hardware/eicon/diva.h index e979085d1b891ff50497337849cd8a5157ffa57e..a0a607c0c32e219b45014f5bb22b64fb61752547 100644 --- a/drivers/isdn/hardware/eicon/diva.h +++ b/drivers/isdn/hardware/eicon/diva.h @@ -19,10 +19,11 @@ int diva_xdi_read(void *adapter, void *os_handle, void __user *dst, int max_length, divas_xdi_copy_to_user_fn_t cp_fn); int diva_xdi_write(void *adapter, void *os_handle, const void __user *src, - int length, divas_xdi_copy_from_user_fn_t cp_fn); + int length, void *msg, + divas_xdi_copy_from_user_fn_t cp_fn); void *diva_xdi_open_adapter(void *os_handle, const void __user *src, - int length, + int length, void *msg, divas_xdi_copy_from_user_fn_t cp_fn); void diva_xdi_close_adapter(void *adapter, void *os_handle); diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 32f34511c416925144e3b04fa2f9051ac5a78e1c..1e8b9918bfce228d250b6f001a6cd2ee6c0fca87 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -591,19 +591,22 @@ static int divas_release(struct inode *inode, struct file *file) static ssize_t divas_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); - } - if (!file->private_data) { - return (-ENODEV); + if (!file->private_data) + return (-ENODEV); + ret = diva_xdi_write(file->private_data, file, + buf, count, &msg, xdi_copy_from_user); + } else { + ret = diva_xdi_write(file->private_data, file, + buf, count, NULL, xdi_copy_from_user); } - ret = diva_xdi_write(file->private_data, file, - buf, count, xdi_copy_from_user); switch (ret) { case -1: /* Message should be removed from rx mailbox first */ ret = -EBUSY; @@ -622,11 +625,12 @@ static ssize_t divas_write(struct file *file, const char __user *buf, static ssize_t divas_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { + diva_xdi_um_cfg_cmd_t msg; int ret = -EINVAL; if (!file->private_data) { file->private_data = diva_xdi_open_adapter(file, buf, - count, + count, &msg, xdi_copy_from_user); } if (!file->private_data) { diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c index 8a850c526f60ebdaf864a5f3615d7db1071f269a..3f97c803586e6c91c87f31a11a5a5fa4b381774f 100644 --- a/drivers/leds/leds-qpnp-haptics.c +++ b/drivers/leds/leds-qpnp-haptics.c @@ -2515,6 +2515,16 @@ static int qpnp_haptics_remove(struct platform_device *pdev) return 0; } +static void qpnp_haptics_shutdown(struct platform_device *pdev) +{ + struct hap_chip *chip = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&chip->haptics_work); + + /* disable haptics */ + qpnp_haptics_mod_enable(chip, false); +} + static const struct dev_pm_ops qpnp_haptics_pm_ops = { .suspend = qpnp_haptics_suspend, }; @@ -2532,6 +2542,7 @@ static struct platform_driver qpnp_haptics_driver = { }, .probe = qpnp_haptics_probe, .remove = qpnp_haptics_remove, + .shutdown = qpnp_haptics_shutdown, }; module_platform_driver(qpnp_haptics_driver); diff --git a/drivers/leds/leds-qpnp-wled.c b/drivers/leds/leds-qpnp-wled.c index 861d9876cf0b21a6228fdd74b25ee8ba9d03bbce..d272ca6ac1d0fdbc1325311516022b003c5fa6b2 100644 --- a/drivers/leds/leds-qpnp-wled.c +++ b/drivers/leds/leds-qpnp-wled.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -420,6 +421,7 @@ struct qpnp_wled { bool prev_state; bool stepper_en; bool ovp_irq_disabled; + bool secure_mode; bool auto_calib_enabled; bool auto_calib_done; bool module_dis_perm; @@ -936,6 +938,46 @@ static ssize_t qpnp_wled_ramp_step_store(struct device *dev, return count; } +/* sysfs function for irqs enable/disable */ +static ssize_t qpnp_wled_irq_control(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_wled *wled = dev_get_drvdata(dev); + int val, rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val != 0 && val != 1) + return count; + + mutex_lock(&wled->lock); + /* Disable irqs */ + if (val == 1 && !wled->secure_mode) { + if (wled->ovp_irq > 0) + disable_irq(wled->ovp_irq); + + if (wled->sc_irq > 0) + disable_irq(wled->sc_irq); + + wled->secure_mode = true; + } else if (val == 0 && wled->secure_mode) { + if (wled->ovp_irq > 0) + enable_irq(wled->ovp_irq); + + if (wled->sc_irq > 0) + enable_irq(wled->sc_irq); + + wled->secure_mode = false; + } + + mutex_unlock(&wled->lock); + + return count; +} + /* sysfs show function for dim mode */ static ssize_t qpnp_wled_dim_mode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1055,6 +1097,7 @@ static struct device_attribute qpnp_wled_attrs[] = { __ATTR(ramp_ms, 0664, qpnp_wled_ramp_ms_show, qpnp_wled_ramp_ms_store), __ATTR(ramp_step, 0664, qpnp_wled_ramp_step_show, qpnp_wled_ramp_step_store), + __ATTR(secure_mode, 0664, NULL, qpnp_wled_irq_control), }; /* worker for setting wled brightness */ @@ -1066,6 +1109,12 @@ static void qpnp_wled_work(struct work_struct *work) wled = container_of(work, struct qpnp_wled, work); mutex_lock(&wled->lock); + + if (wled->secure_mode) { + pr_debug("Can not set brightness in secure_mode\n "); + goto unlock_mutex; + } + level = wled->cdev.brightness; if (wled->brt_map_table) { @@ -2162,6 +2211,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled) /* setup ovp and sc irqs */ if (wled->ovp_irq >= 0) { + irq_set_status_flags(wled->ovp_irq, IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(&wled->pdev->dev, wled->ovp_irq, NULL, qpnp_wled_ovp_irq_handler, IRQF_ONESHOT, "qpnp_wled_ovp_irq", wled); @@ -2182,6 +2232,7 @@ static int qpnp_wled_config(struct qpnp_wled *wled) if (wled->sc_irq >= 0) { wled->sc_cnt = 0; + irq_set_status_flags(wled->sc_irq, IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(&wled->pdev->dev, wled->sc_irq, NULL, qpnp_wled_sc_irq_handler, IRQF_ONESHOT, "qpnp_wled_sc_irq", wled); diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 89fc93bc900924366e58611a31ce8211a34926fd..dafa981437480c17b873183cc0a499d4a2f96d95 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -551,4 +551,24 @@ config DM_ANDROID_VERITY of the metadata contents are verified against the key included in the system keyring. Upon success, the underlying verity target is setup. + +config DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED + bool "Verity will validate blocks at most once" + depends on DM_VERITY + ---help--- + Default enables at_most_once option for dm-verity + + Verify data blocks only the first time they are read from the + data device, rather than every time. This reduces the overhead + of dm-verity so that it can be used on systems that are memory + and/or CPU constrained. However, it provides a reduced level + of security because only offline tampering of the data device's + content will be detected, not online tampering. + + Hash blocks are still verified each time they are read from the + hash device, since verification of hash blocks is less performance + critical than data blocks, and a hash block will not be verified + any more after all the data blocks it covers have been verified anyway. + + If unsure, say N. endif # MD diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 809a4dfc6338aef1fe7481d661acff94d742055c..c837defb5e4dd0d42fa2b7c74883241c6b6f5215 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -373,9 +373,6 @@ static void __cache_size_refresh(void) static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, enum data_mode *data_mode) { - unsigned noio_flag; - void *ptr; - if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) { *data_mode = DATA_MODE_SLAB; return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask); @@ -399,16 +396,16 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask, * all allocations done by this process (including pagetables) are done * as if GFP_NOIO was specified. */ + if (gfp_mask & __GFP_NORETRY) { + unsigned noio_flag = memalloc_noio_save(); + void *ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, + PAGE_KERNEL); - if (gfp_mask & __GFP_NORETRY) - noio_flag = memalloc_noio_save(); - - ptr = __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL); - - if (gfp_mask & __GFP_NORETRY) memalloc_noio_restore(noio_flag); + return ptr; + } - return ptr; + return __vmalloc(c->block_size, gfp_mask | __GFP_HIGHMEM, PAGE_KERNEL); } /* @@ -822,6 +819,7 @@ enum new_flag { static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client *c, enum new_flag nf) { struct dm_buffer *b; + bool tried_noio_alloc = false; /* * dm-bufio is resistant to allocation failures (it just keeps @@ -846,6 +844,15 @@ static struct dm_buffer *__alloc_buffer_wait_no_callback(struct dm_bufio_client if (nf == NF_PREFETCH) return NULL; + if (dm_bufio_cache_size_latch != 1 && !tried_noio_alloc) { + dm_bufio_unlock(c); + b = alloc_buffer(c, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN); + dm_bufio_lock(c); + if (b) + return b; + tried_noio_alloc = true; + } + if (!list_empty(&c->reserved_buffers)) { b = list_entry(c->reserved_buffers.next, struct dm_buffer, lru_list); @@ -1591,19 +1598,11 @@ dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) static unsigned long dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc) { - struct dm_bufio_client *c; - unsigned long count; - unsigned long retain_target; - - c = container_of(shrink, struct dm_bufio_client, shrinker); - if (sc->gfp_mask & __GFP_FS) - dm_bufio_lock(c); - else if (!dm_bufio_trylock(c)) - return 0; + struct dm_bufio_client *c = container_of(shrink, struct dm_bufio_client, shrinker); + unsigned long count = READ_ONCE(c->n_buffers[LIST_CLEAN]) + + READ_ONCE(c->n_buffers[LIST_DIRTY]); + unsigned long retain_target = get_retain_buffers(c); - count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY]; - retain_target = get_retain_buffers(c); - dm_bufio_unlock(c); return (count < retain_target) ? 0 : (count - retain_target); } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index eb419a502692e074df7ccb6722b2afb2da45618a..ea1bfc1a726f4a9c3e77de1d4ad01ae32ae5f1b9 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1384,6 +1384,8 @@ static void schedule_external_copy(struct thin_c *tc, dm_block_t virt_block, static void set_pool_mode(struct pool *pool, enum pool_mode new_mode); +static void requeue_bios(struct pool *pool); + static void check_for_space(struct pool *pool) { int r; @@ -1396,8 +1398,10 @@ static void check_for_space(struct pool *pool) if (r) return; - if (nr_free) + if (nr_free) { set_pool_mode(pool, PM_WRITE); + requeue_bios(pool); + } } /* @@ -1474,7 +1478,10 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result) r = dm_pool_alloc_data_block(pool->pmd, result); if (r) { - metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); + if (r == -ENOSPC) + set_pool_mode(pool, PM_OUT_OF_DATA_SPACE); + else + metadata_operation_failed(pool, "dm_pool_alloc_data_block", r); return r; } diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index d96aa84cacd23f992c7666aa4fc6fadba259071c..0a7a8287e58c15906112a4d694f29920d7530515 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -1049,6 +1049,14 @@ int verity_ctr(struct dm_target *ti, unsigned argc, char **argv) goto bad; } +#ifdef CONFIG_DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED + if (!v->validated_blocks) { + r = verity_alloc_most_once(v); + if (r) + goto bad; + } +#endif + v->hash_per_block_bits = __fls((1 << v->hash_dev_block_bits) / v->digest_size); diff --git a/drivers/md/md.c b/drivers/md/md.c index de0f8de995bd50de4b42ead8f5a93c8200b8639d..13b342446f46716cab1a5d424c837b5a2f11336e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2694,7 +2694,8 @@ state_store(struct md_rdev *rdev, const char *buf, size_t len) err = 0; } } else if (cmd_match(buf, "re-add")) { - if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1)) { + if (test_bit(Faulty, &rdev->flags) && (rdev->raid_disk == -1) && + rdev->saved_raid_disk >= 0) { /* clear_bit is performed _after_ all the devices * have their local Faulty bit cleared. If any writes * happen in the meantime in the local node, they @@ -8272,6 +8273,7 @@ static int remove_and_add_spares(struct mddev *mddev, if (mddev->pers->hot_remove_disk( mddev, rdev) == 0) { sysfs_unlink_rdev(mddev, rdev); + rdev->saved_raid_disk = rdev->raid_disk; rdev->raid_disk = -1; removed++; } diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 01511e5a5566643a32d03ba64fe314c299860ef6..2f054db8807be89152c54980c79b8b6d0e4c6245 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -251,8 +251,20 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, wake_up_interruptible (&events->wait_queue); } +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv, + struct dvb_fe_events *events) +{ + int ret; + + up(&fepriv->sem); + ret = events->eventw != events->eventr; + down(&fepriv->sem); + + return ret; +} + static int dvb_frontend_get_event(struct dvb_frontend *fe, - struct dvb_frontend_event *event, int flags) + struct dvb_frontend_event *event, int flags) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; @@ -270,13 +282,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, if (flags & O_NONBLOCK) return -EWOULDBLOCK; - up(&fepriv->sem); - - ret = wait_event_interruptible (events->wait_queue, - events->eventw != events->eventr); - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; + ret = wait_event_interruptible(events->wait_queue, + dvb_frontend_test_event(fepriv, events)); if (ret < 0) return ret; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index d558ed3e59c61b3f4a3fc105d5721a47d1d56ed1..cc5666050282950aa45b09168cede9984b8d4fd0 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -467,8 +467,13 @@ static void cx23885_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u32 clk_freq = 0; struct workqueue_struct *q; + /* cx23885 sets hostdata to clk_freq pointer */ + if (v4l2_get_subdev_hostdata(&state->sd)) + clk_freq = *((u32 *)v4l2_get_subdev_hostdata(&state->sd)); + /* * Come out of digital power down * The CX23888, at least, needs this, otherwise registers aside from @@ -504,8 +509,13 @@ static void cx23885_initialize(struct i2c_client *client) * 50.0 MHz * (0xb + 0xe8ba26/0x2000000)/4 = 5 * 28.636363 MHz * 572.73 MHz before post divide */ - /* HVR1850 or 50MHz xtal */ - cx25840_write(client, 0x2, 0x71); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25Mhz xtal */ + ; /* nothing to do */ + } else { + /* HVR1850 or 50MHz xtal */ + cx25840_write(client, 0x2, 0x71); + } cx25840_write4(client, 0x11c, 0x01d1744c); cx25840_write4(client, 0x118, 0x00000416); cx25840_write4(client, 0x404, 0x0010253e); @@ -548,9 +558,15 @@ static void cx23885_initialize(struct i2c_client *client) /* HVR1850 */ switch (state->id) { case CX23888_AV: - /* 888/HVR1250 specific */ - cx25840_write4(client, 0x10c, 0x13333333); - cx25840_write4(client, 0x108, 0x00000515); + if (clk_freq == 25000000) { + /* 888/ImpactVCBe or 25MHz xtal */ + cx25840_write4(client, 0x10c, 0x01b6db7b); + cx25840_write4(client, 0x108, 0x00000512); + } else { + /* 888/HVR1250 or 50MHz xtal */ + cx25840_write4(client, 0x10c, 0x13333333); + cx25840_write4(client, 0x108, 0x00000515); + } break; default: cx25840_write4(client, 0x10c, 0x002be2c9); @@ -580,7 +596,7 @@ static void cx23885_initialize(struct i2c_client *client) * 368.64 MHz before post divide * 122.88 MHz / 0xa = 12.288 MHz */ - /* HVR1850 or 50MHz xtal */ + /* HVR1850 or 50MHz xtal or 25MHz xtal */ cx25840_write4(client, 0x114, 0x017dbf48); cx25840_write4(client, 0x110, 0x000a030e); break; diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c index 29de3159e5a742be73da082b29ea4a7ed67fc197..cddbd8309ece7bd5b1736b4532cac5ccae87b92c 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_hw_core.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 @@ -1125,6 +1125,7 @@ static struct platform_driver cam_hw_cdm_driver = { .name = "msm_cam_cdm", .owner = THIS_MODULE, .of_match_table = msm_cam_hw_cdm_dt_match, + .suppress_bind_attrs = true, }, }; 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 fa98be2285b7072c610a831fddfb675496a7236c..e4ec08b415040bbd0f682bca74cc0d49e82ed290 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, 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 @@ -561,6 +561,7 @@ static struct platform_driver cam_cdm_intf_driver = { .name = "msm_cam_cdm_intf", .owner = THIS_MODULE, .of_match_table = msm_cam_cdm_intf_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c index c8b830ff82eaa5eba8c81cebe416a8d990888283..a97a51965ae3f0e5b931e6652e10f72d0838c56b 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.c +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.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 @@ -22,6 +22,14 @@ #define CAM_CDM_DWORD 4 +#define CAM_CDM_SW_CMD_COUNT 2 +#define CAM_CMD_LENGTH_MASK 0xFFFF +#define CAM_CDM_COMMAND_OFFSET 24 +#define CAM_CDM_REG_OFFSET_MASK 0x00FFFFFF + +#define CAM_CDM_DMI_DATA_HI_OFFSET 8 +#define CAM_CDM_DMI_DATA_LO_OFFSET 12 + static unsigned int CDMCmdHeaderSizes[ CAM_CDM_CMD_PRIVATE_BASE + CAM_CDM_SW_CMD_COUNT] = { 0, /* UNUSED*/ @@ -33,7 +41,7 @@ static unsigned int CDMCmdHeaderSizes[ 2, /* GenerateIRQ*/ 3, /* WaitForEvent*/ 1, /* ChangeBase*/ - 1, /* PERF_CONTINUOUSROL*/ + 1, /* PERF_CONTROL*/ 3, /* DMI32*/ 3, /* DMI64*/ }; @@ -540,3 +548,169 @@ int cam_cdm_util_cmd_buf_write(void __iomem **current_device_base, return ret; } + +static long cam_cdm_util_dump_dmi_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_DMI]; + CAM_INFO(CAM_CDM, "DMI"); + return ret; +} + +static long cam_cdm_util_dump_buff_indirect(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_BUFF_INDIRECT]; + CAM_INFO(CAM_CDM, "Buff Indirect"); + return ret; +} + +static long cam_cdm_util_dump_reg_cont_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_regcontinuous_cmd *p_regcont_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + int i = 0; + + p_regcont_cmd = (struct cdm_regcontinuous_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_CONT]; + + CAM_INFO(CAM_CDM, "REG_CONT: COUNT: %u OFFSET: 0x%X", + p_regcont_cmd->count, p_regcont_cmd->offset); + + for (i = 0; i < p_regcont_cmd->count; i++) { + CAM_INFO(CAM_CDM, "DATA_%d: 0x%X", i, + *temp_ptr); + temp_ptr++; + ret++; + } + + return ret; +} + +static long cam_cdm_util_dump_reg_random_cmd(uint32_t *cmd_buf_addr) +{ + struct cdm_regrandom_cmd *p_regrand_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + long ret = 0; + int i = 0; + + p_regrand_cmd = (struct cdm_regrandom_cmd *)temp_ptr; + temp_ptr += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_REG_RANDOM]; + + CAM_INFO(CAM_CDM, "REG_RAND: COUNT: %u", + p_regrand_cmd->count); + + for (i = 0; i < p_regrand_cmd->count; i++) { + CAM_INFO(CAM_CDM, "OFFSET_%d: 0x%X DATA_%d: 0x%X", + i, *temp_ptr & CAM_CDM_REG_OFFSET_MASK, i, + *(temp_ptr + 1)); + temp_ptr += 2; + ret += 2; + } + + return ret; +} + +static long cam_cdm_util_dump_gen_irq_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_GEN_IRQ]; + + CAM_INFO(CAM_CDM, "GEN_IRQ"); + + return ret; +} + +static long cam_cdm_util_dump_wait_event_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_WAIT_EVENT]; + + CAM_INFO(CAM_CDM, "WAIT_EVENT"); + + return ret; +} + +static long cam_cdm_util_dump_change_base_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + struct cdm_changebase_cmd *p_cbase_cmd; + uint32_t *temp_ptr = cmd_buf_addr; + + p_cbase_cmd = (struct cdm_changebase_cmd *)temp_ptr; + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_CHANGE_BASE]; + + CAM_INFO(CAM_CDM, "CHANGE_BASE: 0x%X", + p_cbase_cmd->base); + + return ret; +} + +static long cam_cdm_util_dump_perf_ctrl_cmd(uint32_t *cmd_buf_addr) +{ + long ret = 0; + + ret += CDMCmdHeaderSizes[CAM_CDM_CMD_PERF_CTRL]; + + CAM_INFO(CAM_CDM, "PERF_CTRL"); + + return ret; +} + +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buf_start, uint32_t *cmd_buf_end) +{ + uint32_t *buf_now = cmd_buf_start; + uint32_t cmd = 0; + + if (!cmd_buf_start || !cmd_buf_end) { + CAM_INFO(CAM_CDM, "Invalid args"); + return; + } + + do { + cmd = *buf_now; + cmd = cmd >> CAM_CDM_COMMAND_OFFSET; + + switch (cmd) { + case CAM_CDM_CMD_DMI: + case CAM_CDM_CMD_DMI_32: + case CAM_CDM_CMD_DMI_64: + buf_now += cam_cdm_util_dump_dmi_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_CONT: + buf_now += cam_cdm_util_dump_reg_cont_cmd(buf_now); + break; + case CAM_CDM_CMD_REG_RANDOM: + buf_now += cam_cdm_util_dump_reg_random_cmd(buf_now); + break; + case CAM_CDM_CMD_BUFF_INDIRECT: + buf_now += cam_cdm_util_dump_buff_indirect(buf_now); + break; + case CAM_CDM_CMD_GEN_IRQ: + buf_now += cam_cdm_util_dump_gen_irq_cmd(buf_now); + break; + case CAM_CDM_CMD_WAIT_EVENT: + buf_now += cam_cdm_util_dump_wait_event_cmd(buf_now); + break; + case CAM_CDM_CMD_CHANGE_BASE: + buf_now += cam_cdm_util_dump_change_base_cmd(buf_now); + break; + case CAM_CDM_CMD_PERF_CTRL: + buf_now += cam_cdm_util_dump_perf_ctrl_cmd(buf_now); + break; + default: + CAM_INFO(CAM_CDM, "Invalid CMD: 0x%x buf 0x%x", + cmd, *buf_now); + buf_now++; + break; + } + } while (buf_now <= cmd_buf_end); +} diff --git a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h index 09d0d638c987f0ad40e90ece21a33adc6332c65c..8f2b48853ca8a717017a1cc22a36e2922220971f 100644 --- a/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h +++ b/drivers/media/platform/msm/camera/cam_cdm/cam_cdm_util.h @@ -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 @@ -13,13 +13,6 @@ #ifndef _CAM_CDM_UTIL_H_ #define _CAM_CDM_UTIL_H_ -#define CAM_CDM_SW_CMD_COUNT 2 -#define CAM_CMD_LENGTH_MASK 0xFFFF -#define CAM_CDM_COMMAND_OFFSET 24 - -#define CAM_CDM_DMI_DATA_HI_OFFSET 8 -#define CAM_CDM_DMI_DATA_LO_OFFSET 12 - enum cam_cdm_command { CAM_CDM_CMD_UNUSED = 0x0, CAM_CDM_CMD_DMI = 0x1, @@ -158,4 +151,18 @@ void (*cdm_write_genirq)( uint32_t userdata); }; +/** + * cam_cdm_util_log_cmd_bufs() + * + * @brief: Util function to log cdm command buffers + * + * @cmd_buffer_start: Pointer to start of cmd buffer + * @cmd_buffer_end: Pointer to end of cmd buffer + * + */ +void cam_cdm_util_dump_cmd_buf( + uint32_t *cmd_buffer_start, uint32_t *cmd_buffer_end); + + + #endif /* _CAM_CDM_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera/cam_core/cam_context_utils.c index f167ef7ca5ff7ae52bbc7191035a1f7890bfb37f..fce7fc6cc6b86178747c76ce3db1db975bc939d3 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 @@ -91,10 +91,19 @@ int cam_context_buf_done_from_hw(struct cam_context *ctx, */ list_del_init(&req->list); spin_unlock(&ctx->lock); - if (!bubble_state) + if (!bubble_state) { result = CAM_SYNC_STATE_SIGNALED_SUCCESS; - else + } else { + CAM_DBG(CAM_REQ, + "[%s][ctx_id %d] : req[%llu] is done with error", + ctx->dev_name, ctx->ctx_id, req->request_id); + + for (j = 0; j < req->num_out_map_entries; j++) + CAM_DBG(CAM_REQ, "fence %d signaled with error", + req->out_map_entries[j].sync_id); + result = CAM_SYNC_STATE_SIGNALED_ERROR; + } for (j = 0; j < req->num_out_map_entries; j++) { cam_sync_signal(req->out_map_entries[j].sync_id, result); diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c index 90603de7e6d635b509b133be779af1beb25d6752..212065050d81a8f3a967209673eaa427ceb26ffc 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_hw.c @@ -594,11 +594,8 @@ static int cam_cpas_util_set_camnoc_axi_clk_rate( CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", required_camnoc_bw, clk_rate); - rc = cam_soc_util_set_clk_rate( - soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], - clk_rate); - if (!rc) + rc = cam_soc_util_set_src_clk_rate(soc_info, clk_rate); + if (rc) CAM_ERR(CAM_CPAS, "Failed in setting camnoc axi clk %llu %d %d", required_camnoc_bw, clk_rate, rc); @@ -736,7 +733,7 @@ static int cam_cpas_hw_update_axi_vote(struct cam_hw_info *cpas_hw, goto unlock_client; } - CAM_DBG(CAM_CPAS, + CAM_DBG(CAM_PERF, "Client=[%d][%s][%d] Requested compressed[%llu], uncompressed[%llu]", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, axi_vote.compressed_bw, @@ -898,7 +895,7 @@ static int cam_cpas_hw_update_ahb_vote(struct cam_hw_info *cpas_hw, goto unlock_client; } - CAM_DBG(CAM_CPAS, + CAM_DBG(CAM_PERF, "client=[%d][%s][%d] : type[%d], level[%d], freq[%ld], applied[%d]", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, ahb_vote.type, @@ -1212,17 +1209,26 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, rc = cam_common_util_get_string_index(soc_private->client_name, soc_private->num_clients, client_name, &client_indx); + + mutex_lock(&cpas_core->client_mutex[client_indx]); + if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) || CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { - CAM_ERR(CAM_CPAS, "Invalid Client register : %s %d, %d", + CAM_ERR(CAM_CPAS, + "Inval client %s %d : %d %d %pK %d", register_params->identifier, - register_params->cell_index, client_indx); + register_params->cell_index, + CAM_CPAS_CLIENT_VALID(client_indx), + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx), + cpas_core->cpas_client[client_indx], rc); + mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return -EPERM; } cpas_client = kzalloc(sizeof(struct cam_cpas_client), GFP_KERNEL); if (!cpas_client) { + mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return -ENOMEM; } @@ -1235,6 +1241,7 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, rc); kfree(cpas_client); + mutex_unlock(&cpas_core->client_mutex[client_indx]); mutex_unlock(&cpas_hw->hw_mutex); return -EINVAL; } @@ -1246,12 +1253,13 @@ static int cam_cpas_hw_register_client(struct cam_hw_info *cpas_hw, cpas_core->cpas_client[client_indx] = cpas_client; cpas_core->registered_clients++; - mutex_unlock(&cpas_hw->hw_mutex); - CAM_DBG(CAM_CPAS, "client=[%d][%s][%d], registered_clients=%d", client_indx, cpas_client->data.identifier, cpas_client->data.cell_index, cpas_core->registered_clients); + mutex_unlock(&cpas_core->client_mutex[client_indx]); + mutex_unlock(&cpas_hw->hw_mutex); + return 0; } @@ -1498,27 +1506,6 @@ static int cam_cpas_util_get_internal_ops(struct platform_device *pdev, return rc; } -static int cam_cpas_util_get_hw_version(struct platform_device *pdev, - struct cam_hw_soc_info *soc_info) -{ - struct device_node *of_node = pdev->dev.of_node; - int rc; - - soc_info->hw_version = 0; - - rc = of_property_read_u32(of_node, - "qcom,cpas-hw-ver", &soc_info->hw_version); - - CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); - - if (rc) { - CAM_ERR(CAM_CPAS, "failed to get CPAS HW Version rc=%d", rc); - return -EINVAL; - } - - return rc; -} - int cam_cpas_hw_probe(struct platform_device *pdev, struct cam_hw_intf **hw_intf) { @@ -1661,10 +1648,6 @@ int cam_cpas_hw_probe(struct platform_device *pdev, if (rc) goto axi_cleanup; - rc = cam_cpas_util_get_hw_version(pdev, &cpas_hw->soc_info); - if (rc) - goto axi_cleanup; - *hw_intf = cpas_hw_intf; return 0; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c index 0187a6400275c91fc82659f50bcc95f1a9abd9f6..cdc8a3baef28cd4d32e1c356c282a5287f6e0795 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_intf.c @@ -619,6 +619,7 @@ static int cam_cpas_dev_remove(struct platform_device *dev) } mutex_lock(&g_cpas_intf->intf_lock); + g_cpas_intf->probe_done = false; cam_unregister_subdev(&g_cpas_intf->subdev); cam_cpas_hw_remove(g_cpas_intf->hw_intf); mutex_unlock(&g_cpas_intf->intf_lock); @@ -641,6 +642,7 @@ static struct platform_driver cam_cpas_driver = { .name = CAM_CPAS_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_cpas_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c index b73b32a99d32a59d3e00ad9b4c3e103373feaf8e..83cd326b0ecdbf50d234f04e47713ce1a65fe496 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.c @@ -44,18 +44,6 @@ int cam_cpas_get_custom_dt_info(struct platform_device *pdev, return rc; } - - soc_private->hw_version = 0; - rc = of_property_read_u32(of_node, - "qcom,cpas-hw-ver", &soc_private->hw_version); - if (rc) { - CAM_ERR(CAM_CPAS, "device %s failed to read cpas-hw-ver", - pdev->name); - return rc; - } - - CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_private->hw_version); - soc_private->camnoc_axi_min_ib_bw = 0; rc = of_property_read_u64(of_node, "camnoc-axi-min-ib-bw", diff --git a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h index f6ae8a826c9360c2c174f8b0f84269990d99c95a..7f50d123a4e043e0a1562a3c10a5590533ab452e 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h +++ b/drivers/media/platform/msm/camera/cam_cpas/cam_cpas_soc.h @@ -33,7 +33,6 @@ struct cam_cpas_vdd_ahb_mapping { * struct cam_cpas_private_soc : CPAS private DT info * * @arch_compat: ARCH compatible string - * @hw_version: Camera HW version * @client_id_based: Whether clients are id based * @num_clients: Number of clients supported * @client_name: Client names @@ -53,7 +52,6 @@ struct cam_cpas_vdd_ahb_mapping { */ struct cam_cpas_private_soc { const char *arch_compat; - uint32_t hw_version; bool client_id_based; uint32_t num_clients; const char *client_name[CAM_CPAS_MAX_CLIENTS]; diff --git a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c index 158bbb98a83a362a0d319e8c0cff975011685339..f8687cf555a343667070403841f6ed61b233dd13 100644 --- a/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c +++ b/drivers/media/platform/msm/camera/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -76,6 +76,38 @@ static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw, hw_caps->cpas_version.major, hw_caps->cpas_version.minor, hw_caps->cpas_version.incr, hw_caps->camera_capability); + soc_info->hw_version = CAM_CPAS_TITAN_NONE; + + if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 0)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 1) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V110; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 2) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_170_V120; + } else if ((hw_caps->camera_version.major == 1) && + (hw_caps->camera_version.minor == 7) && + (hw_caps->camera_version.incr == 5)) { + if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 0)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V100; + else if ((hw_caps->cpas_version.major == 1) && + (hw_caps->cpas_version.minor == 0) && + (hw_caps->cpas_version.incr == 1)) + soc_info->hw_version = CAM_CPAS_TITAN_175_V101; + } + + CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); + return 0; } @@ -583,12 +615,11 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, struct cam_cpas_hw_caps *hw_caps) { int rc = 0; - struct cam_cpas_private_soc *soc_private = - (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info; CAM_DBG(CAM_CPAS, "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d", - soc_private->hw_version, + soc_info->hw_version, hw_caps->camera_version.major, hw_caps->camera_version.minor, hw_caps->camera_version.incr, @@ -596,7 +627,7 @@ static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw, hw_caps->cpas_version.minor, hw_caps->cpas_version.incr); - switch (soc_private->hw_version) { + switch (soc_info->hw_version) { case CAM_CPAS_TITAN_170_V100: camnoc_info = &cam170_cpas100_camnoc_info; break; diff --git a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c index 3f0124436b9e1baed2b1c575ad745db56dff7466..d5068ca26971bb7b57af98358530fc6d2e3b16ba 100644 --- a/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/cam_fd_dev.c @@ -194,6 +194,7 @@ static struct platform_driver cam_fd_driver = { .name = "cam_fd", .owner = THIS_MODULE, .of_match_table = cam_fd_dt_match, + .suppress_bind_attrs = true, }, }; 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 a15ccdcf2dcc1489f61126ef5c174eafaa1b9270..d3c39f940f0510fbba0ab263c41f25f93b780c0f 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, 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 @@ -1884,7 +1884,7 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, } rc = cam_req_mgr_workq_create("cam_fd_worker", CAM_FD_WORKQ_NUM_TASK, - &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ); + &g_fd_hw_mgr.work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_FD, "Unable to create a worker, rc=%d", rc); goto detach_smmu; diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c index a18afc6d7acc8a3b6294f8e4266571297d603454..87dc6949de0ca6fe6ba9613bec4b608b24ac6f7b 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -532,7 +532,7 @@ irqreturn_t cam_fd_hw_irq(int irq_num, void *data) if (!fd_hw) { CAM_ERR(CAM_FD, "Invalid data in IRQ callback"); - return -EINVAL; + return IRQ_NONE; } fd_core = (struct cam_fd_core *) fd_hw->core_info; @@ -570,7 +570,7 @@ irqreturn_t cam_fd_hw_irq(int irq_num, void *data) CAM_ERR(CAM_FD, "Invalid number of IRQs, value=0x%x, num_irqs=%d", reg_value, num_irqs); - return -EINVAL; + return IRQ_NONE; } trace_cam_irq_activated("FD", irq_type); diff --git a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c index 6d9d330f783882f0dc3cf5ac1eed9a2339ea5eb5..c7ef37c65659fc38afa4d62dcda52085251751d7 100644 --- a/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -24,6 +24,8 @@ #include "cam_fd_hw_v41.h" #include "cam_fd_hw_v501.h" +static char fd_dev_name[8]; + static int cam_fd_hw_dev_probe(struct platform_device *pdev) { struct cam_hw_info *fd_hw; @@ -32,6 +34,7 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) const struct of_device_id *match_dev = NULL; struct cam_fd_hw_static_info *hw_static_info = NULL; int rc = 0; + uint32_t hw_idx; struct cam_fd_hw_init_args init_args; struct cam_fd_hw_deinit_args deinit_args; @@ -51,14 +54,21 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) kfree(fd_hw_intf); return -ENOMEM; } + of_property_read_u32(pdev->dev.of_node, + "cell-index", &hw_idx); fd_hw_intf->hw_priv = fd_hw; fd_hw->core_info = fd_core; + fd_hw_intf->hw_idx = hw_idx; + + memset(fd_dev_name, 0, sizeof(fd_dev_name)); + snprintf(fd_dev_name, sizeof(fd_dev_name), + "fd%1u", fd_hw_intf->hw_idx); fd_hw->hw_state = CAM_HW_STATE_POWER_DOWN; fd_hw->soc_info.pdev = pdev; fd_hw->soc_info.dev = &pdev->dev; - fd_hw->soc_info.dev_name = pdev->name; + fd_hw->soc_info.dev_name = fd_dev_name; fd_hw->open_count = 0; mutex_init(&fd_hw->hw_mutex); spin_lock_init(&fd_hw->hw_lock); @@ -104,8 +114,6 @@ static int cam_fd_hw_dev_probe(struct platform_device *pdev) goto free_memory; } - fd_hw_intf->hw_idx = fd_hw->soc_info.index; - memset(&init_args, 0x0, sizeof(init_args)); memset(&deinit_args, 0x0, sizeof(deinit_args)); rc = cam_fd_hw_init(fd_hw, &init_args, sizeof(init_args)); @@ -209,6 +217,7 @@ static struct platform_driver cam_fd_hw_driver = { .name = "cam_fd_hw", .owner = THIS_MODULE, .of_match_table = cam_fd_hw_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c index 4f91f734e989755b0c557f4601ca2d168c99a836..7df806b1b7a30c4a2d2703e9d314e48f7468d7e8 100644 --- a/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c +++ b/drivers/media/platform/msm/camera/cam_icp/cam_icp_subdev.c @@ -236,6 +236,7 @@ static struct platform_driver cam_icp_driver = { .name = "cam_icp", .owner = THIS_MODULE, .of_match_table = cam_icp_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h index 2c364e0181e6a3709c66e997dad58d1a7aed4c9b..3e636c65138d5746f0ae82e0cf1e1955b8b1d9a1 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h @@ -35,6 +35,7 @@ struct hfi_mem { * @cmd_q: command queue hfi memory for host to firmware communication * @msg_q: message queue hfi memory for firmware to host communication * @dbg_q: debug queue hfi memory for firmware debug information + * @sfr_buf: buffer for subsystem failure reason[SFR] * @sec_heap: secondary heap hfi memory for firmware * @qdss: qdss mapped memory for fw * @icp_base: icp base address @@ -44,6 +45,7 @@ struct hfi_mem_info { struct hfi_mem cmd_q; struct hfi_mem msg_q; struct hfi_mem dbg_q; + struct hfi_mem sfr_buf; struct hfi_mem sec_heap; struct hfi_mem shmem; struct hfi_mem qdss; @@ -153,4 +155,10 @@ int hfi_cmd_ubwc_config(uint32_t *ubwc_cfg); int cam_hfi_resume(struct hfi_mem_info *hfi_mem, void __iomem *icp_base, bool debug); +/** + * cam_hfi_queue_dump() - utility function to dump hfi queues + */ +void cam_hfi_queue_dump(void); + + #endif /* _HFI_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h index 2153ceacbb83c76e08301d7f233c9518fe7ada6d..f652cfa3d2a33ac438b670fc01e08ef9ea6bcce6 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_reg.h @@ -43,6 +43,7 @@ #define HFI_REG_UNCACHED_HEAP_SIZE 0x60 #define HFI_REG_QDSS_IOVA 0x6C #define HFI_REG_QDSS_IOVA_SIZE 0x70 +#define HFI_REG_SFR_PTR 0x68 /* end of ICP CSR registers */ /* flags for ICP CSR registers */ @@ -72,6 +73,7 @@ #define ICP_CMD_Q_SIZE_IN_BYTES 4096 #define ICP_MSG_Q_SIZE_IN_BYTES 4096 #define ICP_DBG_Q_SIZE_IN_BYTES 102400 +#define ICP_MSG_SFR_SIZE_IN_BYTES 4096 #define ICP_SHARED_MEM_IN_BYTES (1024 * 1024) #define ICP_UNCACHED_HEAP_SIZE_IN_BYTES (2 * 1024 * 1024) @@ -128,10 +130,14 @@ enum reg_settings { /** * @INTR_DISABLE: Disable interrupt * @INTR_ENABLE: Enable interrupt + * @INTR_ENABLE_WD0: Enable WD0 + * @INTR_ENABLE_WD1: Enable WD1 */ enum intr_status { INTR_DISABLE, - INTR_ENABLE + INTR_ENABLE, + INTR_ENABLE_WD0, + INTR_ENABLE_WD1 = 0x4 }; /** @@ -285,6 +291,16 @@ struct hfi_q_hdr { uint32_t dummy14[15]; }; +/** + * struct sfr_buf + * @size: Number of characters + * @msg : Subsystem failure reason + */ +struct sfr_buf { + uint32_t size; + char msg[ICP_MSG_SFR_SIZE_IN_BYTES]; +}; + /** * struct hfi_q_tbl * @q_tbl_hdr: Queue table header diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index a0752f596c9647396baf18e483f6ee9fc9b91097..14a3e656e76dfc89ea7a5b7103d2581512ccb522 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -47,6 +47,49 @@ unsigned int g_icp_mmu_hdl; static DEFINE_MUTEX(hfi_cmd_q_mutex); static DEFINE_MUTEX(hfi_msg_q_mutex); +void cam_hfi_queue_dump(void) +{ + struct hfi_qtbl *qtbl; + struct hfi_qtbl_hdr *qtbl_hdr; + struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr; + struct hfi_mem_info *hfi_mem = NULL; + uint32_t *read_q, *read_ptr; + int i; + + hfi_mem = &g_hfi->map; + if (!hfi_mem) { + CAM_ERR(CAM_HFI, "Unable to dump queues hfi memory is NULL"); + return; + } + + qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva; + qtbl_hdr = &qtbl->q_tbl_hdr; + CAM_INFO(CAM_HFI, + "qtbl: version = %x size = %u num q = %u qhdr_size = %u", + qtbl_hdr->qtbl_version, qtbl_hdr->qtbl_size, + qtbl_hdr->qtbl_num_q, qtbl_hdr->qtbl_qhdr_size); + + cmd_q_hdr = &qtbl->q_hdr[Q_CMD]; + CAM_INFO(CAM_HFI, "cmd: size = %u r_idx = %u w_idx = %u addr = %x", + cmd_q_hdr->qhdr_q_size, cmd_q_hdr->qhdr_read_idx, + cmd_q_hdr->qhdr_write_idx, hfi_mem->cmd_q.iova); + read_q = (uint32_t *)g_hfi->map.cmd_q.kva; + read_ptr = (uint32_t *)(read_q + 0); + CAM_INFO(CAM_HFI, "CMD Q START"); + for (i = 0; i < ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) + CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); + + msg_q_hdr = &qtbl->q_hdr[Q_MSG]; + CAM_INFO(CAM_HFI, "msg: size = %u r_idx = %u w_idx = %u addr = %x", + msg_q_hdr->qhdr_q_size, msg_q_hdr->qhdr_read_idx, + msg_q_hdr->qhdr_write_idx, hfi_mem->msg_q.iova); + read_q = (uint32_t *)g_hfi->map.msg_q.kva; + read_ptr = (uint32_t *)(read_q + 0); + CAM_INFO(CAM_HFI, "MSG Q START"); + for (i = 0; i < ICP_MSG_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT; i++) + CAM_INFO(CAM_HFI, "Word: %d Data: 0x%08x ", i, read_ptr[i]); +} + int hfi_write_cmd(void *cmd_ptr) { uint32_t size_in_words, empty_space, new_write_idx, read_idx, temp; @@ -92,7 +135,8 @@ int hfi_write_cmd(void *cmd_ptr) (q->qhdr_q_size - (q->qhdr_write_idx - read_idx)) : (read_idx - q->qhdr_write_idx); if (empty_space <= size_in_words) { - CAM_ERR(CAM_HFI, "failed"); + CAM_ERR(CAM_HFI, "failed: empty space %u, size_in_words %u", + empty_space, size_in_words); rc = -EIO; goto err; } @@ -556,7 +600,7 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, return -EINVAL; } - cam_io_w_mb((uint32_t)INTR_ENABLE, + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION); @@ -566,6 +610,8 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem, CAM_DBG(CAM_HFI, "wfi status = %x", (int)data); cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, icp_base + HFI_REG_SHARED_MEM_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.len, @@ -591,6 +637,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr; uint32_t hw_version, soc_version, fw_version, status = 0; uint32_t retry_cnt = 0; + struct sfr_buf *sfr_buffer; mutex_lock(&hfi_cmd_q_mutex); mutex_lock(&hfi_msg_q_mutex); @@ -672,6 +719,9 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, dbg_q_hdr->qhdr_read_idx = RESET; dbg_q_hdr->qhdr_write_idx = RESET; + sfr_buffer = (struct sfr_buf *)hfi_mem->sfr_buf.kva; + sfr_buffer->size = ICP_MSG_SFR_SIZE_IN_BYTES; + switch (event_driven_mode) { case INTR_MODE: cmd_q_hdr->qhdr_type = Q_CMD; @@ -744,7 +794,10 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, break; } - cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, + icp_base + HFI_REG_QTBL_PTR); + cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova, + icp_base + HFI_REG_SFR_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.iova, icp_base + HFI_REG_SHARED_MEM_PTR); cam_io_w_mb((uint32_t)hfi_mem->shmem.len, @@ -801,7 +854,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem, g_hfi->hfi_state = HFI_READY; g_hfi->cmd_q_state = true; g_hfi->msg_q_state = true; - cam_io_w_mb((uint32_t)INTR_ENABLE, + cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0), icp_base + HFI_REG_A5_CSR_A2HOSTINTEN); mutex_unlock(&hfi_cmd_q_mutex); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h index 4aa6b4bd570eda048146556c8ddb39894432af15..f4bc813353a8ede7c71229605d3630163148a1d7 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_core.h @@ -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 @@ -25,8 +25,8 @@ #define A5_CSR_BASE 2 #define A5_HOST_INT 0x1 -#define A5_WDT_0 0x10 -#define A5_WDT_1 0x100 +#define A5_WDT_0 0x2 +#define A5_WDT_1 0x4 #define ELF_GUARD_PAGE (2 * 1024 * 1024) diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c index 14c3c9c5815b62d044bfbb5120d797b1d6c99b5e..3b652e72466e870502af8c5bcf03afbb68218010 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/a5_hw/a5_dev.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 @@ -215,6 +215,7 @@ static struct platform_driver cam_a5_driver = { .name = "cam-a5", .owner = THIS_MODULE, .of_match_table = cam_a5_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c index 5bd7f1c91729ff89616f74ba0b685ec0ade8eaa1..d01637436a51a312fcb5f602c4287fab9927fba2 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_core.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 @@ -18,6 +18,7 @@ #include #include #include +#include #include "cam_io_util.h" #include "cam_hw.h" #include "cam_hw_intf.h" @@ -30,6 +31,9 @@ #include "cam_icp_hw_mgr_intf.h" #include "cam_cpas_api.h" #include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info, struct cam_icp_cpas_vote *cpas_vote) @@ -210,6 +214,77 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev) return rc; } +static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_bps_device_core_info *core_info) +{ + uint32_t retry_cnt = 0; + uint32_t status = 0; + int pwr_ctrl, pwr_status, rc = 0; + bool reset_bps_cdm_fail = false; + bool reset_bps_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET"); + /* Reset BPS CDM core*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_cdm_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_CDM_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS CDM rst failed status 0x%x", status); + reset_bps_cdm_fail = true; + } + + /* Reset BPS core*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + BPS_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS), + status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_ICP, "bps_top_irq_status = %u", status); + + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + BPS_TOP_IRQ_STATUS); + if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "BPS top rst failed status 0x%x", status); + reset_bps_top_fail = true; + } + + cam_bps_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After) pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_bps_cdm_fail || reset_bps_top_fail) + rc = -EAGAIN; + + return rc; +} + int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -311,7 +386,12 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type, cam_bps_toggle_clk(soc_info, false); core_info->clk_enable = false; break; + case CAM_ICP_BPS_CMD_RESET: + rc = cam_bps_cmd_reset(soc_info, core_info); + break; default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; break; } return rc; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c index feb0bd899d877262970c5edfdf591f164c193e31..56abb4b8e6e902a51060991dd1be73c95d87fc4b 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_dev.c @@ -33,6 +33,8 @@ static struct cam_bps_device_hw_info cam_bps_hw_info = { }; EXPORT_SYMBOL(cam_bps_hw_info); +static char bps_dev_name[8]; + static bool cam_bps_cpas_cb(uint32_t client_handle, void *userdata, struct cam_cpas_irq_data *irq_data) { @@ -111,9 +113,14 @@ int cam_bps_probe(struct platform_device *pdev) kfree(bps_dev_intf); return -ENOMEM; } + + memset(bps_dev_name, 0, sizeof(bps_dev_name)); + snprintf(bps_dev_name, sizeof(bps_dev_name), + "bps%1u", bps_dev_intf->hw_idx); + bps_dev->soc_info.pdev = pdev; bps_dev->soc_info.dev = &pdev->dev; - bps_dev->soc_info.dev_name = pdev->name; + bps_dev->soc_info.dev_name = bps_dev_name; bps_dev_intf->hw_priv = bps_dev; bps_dev_intf->hw_ops.init = cam_bps_init_hw; bps_dev_intf->hw_ops.deinit = cam_bps_deinit_hw; @@ -187,6 +194,7 @@ static struct platform_driver cam_bps_driver = { .name = "cam-bps", .owner = THIS_MODULE, .of_match_table = cam_bps_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c index d2314c4fd89f3404a55ee2662cbecdf9f2e716f0..1da99a4d960d7f9dd748f905c04f63bcc782ac03 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -154,8 +154,7 @@ int cam_bps_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); } int cam_bps_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) 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 16e97ea1f8133adbaa6dbbe55ada288f3963c9ca..d32d4b69938f709f588b1f12ab71fda74c944308 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 @@ -995,6 +995,8 @@ static int cam_icp_update_clk_rate(struct cam_icp_hw_mgr *hw_mgr, id = CAM_ICP_IPE_CMD_UPDATE_CLK; } + CAM_DBG(CAM_PERF, "clk_rate %u for dev_type %d", curr_clk_rate, + ctx_data->icp_dev_acquire_info->dev_type); clk_upd_cmd.curr_clk_rate = curr_clk_rate; clk_upd_cmd.ipe_bps_pc_enable = icp_hw_mgr.ipe_bps_pc_flag; @@ -1058,6 +1060,10 @@ static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, * anyway. */ + CAM_DBG(CAM_ICP, "compress_bw %llu uncompress_bw %llu dev_type %d", + clk_info->compressed_bw, clk_info->uncompressed_bw, + ctx_data->icp_dev_acquire_info->dev_type); + return 0; } @@ -1179,7 +1185,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, if (hw_mgr->bps_ctxt_cnt) goto end; - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { rc = bps_dev_intf->hw_ops.process_cmd( bps_dev_intf->hw_priv, CAM_ICP_BPS_CMD_POWER_COLLAPSE, @@ -1201,11 +1207,10 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, if (hw_mgr->ipe_ctxt_cnt) goto end; - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { rc = ipe0_dev_intf->hw_ops.process_cmd( ipe0_dev_intf->hw_priv, CAM_ICP_IPE_CMD_POWER_COLLAPSE, NULL, 0); - } if (hw_mgr->ipe_clk_state) @@ -1213,7 +1218,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, ipe0_dev_intf->hw_priv, NULL, 0); if (ipe1_dev_intf) { - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { rc = ipe1_dev_intf->hw_ops.process_cmd( ipe1_dev_intf->hw_priv, CAM_ICP_IPE_CMD_POWER_COLLAPSE, @@ -1226,7 +1231,7 @@ static int cam_icp_mgr_ipe_bps_power_collapse(struct cam_icp_hw_mgr *hw_mgr, } hw_mgr->ipe_clk_state = false; - if (icp_hw_mgr.ipe_bps_pc_flag) { + if (icp_hw_mgr.ipe_bps_pc_flag && !hw_mgr->recovery) { hw_mgr->core_info = hw_mgr->core_info & (~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1)); } @@ -1317,7 +1322,6 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) rc = -ENOMEM; goto err; } - icp_hw_mgr.icp_pc_flag = false; if (!debugfs_create_bool("ipe_bps_pc", 0644, @@ -1328,8 +1332,6 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) goto err; } - icp_hw_mgr.ipe_bps_pc_flag = false; - if (!debugfs_create_file("icp_debug_clk", 0644, icp_hw_mgr.dentry, NULL, @@ -1377,6 +1379,7 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) return rc; err: debugfs_remove_recursive(icp_hw_mgr.dentry); + icp_hw_mgr.dentry = NULL; return rc; } @@ -1456,8 +1459,10 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag) CAM_ERR(CAM_ICP, "Invalid Context"); return -EINVAL; } - CAM_DBG(CAM_ICP, "ctx : %pK, request_id :%lld", - (void *)ctx_data->context_priv, request_id); + CAM_DBG(CAM_REQ, + "ctx_id : %u, request_id :%lld dev_type: %d", + ctx_data->ctx_id, request_id, + ctx_data->icp_dev_acquire_info->dev_type); mutex_lock(&ctx_data->ctx_mutex); cam_icp_ctx_timer_reset(ctx_data); @@ -1718,11 +1723,121 @@ static int cam_icp_mgr_process_direct_ack_msg(uint32_t *msg_ptr) return rc; } +static int cam_icp_ipebps_reset(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + struct cam_hw_intf *ipe0_dev_intf; + struct cam_hw_intf *ipe1_dev_intf; + struct cam_hw_intf *bps_dev_intf; + + ipe0_dev_intf = hw_mgr->ipe0_dev_intf; + ipe1_dev_intf = hw_mgr->ipe1_dev_intf; + bps_dev_intf = hw_mgr->bps_dev_intf; + + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "bps reset failed"); + + rc = ipe0_dev_intf->hw_ops.process_cmd( + ipe0_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe0 reset failed"); + + if (ipe1_dev_intf) { + rc = ipe1_dev_intf->hw_ops.process_cmd( + ipe1_dev_intf->hw_priv, + CAM_ICP_IPE_CMD_RESET, + NULL, 0); + if (rc) + CAM_ERR(CAM_ICP, "ipe1 reset failed"); + } + + return 0; +} + +static int cam_icp_mgr_trigger_recovery(struct cam_icp_hw_mgr *hw_mgr) +{ + int rc = 0; + int i = 0; + struct sfr_buf *sfr_buffer = NULL; + + CAM_DBG(CAM_ICP, "Enter"); + + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (hw_mgr->recovery) { + CAM_ERR(CAM_ICP, "Recovery is set"); + mutex_unlock(&hw_mgr->hw_mgr_mutex); + return rc; + } + + sfr_buffer = (struct sfr_buf *)icp_hw_mgr.hfi_mem.sfr_buf.kva; + CAM_WARN(CAM_ICP, "SFR:%s", sfr_buffer->msg); + + cam_icp_ipebps_reset(hw_mgr); + + hw_mgr->recovery = true; + + if (hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_BPS].watch_dog = NULL; + } + if (hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog) { + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog_reset_counter = 0; + crm_timer_exit(&hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog); + hw_mgr->clk_info[ICP_CLK_HW_IPE].watch_dog = NULL; + } + + for (i = 0; i < CAM_ICP_CTX_MAX; i++) { + mutex_lock(&hw_mgr->ctx_data[i].ctx_mutex); + if (hw_mgr->ctx_data[i].state != CAM_ICP_CTX_STATE_RELEASE) + cam_icp_ctx_timer_stop(&hw_mgr->ctx_data[i]); + mutex_unlock(&hw_mgr->ctx_data[i].ctx_mutex); + } + + mutex_unlock(&hw_mgr->hw_mgr_mutex); + + CAM_DBG(CAM_ICP, "Done"); + return rc; +} +static int cam_icp_mgr_process_fatal_error( + struct cam_icp_hw_mgr *hw_mgr, uint32_t *msg_ptr) +{ + struct hfi_msg_event_notify *event_notify; + int rc = 0; + + CAM_DBG(CAM_ICP, "Enter"); + + event_notify = (struct hfi_msg_event_notify *)msg_ptr; + if (!event_notify) { + CAM_ERR(CAM_ICP, "Empty event message"); + return -EINVAL; + } + + CAM_DBG(CAM_ICP, "evt_id: %u evt_data1: %u evt_data2: %u", + event_notify->event_id, + event_notify->event_data1, + event_notify->event_data2); + + if (event_notify->event_id == HFI_EVENT_SYS_ERROR) { + CAM_INFO(CAM_ICP, "received HFI_EVENT_SYS_ERROR"); + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + } + + return rc; +} + static void cam_icp_mgr_process_dbg_buf(void) { uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; struct hfi_msg_debug *dbg_msg; uint32_t read_len, size_processed = 0; + uint64_t timestamp = 0; char *dbg_buf; int rc = 0; @@ -1736,7 +1851,9 @@ static void cam_icp_mgr_process_dbg_buf(void) if (pkt_ptr[ICP_PACKET_TYPE] == HFI_MSG_SYS_DEBUG) { dbg_msg = (struct hfi_msg_debug *)pkt_ptr; dbg_buf = (char *)&dbg_msg->msg_data; - trace_cam_icp_fw_dbg(dbg_buf); + timestamp = ((((uint64_t)(dbg_msg->timestamp_hi) << 32) + | dbg_msg->timestamp_lo) >> 16); + trace_cam_icp_fw_dbg(dbg_buf, timestamp/2); } size_processed += (pkt_ptr[ICP_PACKET_SIZE] >> BYTE_WORD_SHIFT); @@ -1802,6 +1919,10 @@ static int cam_icp_process_msg_pkt_type( CAM_DBG(CAM_ICP, "received EVENT_NOTIFY"); size_processed = ( (struct hfi_msg_event_notify *)msg_ptr)->size; + rc = cam_icp_mgr_process_fatal_error(hw_mgr, msg_ptr); + if (rc) + CAM_ERR(CAM_ICP, "failed in processing evt notify"); + break; default: @@ -1833,7 +1954,7 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data) rc = hfi_read_message(icp_hw_mgr.msg_buf, Q_MSG, &read_len); if (rc) { - CAM_DBG(CAM_ICP, "Unable to read msg q"); + CAM_DBG(CAM_ICP, "Unable to read msg q rc %d", rc); } else { read_len = read_len << BYTE_WORD_SHIFT; msg_ptr = (uint32_t *)icp_hw_mgr.msg_buf; @@ -1862,6 +1983,13 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data) HFI_DEBUG_MODE_QUEUE) cam_icp_mgr_process_dbg_buf(); + if ((task_data->irq_status & A5_WDT_0) || + (task_data->irq_status & A5_WDT_1)) { + CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5"); + + rc = cam_icp_mgr_trigger_recovery(hw_mgr); + } + return rc; } @@ -1906,6 +2034,7 @@ static void cam_icp_free_hfi_mem(void) cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.cmd_q); cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); } static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap) @@ -1945,6 +2074,31 @@ static int cam_icp_alloc_secheap_mem(struct cam_mem_mgr_memory_desc *secheap) return rc; } +static int cam_icp_alloc_sfr_mem(struct cam_mem_mgr_memory_desc *sfr) +{ + int rc; + struct cam_mem_mgr_request_desc alloc; + struct cam_mem_mgr_memory_desc out; + + memset(&alloc, 0, sizeof(alloc)); + memset(&out, 0, sizeof(out)); + alloc.size = SZ_8K; + alloc.align = 0; + alloc.flags = CAM_MEM_FLAG_HW_READ_WRITE | + CAM_MEM_FLAG_HW_SHARED_ACCESS; + + alloc.smmu_hdl = icp_hw_mgr.iommu_hdl; + rc = cam_mem_mgr_request_mem(&alloc, &out); + if (rc) + return rc; + + *sfr = out; + CAM_DBG(CAM_ICP, "kva: %llX, iova: %x, hdl: %x, len: %lld", + out.kva, out.iova, out.mem_handle, out.len); + + return rc; +} + static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl) { int rc; @@ -2060,6 +2214,12 @@ static int cam_icp_allocate_hfi_mem(void) goto dbg_q_alloc_failed; } + rc = cam_icp_alloc_sfr_mem(&icp_hw_mgr.hfi_mem.sfr_buf); + if (rc) { + CAM_ERR(CAM_ICP, "Unable to allocate sfr buffer"); + goto sfr_buf_alloc_failed; + } + rc = cam_icp_alloc_secheap_mem(&icp_hw_mgr.hfi_mem.sec_heap); if (rc) { CAM_ERR(CAM_ICP, "Unable to allocate sec heap memory"); @@ -2068,6 +2228,8 @@ static int cam_icp_allocate_hfi_mem(void) return rc; sec_heap_alloc_failed: + cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.sfr_buf); +sfr_buf_alloc_failed: cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.dbg_q); dbg_q_alloc_failed: cam_mem_mgr_release_mem(&icp_hw_mgr.hfi_mem.msg_q); @@ -2172,6 +2334,7 @@ static int cam_icp_mgr_hw_close_u(void *hw_priv, void *hw_close_args) struct cam_icp_hw_mgr *hw_mgr = hw_priv; int rc = 0; + CAM_DBG(CAM_ICP, "UMD calls close"); if (!hw_mgr) { CAM_ERR(CAM_ICP, "Null hw mgr"); return 0; @@ -2188,6 +2351,7 @@ static int cam_icp_mgr_hw_close_k(void *hw_priv, void *hw_close_args) { struct cam_icp_hw_mgr *hw_mgr = hw_priv; + CAM_DBG(CAM_ICP, "KMD calls close"); if (!hw_mgr) { CAM_ERR(CAM_ICP, "Null hw mgr"); return 0; @@ -2212,11 +2376,12 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr) } a5_dev = (struct cam_hw_info *)a5_dev_intf->hw_priv; - if (!hw_mgr->icp_pc_flag) { + if (!hw_mgr->icp_pc_flag || hw_mgr->recovery) { cam_hfi_disable_cpu( a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); rc = cam_icp_mgr_hw_close_k(hw_mgr, NULL); } else { + CAM_DBG(CAM_PERF, "Sending PC prep ICP PC enabled"); rc = cam_icp_mgr_send_pc_prep(hw_mgr); cam_hfi_disable_cpu( a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base); @@ -2243,27 +2408,34 @@ static int cam_icp_mgr_hfi_resume(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.qtbl.kva = icp_hw_mgr.hfi_mem.qtbl.kva; hfi_mem.qtbl.iova = icp_hw_mgr.hfi_mem.qtbl.iova; hfi_mem.qtbl.len = icp_hw_mgr.hfi_mem.qtbl.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "qtbl kva = %llX IOVA = %X length = %lld\n", hfi_mem.qtbl.kva, hfi_mem.qtbl.iova, hfi_mem.qtbl.len); hfi_mem.cmd_q.kva = icp_hw_mgr.hfi_mem.cmd_q.kva; hfi_mem.cmd_q.iova = icp_hw_mgr.hfi_mem.cmd_q.iova; hfi_mem.cmd_q.len = icp_hw_mgr.hfi_mem.cmd_q.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "cmd_q kva = %llX IOVA = %X length = %lld\n", hfi_mem.cmd_q.kva, hfi_mem.cmd_q.iova, hfi_mem.cmd_q.len); hfi_mem.msg_q.kva = icp_hw_mgr.hfi_mem.msg_q.kva; hfi_mem.msg_q.iova = icp_hw_mgr.hfi_mem.msg_q.iova; hfi_mem.msg_q.len = icp_hw_mgr.hfi_mem.msg_q.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "msg_q kva = %llX IOVA = %X length = %lld\n", hfi_mem.msg_q.kva, hfi_mem.msg_q.iova, hfi_mem.msg_q.len); hfi_mem.dbg_q.kva = icp_hw_mgr.hfi_mem.dbg_q.kva; hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; - CAM_DBG(CAM_ICP, "kva = %llX IOVA = %X length = %lld\n", + CAM_DBG(CAM_ICP, "dbg_q kva = %llX IOVA = %X length = %lld\n", hfi_mem.dbg_q.kva, hfi_mem.dbg_q.iova, hfi_mem.dbg_q.len); + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + CAM_DBG(CAM_ICP, "sfr kva = %llX IOVA = %X length = %lld\n", + hfi_mem.sfr_buf.kva, hfi_mem.sfr_buf.iova, + hfi_mem.sfr_buf.len); + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; @@ -2323,6 +2495,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_hfi_queue_dump(); } kfree(abort_cmd); @@ -2379,6 +2552,7 @@ static int cam_icp_mgr_destroy_handle( if (icp_hw_mgr.a5_debug_type == HFI_DEBUG_MODE_QUEUE) cam_icp_mgr_process_dbg_buf(); + cam_hfi_queue_dump(); } kfree(destroy_cmd); return rc; @@ -2405,7 +2579,8 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id) cam_icp_mgr_ipe_bps_power_collapse(hw_mgr, &hw_mgr->ctx_data[ctx_id], 0); hw_mgr->ctx_data[ctx_id].state = CAM_ICP_CTX_STATE_RELEASE; - CAM_DBG(CAM_ICP, "E: ctx_id = %d", ctx_id); + CAM_DBG(CAM_ICP, "E: ctx_id = %d recovery = %d", + ctx_id, hw_mgr->recovery); cam_icp_mgr_abort_handle(&hw_mgr->ctx_data[ctx_id]); cam_icp_mgr_destroy_handle(&hw_mgr->ctx_data[ctx_id]); cam_icp_mgr_cleanup_ctx(&hw_mgr->ctx_data[ctx_id]); @@ -2638,6 +2813,10 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr) hfi_mem.dbg_q.iova = icp_hw_mgr.hfi_mem.dbg_q.iova; hfi_mem.dbg_q.len = icp_hw_mgr.hfi_mem.dbg_q.len; + hfi_mem.sfr_buf.kva = icp_hw_mgr.hfi_mem.sfr_buf.kva; + hfi_mem.sfr_buf.iova = icp_hw_mgr.hfi_mem.sfr_buf.iova; + hfi_mem.sfr_buf.len = icp_hw_mgr.hfi_mem.sfr_buf.len; + hfi_mem.sec_heap.kva = icp_hw_mgr.hfi_mem.sec_heap.kva; hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova; hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len; @@ -2680,6 +2859,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_hfi_queue_dump(); } CAM_DBG(CAM_ICP, "Done Waiting for INIT DONE Message"); @@ -2797,6 +2977,7 @@ static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args) hw_mgr->ctxt_cnt = 0; hw_mgr->fw_download = true; + hw_mgr->recovery = false; CAM_INFO(CAM_ICP, "FW download done successfully"); @@ -2858,8 +3039,10 @@ static int cam_icp_mgr_enqueue_config(struct cam_icp_hw_mgr *hw_mgr, struct hfi_cmd_work_data *task_data; struct hfi_cmd_ipebps_async *hfi_cmd; struct cam_hw_update_entry *hw_update_entries; + struct icp_frame_info *frame_info = NULL; - request_id = *(uint64_t *)config_args->priv; + frame_info = (struct icp_frame_info *)config_args->priv; + request_id = frame_info->request_id; hw_update_entries = config_args->hw_update_entries; CAM_DBG(CAM_ICP, "req_id = %lld %pK", request_id, config_args->priv); @@ -2881,6 +3064,82 @@ static int cam_icp_mgr_enqueue_config(struct cam_icp_hw_mgr *hw_mgr, return rc; } +static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, + uint32_t io_buf_addr) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async ioconfig_cmd; + unsigned long rem_jiffies; + int timeout = 5000; + struct crm_workq_task *task; + uint32_t size_in_words; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + reinit_completion(&ctx_data->wait_complete); + + ioconfig_cmd.num_fw_handles = 1; + ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd.payload.indirect = io_buf_addr; + ioconfig_cmd.user_data1 = (uint64_t)ctx_data; + ioconfig_cmd.user_data2 = (uint64_t)0x0; + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)&ioconfig_cmd; + task_data->request_id = 0; + task_data->type = ICP_WORKQ_TASK_MSG_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + size_in_words = (*(uint32_t *)task_data->data) >> 2; + CAM_INFO(CAM_ICP, "size_in_words %u", size_in_words); + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, + msecs_to_jiffies((timeout))); + if (!rem_jiffies) { + rc = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW response timed out %d", rc); + cam_hfi_queue_dump(); + } + + return rc; +} + +static int cam_icp_mgr_send_recfg_io(struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, uint64_t req_id) +{ + int rc = 0; + struct hfi_cmd_work_data *task_data; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)ioconfig_cmd; + task_data->request_id = req_id; + task_data->type = ICP_WORKQ_TASK_CMD_TYPE; + task->process_cb = cam_icp_mgr_process_cmd; + rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, + CRM_TASK_PRIORITY_0); + if (rc) + return rc; + + return rc; +} + static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) { int rc = 0; @@ -2889,6 +3148,7 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) struct cam_icp_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_hw_config_args *config_args = config_hw_args; struct cam_icp_hw_ctx_data *ctx_data = NULL; + struct icp_frame_info *frame_info = NULL; if (!hw_mgr || !config_args) { CAM_ERR(CAM_ICP, "Invalid arguments %pK %pK", @@ -2912,16 +3172,30 @@ static int cam_icp_mgr_config_hw(void *hw_mgr_priv, void *config_hw_args) return -EINVAL; } - req_id = *(uint64_t *)config_args->priv; + frame_info = (struct icp_frame_info *)config_args->priv; + req_id = frame_info->request_id; idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); ctx_data->hfi_frame_process.fw_process_flag[idx] = true; cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); + CAM_DBG(CAM_ICP, "req_id %llu, io config %llu", req_id, + frame_info->io_config); + + if (frame_info->io_config != 0) { + CAM_INFO(CAM_ICP, "Send recfg io"); + rc = cam_icp_mgr_send_recfg_io(ctx_data, + &frame_info->hfi_cfg_io_cmd, req_id); + if (rc) + CAM_ERR(CAM_ICP, "Fail to send reconfig io cmd"); + } + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); if (rc) goto config_err; - CAM_DBG(CAM_ICP, "req_id = %lld %u", - req_id, ctx_data->ctx_id); + CAM_DBG(CAM_REQ, + "req_id = %lld on ctx_id %u for dev %d queued to FW", + req_id, ctx_data->ctx_id, + ctx_data->icp_dev_acquire_info->dev_type); mutex_unlock(&ctx_data->ctx_mutex); mutex_unlock(&hw_mgr->hw_mgr_mutex); @@ -3107,8 +3381,11 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, io_cfg_ptr[i].fence; prepare_args->num_out_map_entries++; } - CAM_DBG(CAM_ICP, "dir[%d]: %u, fence: %u", - i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); + CAM_DBG(CAM_REQ, + "ctx_id: %u req_id: %llu dir[%d]: %u, fence: %u resource_type = %u", + ctx_data->ctx_id, packet->header.request_id, i, + io_cfg_ptr[i].direction, io_cfg_ptr[i].fence, + io_cfg_ptr[i].resource_type); } if (prepare_args->num_in_map_entries > 1) { @@ -3124,7 +3401,9 @@ static int cam_icp_mgr_process_io_cfg(struct cam_icp_hw_mgr *hw_mgr, merged_sync_in_obj; prepare_args->in_map_entries[0].sync_id = merged_sync_in_obj; prepare_args->num_in_map_entries = 1; - CAM_DBG(CAM_ICP, "Merged Sync obj = %d", merged_sync_in_obj); + CAM_DBG(CAM_REQ, "ctx_id: %u req_id: %llu Merged Sync obj: %d", + ctx_data->ctx_id, packet->header.request_id, + merged_sync_in_obj); } else if (prepare_args->num_in_map_entries == 1) { prepare_args->in_map_entries[0].sync_id = sync_in_obj[0]; prepare_args->num_in_map_entries = 1; @@ -3147,7 +3426,9 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, struct icp_cmd_generic_blob *blob; struct cam_icp_hw_ctx_data *ctx_data; uint32_t index; + size_t io_buf_size; int rc = 0; + uint64_t pResource; if (!blob_data || (blob_size == 0)) { CAM_ERR(CAM_ICP, "Invalid blob info %pK %d", blob_data, @@ -3176,6 +3457,28 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, clk_info->compressed_bw); break; + case CAM_ICP_CMD_GENERIC_BLOB_CFG_IO: + CAM_DBG(CAM_ICP, "CAM_ICP_CMD_GENERIC_BLOB_CFG_IO"); + pResource = *((uint32_t *)blob_data); + if (copy_from_user(&ctx_data->icp_dev_io_info, + (void __user *)pResource, + sizeof(struct cam_icp_acquire_dev_info))) { + CAM_ERR(CAM_ICP, "Failed in copy from user"); + return -EFAULT; + } + CAM_DBG(CAM_ICP, "buf handle %d", + ctx_data->icp_dev_io_info.io_config_cmd_handle); + rc = cam_mem_get_io_buf( + ctx_data->icp_dev_io_info.io_config_cmd_handle, + icp_hw_mgr.iommu_hdl, + blob->io_buf_addr, &io_buf_size); + if (rc) + CAM_ERR(CAM_ICP, "Failed in blob update"); + else + CAM_DBG(CAM_ICP, "io buf addr %llu", + *blob->io_buf_addr); + break; + default: CAM_WARN(CAM_ICP, "Invalid blob type %d", blob_type); break; @@ -3186,7 +3489,8 @@ static int cam_icp_packet_generic_blob_handler(void *user_data, static int cam_icp_process_generic_cmd_buffer( struct cam_packet *packet, struct cam_icp_hw_ctx_data *ctx_data, - int32_t index) + int32_t index, + uint64_t *io_buf_addr) { int i, rc = 0; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -3194,6 +3498,7 @@ static int cam_icp_process_generic_cmd_buffer( cmd_generic_blob.ctx = ctx_data; cmd_generic_blob.frame_info_idx = index; + cmd_generic_blob.io_buf_addr = io_buf_addr; cmd_desc = (struct cam_cmd_buf_desc *) ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); @@ -3213,6 +3518,28 @@ static int cam_icp_process_generic_cmd_buffer( return rc; } +static int cam_icp_mgr_process_cfg_io_cmd( + struct cam_icp_hw_ctx_data *ctx_data, + struct hfi_cmd_ipebps_async *ioconfig_cmd, + uint64_t request_id, + uint64_t io_config) +{ + ioconfig_cmd->size = sizeof(struct hfi_cmd_ipebps_async); + ioconfig_cmd->pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; + if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; + else + ioconfig_cmd->opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; + + ioconfig_cmd->num_fw_handles = 1; + ioconfig_cmd->fw_handles[0] = ctx_data->fw_handle; + ioconfig_cmd->payload.indirect = io_config; + ioconfig_cmd->user_data1 = (uint64_t)ctx_data; + ioconfig_cmd->user_data2 = request_id; + + return 0; +} + static int cam_icp_mgr_update_hfi_frame_process( struct cam_icp_hw_ctx_data *ctx_data, struct cam_packet *packet, @@ -3220,6 +3547,7 @@ static int cam_icp_mgr_update_hfi_frame_process( int32_t *idx) { int32_t index, rc; + struct hfi_cmd_ipebps_async *hfi_cmd = NULL; index = find_first_zero_bit(ctx_data->hfi_frame_process.bitmap, ctx_data->hfi_frame_process.bits); @@ -3231,15 +3559,27 @@ static int cam_icp_mgr_update_hfi_frame_process( ctx_data->hfi_frame_process.request_id[index] = packet->header.request_id; - rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index); + ctx_data->hfi_frame_process.frame_info[index].request_id = + packet->header.request_id; + ctx_data->hfi_frame_process.frame_info[index].io_config = 0; + rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index, + &ctx_data->hfi_frame_process.frame_info[index].io_config); if (rc) { clear_bit(index, ctx_data->hfi_frame_process.bitmap); ctx_data->hfi_frame_process.request_id[index] = -1; return rc; } + + if (ctx_data->hfi_frame_process.frame_info[index].io_config) { + hfi_cmd = (struct hfi_cmd_ipebps_async *)&ctx_data-> + hfi_frame_process.frame_info[index].hfi_cfg_io_cmd; + rc = cam_icp_mgr_process_cfg_io_cmd(ctx_data, hfi_cmd, + packet->header.request_id, ctx_data-> + hfi_frame_process.frame_info[index].io_config); + } *idx = index; - return 0; + return rc; } static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, @@ -3284,7 +3624,8 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, return rc; } - CAM_DBG(CAM_ICP, "E: req id = %lld", packet->header.request_id); + CAM_DBG(CAM_REQ, "req id = %lld for ctx = %u", + packet->header.request_id, ctx_data->ctx_id); /* Update Buffer Address from handles and patch information */ rc = cam_packet_util_process_patches(packet, hw_mgr->iommu_hdl, hw_mgr->iommu_sec_hdl); @@ -3320,7 +3661,7 @@ static int cam_icp_mgr_prepare_hw_update(void *hw_mgr_priv, prepare_args->num_hw_update_entries = 1; prepare_args->hw_update_entries[0].addr = (uint64_t)hfi_cmd; - prepare_args->priv = &ctx_data->hfi_frame_process.request_id[idx]; + prepare_args->priv = &ctx_data->hfi_frame_process.frame_info[idx]; CAM_DBG(CAM_ICP, "X: req id = %lld ctx_id = %u", packet->header.request_id, ctx_data->ctx_id); @@ -3480,6 +3821,7 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) { struct cam_hw_flush_args *flush_args = hw_flush_args; struct cam_icp_hw_ctx_data *ctx_data; + struct cam_icp_hw_mgr *hw_mgr = hw_priv; if ((!hw_priv) || (!hw_flush_args)) { CAM_ERR(CAM_ICP, "Input params are Null:"); @@ -3499,10 +3841,22 @@ static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args) return -EINVAL; } + CAM_DBG(CAM_REQ, "ctx_id %d req %lld Flush type %d", + ctx_data->ctx_id, + *(int64_t *)flush_args->flush_req_pending[0], + flush_args->flush_type); + switch (flush_args->flush_type) { case CAM_FLUSH_TYPE_ALL: - if (flush_args->num_req_active) - cam_icp_mgr_abort_handle(ctx_data); + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!hw_mgr->recovery) { + if (flush_args->num_req_active) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + cam_icp_mgr_abort_handle(ctx_data); + } + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + } mutex_lock(&ctx_data->ctx_mutex); cam_icp_mgr_flush_all(ctx_data, flush_args); mutex_unlock(&ctx_data->ctx_mutex); @@ -3540,7 +3894,7 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) return -EINVAL; } - CAM_DBG(CAM_ICP, "Enter"); + CAM_DBG(CAM_ICP, "Enter recovery set %d", hw_mgr->recovery); ctx_data = release_hw->ctxt_to_hw_map; if (!ctx_data) { CAM_ERR(CAM_ICP, "NULL ctx data"); @@ -3561,9 +3915,15 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) } mutex_unlock(&hw_mgr->ctx_data[ctx_id].ctx_mutex); - if (release_hw->active_req) { - cam_icp_mgr_abort_handle(ctx_data); - cam_icp_mgr_send_abort_status(ctx_data); + mutex_lock(&hw_mgr->hw_mgr_mutex); + if (!hw_mgr->recovery) { + mutex_unlock(&hw_mgr->hw_mgr_mutex); + if (release_hw->active_req) { + cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_send_abort_status(ctx_data); + } + } else { + mutex_unlock(&hw_mgr->hw_mgr_mutex); } mutex_lock(&hw_mgr->hw_mgr_mutex); @@ -3577,57 +3937,10 @@ static int cam_icp_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) } mutex_unlock(&hw_mgr->hw_mgr_mutex); - if (!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt) + if ((!hw_mgr->bps_ctxt_cnt || !hw_mgr->ipe_ctxt_cnt)) cam_icp_device_timer_stop(hw_mgr); - CAM_DBG(CAM_ICP, "Exit"); - return rc; -} - -static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data, - uint32_t io_buf_addr) -{ - int rc = 0; - struct hfi_cmd_work_data *task_data; - struct hfi_cmd_ipebps_async ioconfig_cmd; - unsigned long rem_jiffies; - int timeout = 5000; - struct crm_workq_task *task; - - task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); - if (!task) - return -ENOMEM; - - ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async); - ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT; - if (ctx_data->icp_dev_acquire_info->dev_type == CAM_ICP_RES_TYPE_BPS) - ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_BPS_CONFIG_IO; - else - ioconfig_cmd.opcode = HFI_IPEBPS_CMD_OPCODE_IPE_CONFIG_IO; - - reinit_completion(&ctx_data->wait_complete); - ioconfig_cmd.num_fw_handles = 1; - ioconfig_cmd.fw_handles[0] = ctx_data->fw_handle; - ioconfig_cmd.payload.indirect = io_buf_addr; - ioconfig_cmd.user_data1 = (uint64_t)ctx_data; - ioconfig_cmd.user_data2 = (uint64_t)0x0; - task_data = (struct hfi_cmd_work_data *)task->payload; - task_data->data = (void *)&ioconfig_cmd; - task_data->request_id = 0; - task_data->type = ICP_WORKQ_TASK_CMD_TYPE; - task->process_cb = cam_icp_mgr_process_cmd; - rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, - CRM_TASK_PRIORITY_0); - if (rc) - return rc; - - rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete, - msecs_to_jiffies((timeout))); - if (!rem_jiffies) { - rc = -ETIMEDOUT; - CAM_ERR(CAM_ICP, "FW response timed out %d", rc); - } - + CAM_DBG(CAM_ICP, "Release done for ctx_id %d", ctx_id); return rc; } @@ -3665,6 +3978,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_hfi_queue_dump(); } if (ctx_data->fw_handle == 0) { @@ -3710,6 +4024,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_hfi_queue_dump(); } return rc; @@ -3802,6 +4117,21 @@ static int cam_icp_get_acquire_info(struct cam_icp_hw_mgr *hw_mgr, return 0; } +static const char *cam_icp_dev_type_to_name( + uint32_t dev_type) +{ + switch (dev_type) { + case CAM_ICP_RES_TYPE_BPS: + return "BPS"; + case CAM_ICP_RES_TYPE_IPE_RT: + return "IPE_RT"; + case CAM_ICP_RES_TYPE_IPE: + return "IPE"; + default: + return "Invalid dev type"; + } +} + static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { int rc = 0, bitmap_size = 0; @@ -3843,6 +4173,8 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) icp_dev_acquire_info = ctx_data->icp_dev_acquire_info; + CAM_DBG(CAM_ICP, "acquire io buf handle %d", + icp_dev_acquire_info->io_config_cmd_handle); rc = cam_mem_get_io_buf( icp_dev_acquire_info->io_config_cmd_handle, hw_mgr->iommu_hdl, @@ -3931,7 +4263,10 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) cam_icp_ctx_timer_start(ctx_data); hw_mgr->ctxt_cnt++; mutex_unlock(&hw_mgr->hw_mgr_mutex); - CAM_DBG(CAM_ICP, "Acquire Done"); + CAM_DBG(CAM_ICP, "Acquire Done for ctx_id %u dev name %s dev type %d", + ctx_data->ctx_id, cam_icp_dev_type_to_name( + icp_dev_acquire_info->dev_type), + icp_dev_acquire_info->dev_type); return 0; @@ -4134,21 +4469,22 @@ static int cam_icp_mgr_create_wq(void) int i; rc = cam_req_mgr_workq_create("icp_command_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ); + &icp_hw_mgr.cmd_work, CRM_WORKQ_USAGE_NON_IRQ, + 0); if (rc) { CAM_ERR(CAM_ICP, "unable to create a command worker"); goto cmd_work_failed; } rc = cam_req_mgr_workq_create("icp_message_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ); + &icp_hw_mgr.msg_work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_ICP, "unable to create a message worker"); goto msg_work_failed; } rc = cam_req_mgr_workq_create("icp_timer_queue", ICP_WORKQ_NUM_TASK, - &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ); + &icp_hw_mgr.timer_work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_ICP, "unable to create a timer worker"); goto timer_work_failed; @@ -4176,6 +4512,9 @@ static int cam_icp_mgr_create_wq(void) if (rc) goto debugfs_create_failed; + icp_hw_mgr.icp_pc_flag = true; + icp_hw_mgr.ipe_bps_pc_flag = true; + for (i = 0; i < ICP_WORKQ_NUM_TASK; i++) icp_hw_mgr.msg_work->task.pool[i].payload = &icp_hw_mgr.msg_work_data[i]; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 8746ee264f31f9d66eaddbb7702f8f9ffd4dd378..0b931f3c7636eaa7ea05e9eeb2293a66994bc76d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -79,6 +79,7 @@ * @sec_heap: Memory info of secondary heap * @fw_buf: Memory info of firmware * @qdss_buf: Memory info of qdss + * @sfr_buf: Memory info for sfr buffer */ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc qtbl; @@ -88,6 +89,7 @@ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc sec_heap; struct cam_mem_mgr_memory_desc fw_buf; struct cam_mem_mgr_memory_desc qdss_buf; + struct cam_mem_mgr_memory_desc sfr_buf; struct cam_smmu_region_info shmem; }; @@ -125,6 +127,19 @@ struct clk_work_data { void *data; }; +/** + * struct icp_frame_info + * @request_id: request id + * @io_config: the address of io config + * @hfi_cfg_io_cmd: command struct to be sent to hfi + */ +struct icp_frame_info { + uint64_t request_id; + uint64_t io_config; + struct hfi_cmd_ipebps_async hfi_cfg_io_cmd; +}; + + /** * struct hfi_frame_process_info * @hfi_frame_cmd: Frame process command info @@ -136,6 +151,7 @@ struct clk_work_data { * @out_resource: Out sync info * @fw_process_flag: Frame process flag * @clk_info: Clock information for a request + * @frame_info: information needed to process request */ struct hfi_frame_process_info { struct hfi_cmd_ipebps_async hfi_frame_cmd[CAM_FRAME_CMD_MAX]; @@ -149,6 +165,7 @@ struct hfi_frame_process_info { uint32_t in_free_resource[CAM_FRAME_CMD_MAX]; uint32_t fw_process_flag[CAM_FRAME_CMD_MAX]; struct cam_icp_clk_bw_request clk_info[CAM_FRAME_CMD_MAX]; + struct icp_frame_info frame_info[CAM_FRAME_CMD_MAX]; }; /** @@ -189,6 +206,7 @@ struct cam_ctx_clk_info { * @clk_info: Current clock info of a context * @watch_dog: watchdog timer handle * @watch_dog_reset_counter: Counter for watch dog reset + * @icp_dev_io_info: io config resource */ struct cam_icp_hw_ctx_data { void *context_priv; @@ -208,16 +226,19 @@ struct cam_icp_hw_ctx_data { struct cam_ctx_clk_info clk_info; struct cam_req_mgr_timer *watch_dog; uint32_t watch_dog_reset_counter; + struct cam_icp_acquire_dev_info icp_dev_io_info; }; /** * struct icp_cmd_generic_blob * @ctx: Current context info * @frame_info_idx: Index used for frame process info + * @io_buf_addr: pointer to io buffer address */ struct icp_cmd_generic_blob { struct cam_icp_hw_ctx_data *ctx; uint32_t frame_info_idx; + uint64_t *io_buf_addr; }; /** @@ -290,6 +311,9 @@ struct cam_icp_clk_info { * @bps_dev_intf: Device interface for BPS * @ipe_clk_state: IPE clock state flag * @bps_clk_state: BPS clock state flag + * @recovery: Flag to validate if in previous session FW + * reported a fatal error or wdt. If set FW is + * re-downloaded for new camera session. */ struct cam_icp_hw_mgr { struct mutex hw_mgr_mutex; @@ -337,6 +361,7 @@ struct cam_icp_hw_mgr { struct cam_hw_intf *bps_dev_intf; bool ipe_clk_state; bool bps_clk_state; + bool recovery; }; static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args); diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h index 4f0717290b0669ca1249d0f9d97d8a036cc6fb46..0f76a057c68777c56b8f4608fce4f2a56dc86b8d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h @@ -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 @@ -18,6 +18,15 @@ #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" +/* BPS register */ +#define BPS_TOP_RST_CMD 0x1008 +#define BPS_CDM_RST_CMD 0x10 +#define BPS_CDM_IRQ_STATUS 0x44 +#define BPS_TOP_IRQ_STATUS 0x100C + +/* BPS CDM/TOP status register */ +#define BPS_RST_DONE_IRQ_STATUS_BIT 0x1 + enum cam_icp_bps_cmd_type { CAM_ICP_BPS_CMD_FW_DOWNLOAD, CAM_ICP_BPS_CMD_POWER_COLLAPSE, @@ -28,6 +37,7 @@ enum cam_icp_bps_cmd_type { CAM_ICP_BPS_CMD_CPAS_STOP, CAM_ICP_BPS_CMD_UPDATE_CLK, CAM_ICP_BPS_CMD_DISABLE_CLK, + CAM_ICP_BPS_CMD_RESET, CAM_ICP_BPS_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h index 0943bef0836defff3f3da7eeef524149571b9941..d1e3b9a9ae0dfe19662b0036a844c8975143728c 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h @@ -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 @@ -18,6 +18,15 @@ #include "cam_hw_mgr_intf.h" #include "cam_icp_hw_intf.h" +/* IPE registers */ +#define IPE_TOP_RST_CMD 0x1008 +#define IPE_CDM_RST_CMD 0x10 +#define IPE_CDM_IRQ_STATUS 0x44 +#define IPE_TOP_IRQ_STATUS 0x100C + +/* IPE CDM/TOP status register */ +#define IPE_RST_DONE_IRQ_STATUS_BIT 0x1 + enum cam_icp_ipe_cmd_type { CAM_ICP_IPE_CMD_FW_DOWNLOAD, CAM_ICP_IPE_CMD_POWER_COLLAPSE, @@ -28,6 +37,7 @@ enum cam_icp_ipe_cmd_type { CAM_ICP_IPE_CMD_CPAS_STOP, CAM_ICP_IPE_CMD_UPDATE_CLK, CAM_ICP_IPE_CMD_DISABLE_CLK, + CAM_ICP_IPE_CMD_RESET, CAM_ICP_IPE_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c index 87478af551b74a44180341cb746846f02975b88c..620a4bd4943b290d5bfad96bcdb23d1617f94e9d 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_core.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 @@ -18,6 +18,7 @@ #include #include #include +#include #include "cam_io_util.h" #include "cam_hw.h" #include "cam_hw_intf.h" @@ -29,6 +30,9 @@ #include "cam_icp_hw_mgr_intf.h" #include "cam_cpas_api.h" #include "cam_debug_util.h" +#include "hfi_reg.h" + +#define HFI_MAX_POLL_TRY 5 static int cam_ipe_caps_vote(struct cam_ipe_device_core_info *core_info, struct cam_icp_cpas_vote *cpas_vote) @@ -206,6 +210,77 @@ static int cam_ipe_handle_resume(struct cam_hw_info *ipe_dev) return rc; } +static int cam_ipe_cmd_reset(struct cam_hw_soc_info *soc_info, + struct cam_ipe_device_core_info *core_info) +{ + int pwr_ctrl, pwr_status, rc = 0; + uint32_t status = 0, retry_cnt = 0; + bool reset_ipe_cdm_fail = false; + bool reset_ipe_top_fail = false; + + CAM_DBG(CAM_ICP, "CAM_ICP_IPE_CMD_RESET"); + /* IPE CDM core reset*/ + cam_io_w_mb((uint32_t)0xF, + soc_info->reg_map[0].mem_base + IPE_CDM_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_cdm_irq_status = %u", status); + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_CDM_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE CDM rst failed status 0x%x", status); + reset_ipe_cdm_fail = true; + } + + /* IPE reset*/ + status = 0; + cam_io_w_mb((uint32_t)0x3, + soc_info->reg_map[0].mem_base + IPE_TOP_RST_CMD); + while (retry_cnt < HFI_MAX_POLL_TRY) { + readw_poll_timeout((soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS), + status, ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1), + 100, 10000); + + CAM_DBG(CAM_HFI, "ipe_top_irq_status = %u", status); + + + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) == 0x1) + break; + retry_cnt++; + } + status = cam_io_r_mb(soc_info->reg_map[0].mem_base + + IPE_TOP_IRQ_STATUS); + if ((status & IPE_RST_DONE_IRQ_STATUS_BIT) != 0x1) { + CAM_ERR(CAM_ICP, "IPE top rst failed status 0x%x", status); + reset_ipe_top_fail = true; + } + + cam_ipe_get_gdsc_control(soc_info); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_ctrl, + true, &pwr_ctrl); + cam_cpas_reg_read(core_info->cpas_handle, + CAM_CPAS_REG_CPASTOP, core_info->ipe_hw_info->pwr_status, + true, &pwr_status); + CAM_DBG(CAM_ICP, "(After)pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + if (reset_ipe_cdm_fail || reset_ipe_top_fail) + rc = -EAGAIN; + + return rc; +} + int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -302,7 +377,12 @@ int cam_ipe_process_cmd(void *device_priv, uint32_t cmd_type, cam_ipe_toggle_clk(soc_info, false); core_info->clk_enable = false; break; + case CAM_ICP_IPE_CMD_RESET: + rc = cam_ipe_cmd_reset(soc_info, core_info); + break; default: + CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type); + rc = -EINVAL; break; } return rc; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c index cc2b1b1f88a5b206308da2a15f9c97a18a51f2dc..a01d114bae7b27214ca8f7f1b64889d59824bbba 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_dev.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 @@ -41,6 +41,8 @@ static struct cam_ipe_device_hw_info cam_ipe_hw_info[] = { }; EXPORT_SYMBOL(cam_ipe_hw_info); +static char ipe_dev_name[8]; + int cam_ipe_register_cpas(struct cam_hw_soc_info *soc_info, struct cam_ipe_device_core_info *core_info, uint32_t hw_idx) @@ -96,9 +98,14 @@ int cam_ipe_probe(struct platform_device *pdev) kfree(ipe_dev_intf); return -ENOMEM; } + + memset(ipe_dev_name, 0, sizeof(ipe_dev_name)); + snprintf(ipe_dev_name, sizeof(ipe_dev_name), + "ipe%1u", ipe_dev_intf->hw_idx); + ipe_dev->soc_info.pdev = pdev; ipe_dev->soc_info.dev = &pdev->dev; - ipe_dev->soc_info.dev_name = pdev->name; + ipe_dev->soc_info.dev_name = ipe_dev_name; ipe_dev_intf->hw_priv = ipe_dev; ipe_dev_intf->hw_ops.init = cam_ipe_init_hw; ipe_dev_intf->hw_ops.deinit = cam_ipe_deinit_hw; @@ -179,6 +186,7 @@ static struct platform_driver cam_ipe_driver = { .name = "cam-ipe", .owner = THIS_MODULE, .of_match_table = cam_ipe_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c index d24305ac89fe0c241615a7537466ef4cba5b28e9..91d440fcdcee2033bac18ea0ae6f141769e52999 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -157,8 +157,7 @@ int cam_ipe_update_clk_rate(struct cam_hw_soc_info *soc_info, clk_rate = soc_info->clk_rate[CAM_TURBO_VOTE][src_clk_idx]; } - return cam_soc_util_set_clk_rate(soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], clk_rate); + return cam_soc_util_set_src_clk_rate(soc_info, clk_rate); } int cam_ipe_toggle_clk(struct cam_hw_soc_info *soc_info, bool clk_enable) 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 7b02aac2ad0ab0fc4f8ea041eebeb196a2794f77..f5b1bb147c48173adf82981f07be44184c942fa6 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 @@ -435,8 +435,8 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); ctx_isp->active_req_cnt--; - CAM_DBG(CAM_ISP, - "Move active request %lld to free list(cnt = %d)", + CAM_DBG(CAM_REQ, + "Move active request %lld to free list(cnt = %d) [all fences done]", req->request_id, ctx_isp->active_req_cnt); } @@ -536,7 +536,7 @@ 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_ISP, "move request %lld to active list(cnt = %d)", + 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. */ @@ -697,7 +697,7 @@ static int __cam_isp_ctx_reg_upd_in_sof(struct cam_isp_context *ctx_isp, /* need to handle the buf done */ list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", req->request_id, ctx_isp->active_req_cnt); @@ -761,7 +761,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp, list_del_init(&req->list); list_add_tail(&req->list, &ctx->active_req_list); ctx_isp->active_req_cnt++; - CAM_DBG(CAM_ISP, "move request %lld to active list(cnt = %d)", + CAM_DBG(CAM_REQ, "move request %lld to active list(cnt = %d)", req->request_id, ctx_isp->active_req_cnt); req_isp->bubble_report = 0; } @@ -895,8 +895,9 @@ static int __cam_isp_ctx_epoch_in_bubble_applied( 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); + CAM_DBG(CAM_REQ, + "Notify CRM about Bubble req_id %llu frame %lld", + req->request_id, ctx_isp->frame_id); } else { /* * If we can not report bubble, then treat it as if no bubble @@ -1227,7 +1228,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( goto end; } - CAM_DBG(CAM_ISP, "Apply request %lld", req->request_id); + CAM_DBG(CAM_REQ, "Apply request %lld in substate %d", req->request_id, + ctx_isp->substate_activated); req_isp = (struct cam_isp_ctx_req *) req->req_priv; if (ctx_isp->active_req_cnt >= 2) { @@ -1342,6 +1344,8 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx, return 0; } + CAM_DBG(CAM_REQ, "Flush [%u] in progress for req_id %llu", + flush_req->type, flush_req->req_id); list_for_each_entry_safe(req, req_temp, req_list, list) { if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { if (req->request_id != flush_req->req_id) { @@ -2016,7 +2020,8 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, ctx->state = CAM_CTX_AVAILABLE; trace_cam_context_state("ISP", ctx); - CAM_DBG(CAM_ISP, "next state %d", ctx->state); + CAM_DBG(CAM_ISP, "Release device success[%u] next state %d", + ctx->ctx_id, ctx->state); return rc; } @@ -2142,8 +2147,9 @@ static int __cam_isp_ctx_config_dev_in_top_state( if (rc) goto free_req; - CAM_DBG(CAM_ISP, "Preprocessing Config %lld successful", - req->request_id); + CAM_DBG(CAM_REQ, + "Preprocessing Config req_id %lld successful on ctx %u", + req->request_id, ctx->ctx_id); return rc; @@ -2274,7 +2280,10 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, ctx->state = CAM_CTX_ACQUIRED; trace_cam_context_state("ISP", ctx); - CAM_DBG(CAM_ISP, "Acquire success."); + CAM_DBG(CAM_ISP, + "Acquire success on session_hdl 0x%x num_rsrces %d RDI only %d ctx %u", + cmd->session_handle, cmd->num_resources, + (hw_cmd_args.u.is_rdi_only_context ? 1 : 0), ctx->ctx_id); kfree(isp_res); return rc; @@ -2416,7 +2425,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, trace_cam_context_state("ISP", ctx); goto end; } - CAM_DBG(CAM_ISP, "start device success"); + CAM_DBG(CAM_ISP, "start device success ctx %u", ctx->ctx_id); if (req_isp->num_fence_map_out) { list_del_init(&req->list); @@ -2499,7 +2508,8 @@ static int __cam_isp_ctx_stop_dev_in_activated_unlock( ctx_isp->active_req_cnt = 0; ctx_isp->reported_req_id = 0; - CAM_DBG(CAM_ISP, "next state %d", ctx->state); + CAM_DBG(CAM_ISP, "Stop device success next state %d on ctx %u", + ctx->state, ctx->ctx_id); return rc; } @@ -2560,6 +2570,24 @@ static int __cam_isp_ctx_link_resume(struct cam_context *ctx) return rc; } +static int __cam_isp_ctx_handle_sof_freeze_evt( + struct cam_context *ctx) +{ + int rc = 0; + struct cam_isp_hw_cmd_args hw_cmd_args; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *) ctx->ctx_priv; + + hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx; + hw_cmd_args.cmd_type = CAM_ISP_HW_MGR_CMD_SOF_DEBUG; + hw_cmd_args.u.sof_irq_enable = 1; + + rc = ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &hw_cmd_args); + + return rc; +} + static int __cam_isp_ctx_process_evt(struct cam_context *ctx, struct cam_req_mgr_link_evt_data *link_evt_data) { @@ -2575,6 +2603,9 @@ static int __cam_isp_ctx_process_evt(struct cam_context *ctx, case CAM_REQ_MGR_LINK_EVT_RESUME: __cam_isp_ctx_link_resume(ctx); break; + case CAM_REQ_MGR_LINK_EVT_SOF_FREEZE: + __cam_isp_ctx_handle_sof_freeze_evt(ctx); + break; default: CAM_WARN(CAM_ISP, "Unknown event from CRM"); break; diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c index e775daac6fbe256c4ffda8aa4b0228e504359200..a067915bed7d4dd56909ae50d14409e87b1ae397 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_dev.c @@ -136,6 +136,7 @@ static struct platform_driver isp_driver = { .name = "cam_isp", .owner = THIS_MODULE, .of_match_table = cam_isp_dt_match, + .suppress_bind_attrs = true, }, }; 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 c1aa501e229d8ff81a6a3b446eeb675b7cd048e3..8d764b043a181b2c652c261806c8da15c4435ea6 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 @@ -225,6 +225,8 @@ static int cam_ife_hw_mgr_start_hw_res( CAM_ERR(CAM_ISP, "Can not start HW resources"); goto err; } + CAM_DBG(CAM_ISP, "Start HW %d Res %d", hw_intf->hw_idx, + isp_hw_res->hw_res[i]->res_id); } else { CAM_ERR(CAM_ISP, "function null"); goto err; @@ -366,7 +368,8 @@ static int cam_ife_mgr_csid_stop_hw( isp_res = hw_mgr_res->hw_res[i]; if (isp_res->hw_intf->hw_idx != base_idx) continue; - + CAM_DBG(CAM_ISP, "base_idx %d res_id %d cnt %u", + base_idx, isp_res->res_id, cnt); stop_res[cnt] = isp_res; cnt++; } @@ -483,8 +486,8 @@ static void cam_ife_mgr_add_base_info( "Add split id = %d for base idx = %d num_base=%d", split_id, base_idx, ctx->num_base); } else { - /*Check if base index is alreay exist in the list */ - for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + /*Check if base index already exists in the list */ + for (i = 0; i < ctx->num_base; i++) { if (ctx->base[i].idx == base_idx) { if (split_id != CAM_ISP_HW_SPLIT_MAX && ctx->base[i].split_id == @@ -495,7 +498,7 @@ static void cam_ife_mgr_add_base_info( } } - if (i == CAM_IFE_HW_NUM_MAX) { + if (i == ctx->num_base) { ctx->base[ctx->num_base].split_id = split_id; ctx->base[ctx->num_base].idx = base_idx; ctx->num_base++; @@ -845,7 +848,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( } ife_src_res->hw_res[i] = vfe_acquire.vfe_in.rsrc_node; CAM_DBG(CAM_ISP, - "acquire success res type :0x%x res id:0x%x", + "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); @@ -871,29 +875,75 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( static int cam_ife_mgr_acquire_cid_res( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port, - uint32_t *cid_res_id, + struct cam_ife_hw_mgr_res **cid_res, enum cam_ife_pix_path_res_id csid_path) { int rc = -1; int i, j; struct cam_ife_hw_mgr *ife_hw_mgr; - struct cam_ife_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; + struct cam_ife_hw_mgr_res *cid_res_temp, *cid_res_iterator; struct cam_csid_hw_reserve_resource_args csid_acquire; + uint32_t acquired_cnt = 0; ife_hw_mgr = ife_ctx->hw_mgr; + *cid_res = NULL; - rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &cid_res); + rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, cid_res); if (rc) { CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; + goto end; } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res); + + cid_res_temp = *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); + + /* Try acquiring CID resource from previously acquired HW */ + list_for_each_entry(cid_res_iterator, &ife_ctx->res_list_ife_cid, + list) { + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!cid_res_iterator->hw_res[i]) + continue; + + hw_intf = cid_res_iterator->hw_res[i]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "No ife cid resource from hw %d", + hw_intf->hw_idx); + continue; + } + + cid_res_temp->hw_res[acquired_cnt++] = + csid_acquire.node_res; + + CAM_DBG(CAM_ISP, + "acquired 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) + /* Continue to acquire Right */ + continue; + + if (acquired_cnt) + /* + * If successfully acquired CID from + * previously acquired HW, skip the next + * part + */ + goto acquire_successful; + } + } + /* Acquire Left if not already acquired */ for (i = 0; i < CAM_IFE_CSID_HW_NUM_MAX; i++) { if (!ife_hw_mgr->csid_devices[i]) continue; @@ -903,31 +953,45 @@ static int cam_ife_mgr_acquire_cid_res( sizeof(csid_acquire)); if (rc) continue; - else + 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 csid rdi resource"); - goto err; + CAM_ERR(CAM_ISP, "Can not acquire ife cid resource for path %d", + csid_path); + goto put_res; } - cid_res->res_type = CAM_IFE_HW_MGR_RES_CID; - cid_res->res_id = csid_acquire.node_res->res_id; - cid_res->is_dual_vfe = in_port->usage_type; - cid_res->hw_res[0] = csid_acquire.node_res; - cid_res->hw_res[1] = NULL; +acquire_successful: + CAM_DBG(CAM_ISP, "CID left acquired success is_dual %d", + in_port->usage_type); + + cid_res_temp->res_type = CAM_IFE_HW_MGR_RES_CID; /* CID(DT_ID) value of acquire device, require for path */ - *cid_res_id = csid_acquire.node_res->res_id; + cid_res_temp->res_id = csid_acquire.node_res->res_id; + cid_res_temp->is_dual_vfe = in_port->usage_type; + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, cid_res); - if (cid_res->is_dual_vfe) { + /* + * Acquire Right if not already acquired. + * Dual IFE for RDI is not currently supported. + */ + if (cid_res_temp->is_dual_vfe && csid_path + == CAM_IFE_PIX_PATH_RES_IPP && acquired_cnt == 1) { csid_acquire.node_res = NULL; csid_acquire.res_type = CAM_ISP_RESOURCE_CID; csid_acquire.in_port = in_port; - for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { + for (j = 0; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { if (!ife_hw_mgr->csid_devices[j]) continue; + if (j == cid_res_temp->hw_res[0]->hw_intf->hw_idx) + continue; + hw_intf = ife_hw_mgr->csid_devices[j]; rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, &csid_acquire, sizeof(csid_acquire)); @@ -940,16 +1004,20 @@ static int cam_ife_mgr_acquire_cid_res( if (j == CAM_IFE_CSID_HW_NUM_MAX) { CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource"); - goto err; + goto end; } - cid_res->hw_res[1] = csid_acquire.node_res; + cid_res_temp->hw_res[1] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, "CID right acquired success is_dual %d", + in_port->usage_type); } - cid_res->parent = &ife_ctx->res_list_ife_in; + 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; + ife_ctx->res_list_ife_in.num_children++] = cid_res_temp; return 0; -err: +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, cid_res); +end: return rc; } @@ -966,35 +1034,25 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( struct cam_ife_hw_mgr_res *csid_res; struct cam_ife_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; - uint32_t cid_res_id; struct cam_csid_hw_reserve_resource_args csid_acquire; + ife_hw_mgr = ife_ctx->hw_mgr; /* get cid resource */ - rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id, + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, CAM_IFE_PIX_PATH_RES_IPP); if (rc) { CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); - goto err; + goto end; } - ife_hw_mgr = ife_ctx->hw_mgr; - rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res); if (rc) { CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; + goto end; } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - - csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; - csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP; - csid_acquire.cid = cid_res_id; - csid_acquire.in_port = in_port; - csid_acquire.out_port = in_port->data; csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP; - csid_res->is_dual_vfe = in_port->usage_type; if (in_port->usage_type) csid_res->is_dual_vfe = 1; @@ -1003,66 +1061,60 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; } - list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid, - list) { - if (cid_res->res_id != cid_res_id) - continue; - - for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { - if (!cid_res->hw_res[i]) - continue; + /* IPP resource needs to be from same HW as CID resource */ + for (i = 0; i <= csid_res->is_dual_vfe; i++) { + CAM_DBG(CAM_ISP, "i %d is_dual %d", i, csid_res->is_dual_vfe); + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP; + csid_acquire.cid = cid_res->hw_res[i]->res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + csid_acquire.node_res = NULL; - hw_intf = ife_hw_mgr->csid_devices[ - cid_res->hw_res[i]->hw_intf->hw_idx]; + hw_intf = cid_res->hw_res[i]->hw_intf; - csid_acquire.node_res = NULL; - if (csid_res->is_dual_vfe) { - if (i == CAM_ISP_HW_SPLIT_LEFT) { - master_idx = hw_intf->hw_idx; - csid_acquire.sync_mode = - CAM_ISP_HW_SYNC_MASTER; - } else { - if (master_idx == -1) { - CAM_ERR(CAM_ISP, - "No Master found"); - goto err; - } - csid_acquire.sync_mode = - CAM_ISP_HW_SYNC_SLAVE; - csid_acquire.master_idx = master_idx; + if (csid_res->is_dual_vfe) { + if (i == CAM_ISP_HW_SPLIT_LEFT) { + master_idx = hw_intf->hw_idx; + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + } else { + if (master_idx == -1) { + CAM_ERR(CAM_ISP, + "No Master found"); + goto put_res; } + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + csid_acquire.master_idx = master_idx; } - - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) { - CAM_ERR(CAM_ISP, - "Cannot acquire ife csid ipp resource"); - goto err; - } - - csid_res->hw_res[i] = csid_acquire.node_res; - CAM_DBG(CAM_ISP, - "acquired csid(%s)=%d ipp rsrc successfully", - (i == 0) ? "left" : "right", - hw_intf->hw_idx); - } - if (i == CAM_IFE_CSID_HW_NUM_MAX) { + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { CAM_ERR(CAM_ISP, - "Can not acquire ife csid ipp resource"); - goto err; + "Cannot acquire ife csid ipp resource"); + goto put_res; } - csid_res->parent = cid_res; - cid_res->child[cid_res->num_children++] = csid_res; + csid_res->hw_res[i] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, + "acquired csid(%s)=%d ipp rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = csid_res; CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id); return 0; -err: +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: return rc; } @@ -1099,111 +1151,88 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( struct cam_ife_hw_mgr_ctx *ife_ctx, struct cam_isp_in_port_info *in_port) { - int rc = -1; - int i, j; + int rc = -EINVAL; + int i; struct cam_ife_hw_mgr *ife_hw_mgr; struct cam_ife_hw_mgr_res *csid_res; struct cam_ife_hw_mgr_res *cid_res; struct cam_hw_intf *hw_intf; struct cam_isp_out_port_info *out_port; - uint32_t cid_res_id; struct cam_csid_hw_reserve_resource_args csid_acquire; + enum cam_ife_pix_path_res_id path_type; 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)) + path_type = cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type); + if (path_type == CAM_IFE_PIX_PATH_RES_MAX) continue; - /* get cid resource */ - rc = cam_ife_mgr_acquire_cid_res(ife_ctx, - in_port, &cid_res_id, - cam_ife_hw_mgr_get_ife_csid_rdi_res_type( - out_port->res_type)); - if (rc) { - CAM_ERR(CAM_ISP, - "Acquire IFE CID resource Failed"); - goto err; + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res, + path_type); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto end; } + /* For each RDI we need CID + PATH resource */ rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, &csid_res); if (rc) { CAM_ERR(CAM_ISP, "No more free hw mgr resource"); - goto err; + goto end; } - cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - - /* - * no need to check since we are doing one to one mapping - * between the csid rdi type and out port rdi type - */ memset(&csid_acquire, 0, sizeof(csid_acquire)); - csid_acquire.res_id = - cam_ife_hw_mgr_get_ife_csid_rdi_res_type( - out_port->res_type); + csid_acquire.res_id = path_type; csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; - csid_acquire.cid = cid_res_id; + csid_acquire.cid = cid_res->hw_res[0]->res_id; csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + csid_acquire.node_res = NULL; - list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid, - list) { - if (cid_res->res_id != cid_res_id) - continue; - - for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { - if (!cid_res->hw_res[j]) - continue; - - csid_acquire.node_res = NULL; - - hw_intf = ife_hw_mgr->csid_devices[ - cid_res->hw_res[j]->hw_intf->hw_idx]; - rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, - &csid_acquire, sizeof(csid_acquire)); - if (rc) { - CAM_DBG(CAM_ISP, - "CSID Path reserve failed hw=%d rc=%d", - hw_intf->hw_idx, rc); - continue; - } + hw_intf = cid_res->hw_res[0]->hw_intf; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_ERR(CAM_ISP, + "CSID Path reserve failed hw=%d rc=%d cid=%d", + hw_intf->hw_idx, rc, + cid_res->hw_res[0]->res_id); - /* RDI does not need Dual ISP. Break */ - break; - } + goto put_res; + } - if (j == CAM_ISP_HW_SPLIT_MAX && - csid_acquire.node_res == NULL) { - CAM_ERR(CAM_ISP, - "acquire csid rdi rsrc failed, cid %d", - cid_res_id); - goto err; - } + if (csid_acquire.node_res == NULL) { + CAM_ERR(CAM_ISP, "Acquire CSID RDI rsrc failed"); - csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; - csid_res->res_id = csid_acquire.res_id; - csid_res->is_dual_vfe = 0; - csid_res->hw_res[0] = csid_acquire.node_res; - csid_res->hw_res[1] = NULL; - CAM_DBG(CAM_ISP, "acquire res %d", - csid_acquire.res_id); - csid_res->parent = cid_res; - cid_res->child[cid_res->num_children++] = - csid_res; - - /* Done with cid_res_id. Break */ - break; + goto put_res; } + + csid_res->res_type = (enum cam_ife_hw_mgr_res_type) + CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_id = csid_acquire.res_id; + csid_res->is_dual_vfe = 0; + csid_res->hw_res[0] = csid_acquire.node_res; + csid_res->hw_res[1] = NULL; + 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_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); } return 0; -err: +put_res: + cam_ife_hw_mgr_put_res(&ife_ctx->free_res_list, &csid_res); +end: return rc; } @@ -1511,7 +1540,7 @@ static int cam_isp_blob_bw_update( int rc = -EINVAL; uint32_t i; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n" "right cam_bw_bps=%llu ext_bw_bps=%llu", bw_config->usage_type, @@ -1667,8 +1696,6 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, "config done Success for req_id=%llu", cfg->request_id); } - - rc = 0; } } else { CAM_ERR(CAM_ISP, "No commands to config"); @@ -1870,33 +1897,39 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) */ if (i == ctx->num_base) master_base_idx = ctx->base[0].idx; + CAM_DBG(CAM_ISP, "Stopping master CSID idx %d", master_base_idx); - /* Stop the master CIDs first */ - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, - master_base_idx, csid_halt_type); + /* Stop the master CSID path first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + master_base_idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); - /* stop rest of the CIDs */ + /* stop rest of the CSID paths */ for (i = 0; i < ctx->num_base; i++) { - if (i == master_base_idx) + if (ctx->base[i].idx == master_base_idx) continue; - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, - ctx->base[i].idx, csid_halt_type); + CAM_DBG(CAM_ISP, "Stopping CSID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, CAM_CSID_HALT_AT_FRAME_BOUNDARY); } - /* Stop the master CSID path first */ - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + CAM_DBG(CAM_ISP, "Stopping master CID idx %d", master_base_idx); + + /* Stop the master CIDs first */ + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, master_base_idx, csid_halt_type); - /* stop rest of the CSID paths */ + /* stop rest of the CIDs */ for (i = 0; i < ctx->num_base; i++) { - if (i == master_base_idx) + if (ctx->base[i].idx == master_base_idx) continue; - - cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + CAM_DBG(CAM_ISP, "Stopping CID idx %d i %d master %d", + ctx->base[i].idx, i, master_base_idx); + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, ctx->base[i].idx, csid_halt_type); } - /* Deinit IFE CID */ list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_cid, list) { CAM_DBG(CAM_ISP, "%s: Going to DeInit IFE CID\n", __func__); @@ -1918,7 +1951,8 @@ static int cam_ife_mgr_stop_hw(void *hw_mgr_priv, void *stop_hw_args) for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) cam_ife_hw_mgr_deinit_hw_res(&ctx->res_list_ife_out[i]); - CAM_DBG(CAM_ISP, "Exit...ctx id:%d rc :%d", ctx->ctx_index, rc); + CAM_DBG(CAM_ISP, + "Stop success for ctx id:%d rc :%d", ctx->ctx_index, rc); mutex_lock(&g_ife_hw_mgr.ctx_mutex); if (!atomic_dec_return(&g_ife_hw_mgr.active_ctx_cnt)) { @@ -2196,7 +2230,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) } /* Start IFE root node: do nothing */ - CAM_DBG(CAM_ISP, "Exit...(success)"); + CAM_DBG(CAM_ISP, "Start success for ctx id:%d", ctx->ctx_index); return 0; err: stop_hw_method.hw_stop_cmd = CAM_CSID_HALT_IMMEDIATELY; @@ -2383,7 +2417,7 @@ static int cam_isp_blob_clock_update( ctx = prepare->ctxt_to_hw_map; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_PERF, "usage=%u left_clk= %lu right_clk=%lu", clock_config->usage_type, clock_config->left_pix_hz, @@ -2536,7 +2570,8 @@ static int cam_ife_mgr_prepare_hw_update(void *hw_mgr_priv, return -EINVAL; } - CAM_DBG(CAM_ISP, "enter"); + CAM_DBG(CAM_REQ, "Enter for req_id %lld", + prepare->packet->header.request_id); prepare_hw_data = (struct cam_isp_prepare_hw_update_data *) prepare->priv; @@ -2664,6 +2699,52 @@ static int cam_ife_mgr_resume_hw(struct cam_ife_hw_mgr_ctx *ctx) return cam_ife_mgr_bw_control(ctx, CAM_VFE_BW_CONTROL_INCLUDE); } +static int cam_ife_mgr_sof_irq_debug( + struct cam_ife_hw_mgr_ctx *ctx, + uint32_t sof_irq_enable) +{ + int rc = 0; + uint32_t i = 0; + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_hw_intf *hw_intf = NULL; + struct cam_isp_resource_node *rsrc_node = NULL; + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + hw_intf = hw_mgr_res->hw_res[i]->hw_intf; + if (hw_intf->hw_ops.process_cmd) { + rc |= hw_intf->hw_ops.process_cmd( + hw_intf->hw_priv, + CAM_IFE_CSID_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + list_for_each_entry(hw_mgr_res, &ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i]) + continue; + + rsrc_node = hw_mgr_res->hw_res[i]; + if (rsrc_node->process_cmd && (rsrc_node->res_id == + CAM_ISP_HW_VFE_IN_CAMIF)) { + rc |= hw_mgr_res->hw_res[i]->process_cmd( + hw_mgr_res->hw_res[i], + CAM_ISP_HW_CMD_SOF_IRQ_DEBUG, + &sof_irq_enable, + sizeof(sof_irq_enable)); + } + } + } + + return rc; +} + static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) { int rc = 0; @@ -2695,6 +2776,9 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) case CAM_ISP_HW_MGR_CMD_RESUME_HW: cam_ife_mgr_resume_hw(ctx); break; + case CAM_ISP_HW_MGR_CMD_SOF_DEBUG: + cam_ife_mgr_sof_irq_debug(ctx, hw_cmd_args->u.sof_irq_enable); + break; default: CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", hw_cmd_args->cmd_type); @@ -4218,7 +4302,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf) /* Create Worker for ife_hw_mgr with 10 tasks */ rc = cam_req_mgr_workq_create("cam_ife_worker", 10, - &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ); + &g_ife_hw_mgr.workq, CRM_WORKQ_USAGE_NON_IRQ, 0); if (rc < 0) { CAM_ERR(CAM_ISP, "Unable to create worker"); goto end; 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 e869e2bdc9184551541f275ad5c990640aea02fe..abc6bb0a6db897cd75a31fa8acdb2addfef9ab0f 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 @@ -70,6 +70,12 @@ int cam_isp_add_change_base( hw_entry[num_ent].handle = kmd_buf_info->handle; hw_entry[num_ent].len = get_base.cmd.used_bytes; hw_entry[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); kmd_buf_info->used_bytes += get_base.cmd.used_bytes; kmd_buf_info->offset += get_base.cmd.used_bytes; @@ -184,6 +190,16 @@ int cam_isp_add_cmd_buf_update( return -EINVAL; } + cmd_update.cmd_type = hw_cmd_type; + cmd_update.cmd.cmd_buf_addr = cmd_buf_addr; + cmd_update.cmd.size = kmd_buf_remain_size; + cmd_update.cmd.used_bytes = 0; + cmd_update.data = cmd_update_data; + CAM_DBG(CAM_ISP, "cmd_type %u cmd buffer 0x%pK, size %d", + cmd_update.cmd_type, + cmd_update.cmd.cmd_buf_addr, + cmd_update.cmd.size); + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { if (!hw_mgr_res->hw_res[i]) continue; @@ -193,14 +209,7 @@ int cam_isp_add_cmd_buf_update( res = hw_mgr_res->hw_res[i]; cmd_update.res = res; - cmd_update.cmd_type = hw_cmd_type; - cmd_update.cmd.cmd_buf_addr = cmd_buf_addr; - cmd_update.cmd.size = kmd_buf_remain_size; - cmd_update.data = cmd_update_data; - - CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", - cmd_update.cmd.cmd_buf_addr, - cmd_update.cmd.size); + rc = res->hw_intf->hw_ops.process_cmd( res->hw_intf->hw_priv, cmd_update.cmd_type, &cmd_update, @@ -280,6 +289,12 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle = cmd_desc[i].mem_handle; hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Left num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_LEFT) @@ -295,6 +310,12 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle = cmd_desc[i].mem_handle; hw_entry[num_ent].offset = cmd_desc[i].offset; + CAM_DBG(CAM_ISP, + "Meta_Right num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_RIGHT) @@ -308,7 +329,12 @@ int cam_isp_add_command_buffers( hw_entry[num_ent].handle = cmd_desc[i].mem_handle; hw_entry[num_ent].offset = cmd_desc[i].offset; - + CAM_DBG(CAM_ISP, + "Meta_Common num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + hw_entry[num_ent].handle, + hw_entry[num_ent].len, + hw_entry[num_ent].offset); if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON) hw_entry[num_ent].flags = 0x1; @@ -443,11 +469,12 @@ int cam_isp_add_io_buffers( for (i = 0; i < prepare->packet->num_io_configs; i++) { CAM_DBG(CAM_ISP, "======= io config idx %d ============", i); - CAM_DBG(CAM_ISP, "i %d resource_type:%d fence:%d", - i, io_cfg[i].resource_type, io_cfg[i].fence); - CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); - CAM_DBG(CAM_ISP, "direction %d", + CAM_DBG(CAM_REQ, + "i %d req_id %llu resource_type:%d fence:%d direction %d", + i, prepare->packet->header.request_id, + io_cfg[i].resource_type, io_cfg[i].fence, io_cfg[i].direction); + CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); if (io_cfg[i].direction == CAM_BUF_OUTPUT) { res_id_out = io_cfg[i].resource_type & 0xFF; @@ -647,6 +674,12 @@ int cam_isp_add_io_buffers( prepare->hw_update_entries[num_ent].len = io_cfg_used_bytes; prepare->hw_update_entries[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); num_ent++; kmd_buf_info->used_bytes += io_cfg_used_bytes; @@ -741,6 +774,12 @@ int cam_isp_add_reg_update( prepare->hw_update_entries[num_ent].len = reg_update_size; prepare->hw_update_entries[num_ent].offset = kmd_buf_info->offset; + CAM_DBG(CAM_ISP, + "num_ent=%d handle=0x%x, len=%u, offset=%u", + num_ent, + prepare->hw_update_entries[num_ent].handle, + prepare->hw_update_entries[num_ent].len, + prepare->hw_update_entries[num_ent].offset); num_ent++; kmd_buf_info->used_bytes += reg_update_size; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index 3a897328eeb3f1ea912dcf354dd42d09b901b273..2c08e4d3cf85eaad34140116b7ca302b208968b3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -70,41 +70,44 @@ struct cam_tasklet_info { void *ctx_priv; }; -/** - * cam_tasklet_get_cmd() - * - * @brief: Get free cmd from tasklet - * - * @tasklet: Tasklet Info structure to get cmd from - * @tasklet_cmd: Return tasklet_cmd pointer if successful - * - * @return: 0: Success - * Negative: Failure - */ -static int cam_tasklet_get_cmd( - struct cam_tasklet_info *tasklet, - struct cam_tasklet_queue_cmd **tasklet_cmd) +struct cam_irq_bh_api tasklet_bh_api = { + .bottom_half_enqueue_func = cam_tasklet_enqueue_cmd, + .get_bh_payload_func = cam_tasklet_get_cmd, + .put_bh_payload_func = cam_tasklet_put_cmd, +}; + +int cam_tasklet_get_cmd( + void *bottom_half, + void **bh_cmd) { int rc = 0; unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; - *tasklet_cmd = NULL; + *bh_cmd = NULL; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return -EINVAL; + } if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active!\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active"); rc = -EPIPE; return rc; } spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->free_cmd_list)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd!\n"); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No more free tasklet cmd"); rc = -ENODEV; goto spin_unlock; } else { - *tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, + tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, struct cam_tasklet_queue_cmd, list); - list_del_init(&(*tasklet_cmd)->list); + list_del_init(&(tasklet_cmd)->list); + *bh_cmd = tasklet_cmd; } spin_unlock: @@ -112,25 +115,28 @@ static int cam_tasklet_get_cmd( return rc; } -/** - * cam_tasklet_put_cmd() - * - * @brief: Put back cmd to free list - * - * @tasklet: Tasklet Info structure to put cmd into - * @tasklet_cmd: tasklet_cmd pointer that needs to be put back - * - * @return: Void - */ -static void cam_tasklet_put_cmd( - struct cam_tasklet_info *tasklet, - struct cam_tasklet_queue_cmd **tasklet_cmd) +void cam_tasklet_put_cmd( + void *bottom_half, + void **bh_cmd) { unsigned long flags; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = *bh_cmd; + + if (tasklet == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "tasklet is NULL"); + return; + } + + if (tasklet_cmd == NULL) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Invalid tasklet_cmd"); + return; + } spin_lock_irqsave(&tasklet->tasklet_lock, flags); - list_add_tail(&(*tasklet_cmd)->list, - &tasklet->free_cmd_list); + list_del_init(&tasklet_cmd->list); + list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list); + *bh_cmd = NULL; spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); } @@ -157,12 +163,6 @@ static int cam_tasklet_dequeue_cmd( *tasklet_cmd = NULL; - if (!atomic_read(&tasklet->tasklet_active)) { - CAM_ERR(CAM_ISP, "Tasklet is not active!"); - rc = -EPIPE; - return rc; - } - CAM_DBG(CAM_ISP, "Dequeue before lock."); spin_lock_irqsave(&tasklet->tasklet_lock, flags); if (list_empty(&tasklet->used_cmd_list)) { @@ -181,38 +181,40 @@ static int cam_tasklet_dequeue_cmd( return rc; } -int cam_tasklet_enqueue_cmd( +void cam_tasklet_enqueue_cmd( void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler) { - struct cam_tasklet_info *tasklet = bottom_half; - struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; unsigned long flags; - int rc; + struct cam_tasklet_queue_cmd *tasklet_cmd = bh_cmd; + struct cam_tasklet_info *tasklet = bottom_half; if (!bottom_half) { - CAM_ERR(CAM_ISP, "NULL bottom half"); - return -EINVAL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bottom half"); + return; } - rc = cam_tasklet_get_cmd(tasklet, &tasklet_cmd); - - if (tasklet_cmd) { - CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); - tasklet_cmd->bottom_half_handler = bottom_half_handler; - tasklet_cmd->payload = evt_payload_priv; - spin_lock_irqsave(&tasklet->tasklet_lock, flags); - list_add_tail(&tasklet_cmd->list, - &tasklet->used_cmd_list); - spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); - tasklet_schedule(&tasklet->tasklet); - } else { - CAM_ERR(CAM_ISP, "tasklet cmd is NULL!"); + if (!bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bh cmd"); + return; } - return rc; + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active\n"); + return; + } + + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); + tasklet_cmd->bottom_half_handler = bottom_half_handler; + tasklet_cmd->payload = evt_payload_priv; + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_add_tail(&tasklet_cmd->list, + &tasklet->used_cmd_list); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + tasklet_schedule(&tasklet->tasklet); } int cam_tasklet_init( @@ -244,7 +246,7 @@ int cam_tasklet_init( } tasklet_init(&tasklet->tasklet, cam_tasklet_action, (unsigned long)tasklet); - cam_tasklet_stop(tasklet); + tasklet_disable(&tasklet->tasklet); *tasklet_info = tasklet; @@ -255,19 +257,18 @@ void cam_tasklet_deinit(void **tasklet_info) { struct cam_tasklet_info *tasklet = *tasklet_info; - atomic_set(&tasklet->tasklet_active, 0); - tasklet_kill(&tasklet->tasklet); + if (atomic_read(&tasklet->tasklet_active)) { + atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); + tasklet_disable(&tasklet->tasklet); + } kfree(tasklet); *tasklet_info = NULL; } -static void cam_tasklet_flush(void *tasklet_info) +static inline void cam_tasklet_flush(struct cam_tasklet_info *tasklet_info) { - unsigned long data; - struct cam_tasklet_info *tasklet = tasklet_info; - - data = (unsigned long)tasklet; - cam_tasklet_action(data); + cam_tasklet_action((unsigned long) tasklet_info); } int cam_tasklet_start(void *tasklet_info) @@ -280,7 +281,6 @@ int cam_tasklet_start(void *tasklet_info) tasklet->index); return -EBUSY; } - atomic_set(&tasklet->tasklet_active, 1); /* clean up the command queue first */ for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { @@ -289,6 +289,8 @@ int cam_tasklet_start(void *tasklet_info) &tasklet->free_cmd_list); } + atomic_set(&tasklet->tasklet_active, 1); + tasklet_enable(&tasklet->tasklet); return 0; @@ -298,9 +300,10 @@ void cam_tasklet_stop(void *tasklet_info) { struct cam_tasklet_info *tasklet = tasklet_info; - cam_tasklet_flush(tasklet); atomic_set(&tasklet->tasklet_active, 0); + tasklet_kill(&tasklet->tasklet); tasklet_disable(&tasklet->tasklet); + cam_tasklet_flush(tasklet); } /* @@ -323,7 +326,7 @@ static void cam_tasklet_action(unsigned long data) while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) { tasklet_cmd->bottom_half_handler(tasklet_info->ctx_priv, tasklet_cmd->payload); - cam_tasklet_put_cmd(tasklet_info, &tasklet_cmd); + cam_tasklet_put_cmd(tasklet_info, (void **)(&tasklet_cmd)); } } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h index 0e4bf1261ca1cd68d4713759b2ea3336adbe6591..8bd93d81f620988c091036ccaecc19d52852f889 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h @@ -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 @@ -76,6 +76,7 @@ void cam_tasklet_stop(void *tasklet); * @brief: Enqueue the tasklet_cmd to used list * * @bottom_half: Tasklet info to enqueue onto + * @bh_cmd: Tasklet cmd used to enqueue task * @handler_priv: Private Handler data that will be passed to the * handler function * @evt_payload_priv: Event payload that will be passed to the handler @@ -83,13 +84,40 @@ void cam_tasklet_stop(void *tasklet); * @bottom_half_handler: Callback function that will be called by tasklet * for handling event * - * @return: 0: Success - * Negative: Failure + * @return: Void */ -int cam_tasklet_enqueue_cmd( +void cam_tasklet_enqueue_cmd( void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler); +/** + * cam_tasklet_get_cmd() + * + * @brief: Get free cmd from tasklet + * + * @bottom_half: Tasklet Info structure to get cmd from + * @bh_cmd: Return tasklet_cmd pointer if successful + * + * @return: 0: Success + * Negative: Failure + */ +int cam_tasklet_get_cmd(void *bottom_half, void **bh_cmd); + +/** + * cam_tasklet_put_cmd() + * + * @brief: Put back cmd to free list + * + * @bottom_half: Tasklet Info structure to put cmd into + * @bh_cmd: tasklet_cmd pointer that needs to be put back + * + * @return: Void + */ +void cam_tasklet_put_cmd(void *bottom_half, void **bh_cmd); + +extern struct cam_irq_bh_api tasklet_bh_api; + #endif /* _CAM_TASKLET_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index feb79ccc658d3d76fb131bb4322f083219a8b984..e418fa97081d32dc7c8ea5bb3abdc7b55e617a91 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -13,6 +13,8 @@ #include #include #include +#include + #include "cam_io_util.h" #include "cam_irq_controller.h" #include "cam_debug_util.h" @@ -42,7 +44,7 @@ struct cam_irq_evt_handler { CAM_IRQ_HANDLER_TOP_HALF top_half_handler; CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler; void *bottom_half; - CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func; + struct cam_irq_bh_api irq_bh_api; struct list_head list_node; struct list_head th_list_node; int index; @@ -139,21 +141,21 @@ int cam_irq_controller_init(const char *name, if (!register_info->num_registers || !register_info->irq_reg_set || !name || !mem_base) { - CAM_ERR(CAM_ISP, "Invalid parameters"); + CAM_ERR(CAM_IRQ_CTRL, "Invalid parameters"); rc = -EINVAL; return rc; } controller = kzalloc(sizeof(struct cam_irq_controller), GFP_KERNEL); if (!controller) { - CAM_DBG(CAM_ISP, "Failed to allocate IRQ Controller"); + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ Controller"); return -ENOMEM; } controller->irq_register_arr = kzalloc(register_info->num_registers * sizeof(struct cam_irq_register_obj), GFP_KERNEL); if (!controller->irq_register_arr) { - CAM_DBG(CAM_ISP, "Failed to allocate IRQ register Arr"); + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ register Arr"); rc = -ENOMEM; goto reg_alloc_error; } @@ -161,7 +163,7 @@ int cam_irq_controller_init(const char *name, controller->irq_status_arr = kzalloc(register_info->num_registers * sizeof(uint32_t), GFP_KERNEL); if (!controller->irq_status_arr) { - CAM_DBG(CAM_ISP, "Failed to allocate IRQ status Arr"); + CAM_DBG(CAM_IRQ_CTRL, "Failed to allocate IRQ status Arr"); rc = -ENOMEM; goto status_alloc_error; } @@ -170,14 +172,16 @@ int cam_irq_controller_init(const char *name, kzalloc(register_info->num_registers * sizeof(uint32_t), GFP_KERNEL); if (!controller->th_payload.evt_status_arr) { - CAM_DBG(CAM_ISP, "Failed to allocate BH payload bit mask Arr"); + CAM_DBG(CAM_IRQ_CTRL, + "Failed to allocate BH payload bit mask Arr"); rc = -ENOMEM; goto evt_mask_alloc_error; } controller->name = name; - CAM_DBG(CAM_ISP, "num_registers: %d", register_info->num_registers); + CAM_DBG(CAM_IRQ_CTRL, "num_registers: %d", + register_info->num_registers); for (i = 0; i < register_info->num_registers; i++) { controller->irq_register_arr[i].index = i; controller->irq_register_arr[i].mask_reg_offset = @@ -186,11 +190,11 @@ int cam_irq_controller_init(const char *name, register_info->irq_reg_set[i].clear_reg_offset; controller->irq_register_arr[i].status_reg_offset = register_info->irq_reg_set[i].status_reg_offset; - CAM_DBG(CAM_ISP, "i %d mask_reg_offset: 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "i %d mask_reg_offset: 0x%x", i, controller->irq_register_arr[i].mask_reg_offset); - CAM_DBG(CAM_ISP, "i %d clear_reg_offset: 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "i %d clear_reg_offset: 0x%x", i, controller->irq_register_arr[i].clear_reg_offset); - CAM_DBG(CAM_ISP, "i %d status_reg_offset: 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "i %d status_reg_offset: 0x%x", i, controller->irq_register_arr[i].status_reg_offset); } controller->num_registers = register_info->num_registers; @@ -198,11 +202,12 @@ int cam_irq_controller_init(const char *name, controller->global_clear_offset = register_info->global_clear_offset; controller->mem_base = mem_base; - CAM_DBG(CAM_ISP, "global_clear_bitmask: 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "global_clear_bitmask: 0x%x", controller->global_clear_bitmask); - CAM_DBG(CAM_ISP, "global_clear_offset: 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "global_clear_offset: 0x%x", controller->global_clear_offset); - CAM_DBG(CAM_ISP, "mem_base: %pK", (void __iomem *)controller->mem_base); + CAM_DBG(CAM_IRQ_CTRL, "mem_base: %pK", + (void __iomem *)controller->mem_base); INIT_LIST_HEAD(&controller->evt_handler_list_head); for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) @@ -232,7 +237,7 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, CAM_IRQ_HANDLER_TOP_HALF top_half_handler, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, void *bottom_half, - CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func) + struct cam_irq_bh_api *irq_bh_api) { struct cam_irq_controller *controller = irq_controller; struct cam_irq_evt_handler *evt_handler = NULL; @@ -243,43 +248,55 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, bool need_lock; if (!controller || !handler_priv || !evt_bit_mask_arr) { - CAM_ERR(CAM_ISP, + CAM_ERR(CAM_IRQ_CTRL, "Inval params: ctlr=%pK hdl_priv=%pK bit_mask_arr=%pK", controller, handler_priv, evt_bit_mask_arr); return -EINVAL; } if (!top_half_handler) { - CAM_ERR(CAM_ISP, "Missing top half handler"); + CAM_ERR(CAM_IRQ_CTRL, "Missing top half handler"); return -EINVAL; } if (bottom_half_handler && - (!bottom_half || !bottom_half_enqueue_func)) { - CAM_ERR(CAM_ISP, + (!bottom_half || !irq_bh_api)) { + CAM_ERR(CAM_IRQ_CTRL, "Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK", bottom_half_handler, bottom_half, - bottom_half_enqueue_func); + irq_bh_api); + return -EINVAL; + } + + if (irq_bh_api && + (!irq_bh_api->bottom_half_enqueue_func || + !irq_bh_api->get_bh_payload_func || + !irq_bh_api->put_bh_payload_func)) { + CAM_ERR(CAM_IRQ_CTRL, + "Invalid: enqueue_func=%pK get_bh=%pK put_bh=%pK", + irq_bh_api->bottom_half_enqueue_func, + irq_bh_api->get_bh_payload_func, + irq_bh_api->put_bh_payload_func); return -EINVAL; } if (priority >= CAM_IRQ_PRIORITY_MAX) { - CAM_ERR(CAM_ISP, "Invalid priority=%u, max=%u", priority, + CAM_ERR(CAM_IRQ_CTRL, "Invalid priority=%u, max=%u", priority, CAM_IRQ_PRIORITY_MAX); return -EINVAL; } evt_handler = kzalloc(sizeof(struct cam_irq_evt_handler), GFP_KERNEL); if (!evt_handler) { - CAM_DBG(CAM_ISP, "Error allocating hlist_node"); + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); return -ENOMEM; } evt_handler->evt_bit_mask_arr = kzalloc(sizeof(uint32_t) * controller->num_registers, GFP_KERNEL); if (!evt_handler->evt_bit_mask_arr) { - CAM_DBG(CAM_ISP, "Error allocating hlist_node"); + CAM_DBG(CAM_IRQ_CTRL, "Error allocating hlist_node"); rc = -ENOMEM; goto free_evt_handler; } @@ -295,9 +312,11 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, evt_handler->top_half_handler = top_half_handler; evt_handler->bottom_half_handler = bottom_half_handler; evt_handler->bottom_half = bottom_half; - evt_handler->bottom_half_enqueue_func = bottom_half_enqueue_func; evt_handler->index = controller->hdl_idx++; + if (irq_bh_api) + evt_handler->irq_bh_api = *irq_bh_api; + /* Avoid rollover to negative values */ if (controller->hdl_idx > 0x3FFFFFFF) controller->hdl_idx = 1; @@ -358,7 +377,7 @@ int cam_irq_controller_enable_irq(void *irq_controller, uint32_t handle) list_for_each_entry_safe(evt_handler, evt_handler_temp, &controller->evt_handler_list_head, list_node) { if (evt_handler->index == handle) { - CAM_DBG(CAM_ISP, "enable item %d", handle); + CAM_DBG(CAM_IRQ_CTRL, "enable item %d", handle); found = 1; rc = 0; break; @@ -414,7 +433,7 @@ int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle) list_for_each_entry_safe(evt_handler, evt_handler_temp, &controller->evt_handler_list_head, list_node) { if (evt_handler->index == handle) { - CAM_DBG(CAM_ISP, "disable item %d", handle); + CAM_DBG(CAM_IRQ_CTRL, "disable item %d", handle); found = 1; rc = 0; break; @@ -435,13 +454,13 @@ int cam_irq_controller_disable_irq(void *irq_controller, uint32_t handle) irq_mask = cam_io_r_mb(controller->mem_base + irq_register->mask_reg_offset); - CAM_DBG(CAM_ISP, "irq_mask 0x%x before disable 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x before disable 0x%x", irq_register->mask_reg_offset, irq_mask); irq_mask &= ~(evt_handler->evt_bit_mask_arr[i]); cam_io_w_mb(irq_mask, controller->mem_base + irq_register->mask_reg_offset); - CAM_DBG(CAM_ISP, "irq_mask 0x%x after disable 0x%x", + CAM_DBG(CAM_IRQ_CTRL, "irq_mask 0x%x after disable 0x%x", irq_register->mask_reg_offset, irq_mask); /* Clear the IRQ bits of this handler */ @@ -483,7 +502,7 @@ int cam_irq_controller_unsubscribe_irq(void *irq_controller, list_for_each_entry_safe(evt_handler, evt_handler_temp, &controller->evt_handler_list_head, list_node) { if (evt_handler->index == handle) { - CAM_DBG(CAM_ISP, "unsubscribe item %d", handle); + CAM_DBG(CAM_IRQ_CTRL, "unsubscribe item %d", handle); list_del_init(&evt_handler->list_node); list_del_init(&evt_handler->th_list_node); found = 1; @@ -564,8 +583,10 @@ static void cam_irq_controller_th_processing( bool is_irq_match; int rc = -EINVAL; int i; + void *bh_cmd = NULL; + struct cam_irq_bh_api *irq_bh_api = NULL; - CAM_DBG(CAM_ISP, "Enter"); + CAM_DBG(CAM_IRQ_CTRL, "Enter"); if (list_empty(th_list_head)) return; @@ -577,7 +598,7 @@ static void cam_irq_controller_th_processing( if (!is_irq_match) continue; - CAM_DBG(CAM_ISP, "match found"); + CAM_DBG(CAM_IRQ_CTRL, "match found"); cam_irq_th_payload_init(th_payload); th_payload->handler_priv = evt_handler->handler_priv; @@ -588,6 +609,19 @@ static void cam_irq_controller_th_processing( evt_handler->evt_bit_mask_arr[i]; } + irq_bh_api = &evt_handler->irq_bh_api; + bh_cmd = NULL; + + if (evt_handler->bottom_half_handler) { + rc = irq_bh_api->get_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + if (rc || !bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can't get bh payload"); + continue; + } + } + /* * irq_status_arr[0] is dummy argument passed. the entire * status array is passed in th_payload. @@ -597,20 +631,25 @@ static void cam_irq_controller_th_processing( controller->irq_status_arr[0], (void *)th_payload); - if (!rc && evt_handler->bottom_half_handler) { - CAM_DBG(CAM_ISP, "Enqueuing bottom half for %s", + if (rc && bh_cmd) { + irq_bh_api->put_bh_payload_func( + evt_handler->bottom_half, &bh_cmd); + continue; + } + + if (evt_handler->bottom_half_handler) { + CAM_DBG(CAM_IRQ_CTRL, "Enqueuing bottom half for %s", controller->name); - if (evt_handler->bottom_half_enqueue_func) { - evt_handler->bottom_half_enqueue_func( - evt_handler->bottom_half, - evt_handler->handler_priv, - th_payload->evt_payload_priv, - evt_handler->bottom_half_handler); - } + irq_bh_api->bottom_half_enqueue_func( + evt_handler->bottom_half, + bh_cmd, + evt_handler->handler_priv, + th_payload->evt_payload_priv, + evt_handler->bottom_half_handler); } } - CAM_DBG(CAM_ISP, "Exit"); + CAM_DBG(CAM_IRQ_CTRL, "Exit"); } irqreturn_t cam_irq_controller_clear_and_mask(int irq_num, void *priv) @@ -651,7 +690,7 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) if (!controller) return IRQ_NONE; - CAM_DBG(CAM_ISP, "locking controller %pK name %s lock %pK", + CAM_DBG(CAM_IRQ_CTRL, "locking controller %pK name %s lock %pK", controller, controller->name, &controller->lock); spin_lock(&controller->lock); for (i = 0; i < controller->num_registers; i++) { @@ -662,36 +701,36 @@ irqreturn_t cam_irq_controller_handle_irq(int irq_num, void *priv) cam_io_w_mb(controller->irq_status_arr[i], controller->mem_base + controller->irq_register_arr[i].clear_reg_offset); - CAM_DBG(CAM_ISP, "Read irq status%d (0x%x) = 0x%x", i, + CAM_DBG(CAM_IRQ_CTRL, "Read irq status%d (0x%x) = 0x%x", i, controller->irq_register_arr[i].status_reg_offset, controller->irq_status_arr[i]); for (j = 0; j < CAM_IRQ_PRIORITY_MAX; j++) { if (irq_register->top_half_enable_mask[j] & controller->irq_status_arr[i]) need_th_processing[j] = true; - CAM_DBG(CAM_ISP, + CAM_DBG(CAM_IRQ_CTRL, "i %d j %d need_th_processing = %d", i, j, need_th_processing[j]); } } - CAM_DBG(CAM_ISP, "Status Registers read Successful"); + CAM_DBG(CAM_IRQ_CTRL, "Status Registers read Successful"); if (controller->global_clear_offset) cam_io_w_mb(controller->global_clear_bitmask, controller->mem_base + controller->global_clear_offset); - CAM_DBG(CAM_ISP, "Status Clear done"); + CAM_DBG(CAM_IRQ_CTRL, "Status Clear done"); for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) { if (need_th_processing[i]) { - CAM_DBG(CAM_ISP, "Invoke TH processing"); + CAM_DBG(CAM_IRQ_CTRL, "Invoke TH processing"); cam_irq_controller_th_processing(controller, &controller->th_list_head[i]); } } spin_unlock(&controller->lock); - CAM_DBG(CAM_ISP, "unlocked controller %pK name %s lock %pK", + CAM_DBG(CAM_IRQ_CTRL, "unlocked controller %pK name %s lock %pK", controller, controller->name, &controller->lock); return IRQ_HANDLED; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h index e3071ac2f2309fbd6e3c8507f8b6bbd04af4483a..c3c1e7c936cec1e0f7f3afe57e0b2025c285fef8 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h @@ -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 @@ -111,10 +111,22 @@ typedef int (*CAM_IRQ_HANDLER_TOP_HALF)(uint32_t evt_id, typedef int (*CAM_IRQ_HANDLER_BOTTOM_HALF)(void *handler_priv, void *evt_payload_priv); -typedef int (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half, - void *handler_priv, void *evt_payload_priv, +typedef void (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bottom_half, + void *bh_cmd, void *handler_priv, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF); +typedef int (*CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +typedef void (*CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC)(void *bottom_half, + void **bh_cmd); + +struct cam_irq_bh_api { + CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func; + CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC get_bh_payload_func; + CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC put_bh_payload_func; +}; + /* * cam_irq_controller_init() * @@ -165,7 +177,7 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, CAM_IRQ_HANDLER_TOP_HALF top_half_handler, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler, void *bottom_half, - CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC bottom_half_enqueue_func); + struct cam_irq_bh_api *irq_bh_api); /* * cam_irq_controller_unsubscribe_irq() diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 5410858e27a3bef8362f7ceec4f8e9452ef6a0ac..8f1911edf2c91e70d571b7c8f5c126e0994e3e26 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -180,6 +180,7 @@ enum cam_isp_hw_mgr_command { CAM_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT, CAM_ISP_HW_MGR_CMD_PAUSE_HW, CAM_ISP_HW_MGR_CMD_RESUME_HW, + CAM_ISP_HW_MGR_CMD_SOF_DEBUG, CAM_ISP_HW_MGR_CMD_MAX, }; @@ -195,6 +196,7 @@ struct cam_isp_hw_cmd_args { uint32_t cmd_type; union { uint32_t is_rdi_only_context; + uint32_t sof_irq_enable; } u; }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c index bdd59d232f700bf8e278d3fdd790b0c5c116eb6e..70223f1427f5f5c85f685a2554748f9241e2f3e3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.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 @@ -41,6 +41,7 @@ static struct platform_driver cam_ife_csid170_driver = { .name = CAM_CSID_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid170_dt_match, + .suppress_bind_attrs = true, }, }; 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 3edae4a53d28a74772b0a0a1da31608a5584521e..e5fb03f550866bbc03561f084642379ce5294080 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 @@ -20,6 +20,7 @@ #include "cam_soc_util.h" #include "cam_io_util.h" #include "cam_debug_util.h" +#include "cam_cpas_api.h" /* Timeout value in msec */ #define IFE_CSID_TIMEOUT 1000 @@ -286,67 +287,49 @@ static int cam_ife_csid_get_format_ipp( } static int cam_ife_csid_cid_get(struct cam_ife_csid_hw *csid_hw, - struct cam_isp_resource_node **res, int32_t vc, uint32_t dt, - uint32_t res_type) + struct cam_isp_resource_node **res, int32_t vc, uint32_t dt) { - int rc = 0; struct cam_ife_csid_cid_data *cid_data; - uint32_t i = 0, j = 0; + uint32_t i = 0; + *res = NULL; + + /* Return already reserved CID if the VC/DT matches */ for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { if (csid_hw->cid_res[i].res_state >= CAM_ISP_RESOURCE_STATE_RESERVED) { cid_data = (struct cam_ife_csid_cid_data *) csid_hw->cid_res[i].res_priv; - if (res_type == CAM_ISP_IFE_IN_RES_TPG) { - if (cid_data->tpg_set) { - cid_data->cnt++; - *res = &csid_hw->cid_res[i]; - break; - } - } else { - if (cid_data->vc == vc && cid_data->dt == dt) { - cid_data->cnt++; - *res = &csid_hw->cid_res[i]; - break; - } + if (cid_data->vc == vc && cid_data->dt == dt) { + cid_data->cnt++; + *res = &csid_hw->cid_res[i]; + return 0; } } } - if (i == CAM_IFE_CSID_CID_RES_MAX) { - if (res_type == CAM_ISP_IFE_IN_RES_TPG) { - CAM_ERR(CAM_ISP, "CSID:%d TPG CID not available", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - } - - for (j = 0; j < CAM_IFE_CSID_CID_RES_MAX; j++) { - if (csid_hw->cid_res[j].res_state == - CAM_ISP_RESOURCE_STATE_AVAILABLE) { - cid_data = (struct cam_ife_csid_cid_data *) - csid_hw->cid_res[j].res_priv; - cid_data->vc = vc; - cid_data->dt = dt; - cid_data->cnt = 1; - csid_hw->cid_res[j].res_state = - CAM_ISP_RESOURCE_STATE_RESERVED; - *res = &csid_hw->cid_res[j]; - CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", - csid_hw->hw_intf->hw_idx, - csid_hw->cid_res[j].res_id); - break; - } - } - - if (j == CAM_IFE_CSID_CID_RES_MAX) { - CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; + for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { + if (csid_hw->cid_res[i].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[i].res_priv; + cid_data->vc = vc; + cid_data->dt = dt; + cid_data->cnt = 1; + csid_hw->cid_res[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + *res = &csid_hw->cid_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[i].res_id); + return 0; } } - return rc; + CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", + csid_hw->hw_intf->hw_idx); + + return -EINVAL; } @@ -547,6 +530,7 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, { int rc = 0; struct cam_ife_csid_cid_data *cid_data; + uint32_t camera_hw_version; CAM_DBG(CAM_ISP, "CSID:%d res_sel:0x%x Lane type:%d lane_num:%d dt:%d vc:%d", @@ -614,12 +598,40 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, goto end; } - if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && - csid_hw->hw_intf->hw_idx != 2) { + if (csid_hw->csi2_reserve_cnt == UINT_MAX) { + CAM_ERR(CAM_ISP, + "CSID%d reserve cnt reached max", + csid_hw->hw_intf->hw_idx); rc = -EINVAL; goto end; } + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to get HW version rc:%d", rc); + goto end; + } + CAM_DBG(CAM_ISP, "HW version: %d", 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); + break; + case CAM_CPAS_TITAN_170_V100: + case CAM_CPAS_TITAN_170_V110: + case CAM_CPAS_TITAN_170_V120: + if (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && + csid_hw->hw_intf->hw_idx != 2) { + rc = -EINVAL; + goto end; + } + break; + default: + break; + } + CAM_DBG(CAM_ISP, "Reserve_cnt %u", csid_hw->csi2_reserve_cnt); + if (csid_hw->csi2_reserve_cnt) { /* current configure res type should match requested res type */ if (csid_hw->res_type != cid_reserv->in_port->res_type) { @@ -652,12 +664,53 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, } } + switch (cid_reserv->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + if (csid_hw->ipp_res.res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_DBG(CAM_ISP, + "CSID:%d IPP resource not available", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + break; + case CAM_IFE_PIX_PATH_RES_RDI_0: + case CAM_IFE_PIX_PATH_RES_RDI_1: + case CAM_IFE_PIX_PATH_RES_RDI_2: + case CAM_IFE_PIX_PATH_RES_RDI_3: + if (csid_hw->rdi_res[cid_reserv->res_id].res_state != + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + CAM_ERR(CAM_ISP, + "CSID:%d RDI:%d resource not available", + csid_hw->hw_intf->hw_idx, + cid_reserv->res_id); + rc = -EINVAL; + goto end; + } + break; + default: + CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + goto end; + } + + rc = cam_ife_csid_cid_get(csid_hw, + &cid_reserv->node_res, + cid_reserv->in_port->vc, + cid_reserv->in_port->dt); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d CID Reserve failed res_type %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->res_type); + goto end; + } + cid_data = (struct cam_ife_csid_cid_data *) + cid_reserv->node_res->res_priv; + if (!csid_hw->csi2_reserve_cnt) { csid_hw->res_type = cid_reserv->in_port->res_type; - /* Take the first CID resource*/ - csid_hw->cid_res[0].res_state = CAM_ISP_RESOURCE_STATE_RESERVED; - cid_data = (struct cam_ife_csid_cid_data *) - csid_hw->cid_res[0].res_priv; csid_hw->csi2_rx_cfg.lane_cfg = cid_reserv->in_port->lane_cfg; @@ -699,71 +752,13 @@ static int cam_ife_csid_cid_reserve(struct cam_ife_csid_hw *csid_hw, csid_hw->csi2_rx_cfg.phy_sel = (cid_reserv->in_port->res_type & 0xFF) - 1; } - - cid_data->vc = cid_reserv->in_port->vc; - cid_data->dt = cid_reserv->in_port->dt; - cid_data->cnt = 1; - cid_reserv->node_res = &csid_hw->cid_res[0]; - csid_hw->csi2_reserve_cnt++; - - CAM_DBG(CAM_ISP, - "CSID:%d CID :%d resource acquired successfully", - csid_hw->hw_intf->hw_idx, - cid_reserv->node_res->res_id); - } else { - switch (cid_reserv->res_id) { - case CAM_IFE_PIX_PATH_RES_IPP: - if (csid_hw->ipp_res.res_state != - CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_DBG(CAM_ISP, - "CSID:%d IPP resource not available", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - goto end; - } - break; - case CAM_IFE_PIX_PATH_RES_RDI_0: - case CAM_IFE_PIX_PATH_RES_RDI_1: - case CAM_IFE_PIX_PATH_RES_RDI_2: - case CAM_IFE_PIX_PATH_RES_RDI_3: - if (csid_hw->rdi_res[cid_reserv->res_id].res_state != - CAM_ISP_RESOURCE_STATE_AVAILABLE) { - CAM_DBG(CAM_ISP, - "CSID:%d RDI:%d resource not available", - csid_hw->hw_intf->hw_idx, - cid_reserv->res_id); - rc = -EINVAL; - goto end; - } - break; - default: - CAM_ERR(CAM_ISP, "CSID%d: Invalid csid path", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - goto end; - } - - rc = cam_ife_csid_cid_get(csid_hw, - &cid_reserv->node_res, - cid_reserv->in_port->vc, - cid_reserv->in_port->dt, - cid_reserv->in_port->res_type); - /* if success then increment the reserve count */ - if (!rc) { - if (csid_hw->csi2_reserve_cnt == UINT_MAX) { - CAM_ERR(CAM_ISP, - "CSID%d reserve cnt reached max", - csid_hw->hw_intf->hw_idx); - rc = -EINVAL; - } else { - csid_hw->csi2_reserve_cnt++; - CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", - csid_hw->hw_intf->hw_idx, - cid_reserv->node_res->res_id); - } - } } + csid_hw->csi2_reserve_cnt++; + CAM_DBG(CAM_ISP, "CSID:%d CID:%d acquired", + csid_hw->hw_intf->hw_idx, + cid_reserv->node_res->res_id); + end: return rc; } @@ -1856,8 +1851,8 @@ static int cam_ife_csid_disable_rdi_path( soc_info = &csid_hw->hw_info->soc_info; id = res->res_id; - if (res->res_id >= CAM_IFE_PIX_PATH_RES_MAX || - !csid_reg->rdi_reg[res->res_id]) { + if ((res->res_id > CAM_IFE_PIX_PATH_RES_RDI_3) || + (!csid_reg->rdi_reg[res->res_id])) { CAM_ERR_RATE_LIMIT(CAM_ISP, "CSID:%d Invalid res id%d", csid_hw->hw_intf->hw_idx, res->res_id); return -EINVAL; @@ -2415,12 +2410,24 @@ static int cam_ife_csid_stop(void *hw_priv, return -EINVAL; } csid_stop = (struct cam_csid_hw_stop_args *) stop_args; + + if (!csid_stop->num_res) { + CAM_ERR(CAM_ISP, "CSID: Invalid args"); + return -EINVAL; + } + csid_hw_info = (struct cam_hw_info *)hw_priv; csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + CAM_DBG(CAM_ISP, "CSID:%d num_res %d", + csid_hw->hw_intf->hw_idx, + csid_stop->num_res); /* Stop the resource first */ for (i = 0; i < csid_stop->num_res; i++) { res = csid_stop->node_res[i]; + CAM_DBG(CAM_ISP, "CSID:%d res_type %d res_id %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); switch (res->res_type) { case CAM_ISP_RESOURCE_CID: if (csid_hw->res_type == CAM_ISP_IFE_IN_RES_TPG) @@ -2469,6 +2476,61 @@ static int cam_ife_csid_write(void *hw_priv, return -EINVAL; } +static int cam_ife_csid_sof_irq_debug( + struct cam_ife_csid_hw *csid_hw, void *cmd_args) +{ + int i = 0; + uint32_t val = 0; + bool sof_irq_enable = false; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + + if (*((uint32_t *)cmd_args) == 1) + sof_irq_enable = true; + + 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; + + 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++) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + if (val) { + if (sof_irq_enable) + val |= CSID_PATH_INFO_INPUT_SOF; + else + val &= ~CSID_PATH_INFO_INPUT_SOF; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_irq_mask_addr); + val = 0; + } + } + + if (sof_irq_enable) + csid_hw->csid_debug |= CSID_DEBUG_ENABLE_SOF_IRQ; + else + csid_hw->csid_debug &= ~CSID_DEBUG_ENABLE_SOF_IRQ; + + CAM_INFO(CAM_ISP, "SOF freeze: CSID SOF irq %s", + (sof_irq_enable == true) ? "enabled" : "disabled"); + + return 0; +} + static int cam_ife_csid_process_cmd(void *hw_priv, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -2491,8 +2553,11 @@ static int cam_ife_csid_process_cmd(void *hw_priv, case CAM_IFE_CSID_SET_CSID_DEBUG: rc = cam_ife_csid_set_csid_debug(csid_hw, cmd_args); break; + case CAM_IFE_CSID_SOF_IRQ_DEBUG: + rc = cam_ife_csid_sof_irq_debug(csid_hw, cmd_args); + break; default: - CAM_ERR(CAM_ISP, "CSID:%d un supported cmd:%d", + CAM_ERR(CAM_ISP, "CSID:%d unsupported cmd:%d", csid_hw->hw_intf->hw_idx, cmd_type); rc = -EINVAL; break; @@ -2777,6 +2842,7 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, { int rc = -EINVAL; uint32_t i; + uint32_t num_paths; struct cam_ife_csid_path_cfg *path_data; struct cam_ife_csid_cid_data *cid_data; struct cam_hw_info *csid_hw_info; @@ -2828,8 +2894,10 @@ int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, ife_csid_hw->hw_intf->hw_ops.write = cam_ife_csid_write; ife_csid_hw->hw_intf->hw_ops.process_cmd = cam_ife_csid_process_cmd; - /*Initialize the CID resoure */ - for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) { + num_paths = ife_csid_hw->csid_info->csid_reg->cmn_reg->no_pix + + ife_csid_hw->csid_info->csid_reg->cmn_reg->no_rdis; + /* Initialize the CID resource */ + for (i = 0; i < num_paths; i++) { ife_csid_hw->cid_res[i].res_type = CAM_ISP_RESOURCE_CID; ife_csid_hw->cid_res[i].res_id = i; ife_csid_hw->cid_res[i].res_state = diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c index 128c050284d4d61d967cb2952b507e0442fb9a57..2556b65875db4c4a3735e9fd662ecf53f864bc9a 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.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 @@ -21,6 +21,8 @@ static struct cam_hw_intf *cam_ife_csid_hw_list[CAM_IFE_CSID_HW_RES_MAX] = { 0, 0, 0, 0}; +static char csid_dev_name[8]; + int cam_ife_csid_probe(struct platform_device *pdev) { @@ -63,6 +65,10 @@ int cam_ife_csid_probe(struct platform_device *pdev) goto free_dev; } + memset(csid_dev_name, 0, sizeof(csid_dev_name)); + snprintf(csid_dev_name, sizeof(csid_dev_name), + "csid%1u", csid_dev_idx); + csid_hw_intf->hw_idx = csid_dev_idx; csid_hw_intf->hw_type = CAM_ISP_HW_TYPE_IFE_CSID; csid_hw_intf->hw_priv = csid_hw_info; @@ -70,7 +76,7 @@ int cam_ife_csid_probe(struct platform_device *pdev) csid_hw_info->core_info = csid_dev; csid_hw_info->soc_info.pdev = pdev; csid_hw_info->soc_info.dev = &pdev->dev; - csid_hw_info->soc_info.dev_name = pdev->name; + csid_hw_info->soc_info.dev_name = csid_dev_name; csid_hw_info->soc_info.index = csid_dev_idx; csid_hw_data = (struct cam_ife_csid_hw_info *)match_dev->data; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c index 36c6df0ae19429437f80f20bef61ab9f5c3b47d8..6c39bd84e47fc1b672ca72c613513deedb2cde7c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.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 @@ -39,6 +39,7 @@ static struct platform_driver cam_ife_csid_lite170_driver = { .name = CAM_CSID_LITE_DRV_NAME, .owner = THIS_MODULE, .of_match_table = cam_ife_csid_lite170_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c index e11ff6372ae0b5224ae8fe698c7a63b79b9f3c51..d3261f84e2f408f1db66eaa0754c41c406d252fc 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.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 @@ -112,8 +112,6 @@ int cam_ife_csid_deinit_soc_resources( CAM_ERR(CAM_ISP, "CPAS unregistration failed rc=%d", rc); rc = cam_soc_util_release_platform_resource(soc_info); - if (rc < 0) - return rc; return rc; } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h index 8911f9959fbe0890cdf1fae163199c5651f891a2..bbd092f2172cfdca9046b6bffa95026277864813 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -153,6 +153,7 @@ struct cam_csid_get_time_stamp_args { enum cam_ife_csid_cmd_type { CAM_IFE_CSID_CMD_GET_TIME_STAMP, CAM_IFE_CSID_SET_CSID_DEBUG, + CAM_IFE_CSID_SOF_IRQ_DEBUG, CAM_IFE_CSID_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h index c56c49fac5afdd25d26f1829906c6857e250337d..70e04677282df0b1f29446f5acacbeb90c739920 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -95,6 +95,7 @@ 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_SOF_IRQ_DEBUG, CAM_ISP_HW_CMD_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index fd38a964faf6b5b70791550f2532053c4eb1aba7..f6becfbf41a158914070de37af5abf597a849c3d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -560,7 +560,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet, isp_res->tasklet_info, - cam_tasklet_enqueue_cmd); + &tasklet_bh_api); if (isp_res->irq_handle < 1) rc = -ENOMEM; } else if (isp_res->rdi_only_ctx) { @@ -573,7 +573,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) cam_vfe_irq_top_half, cam_ife_mgr_do_tasklet, isp_res->tasklet_info, - cam_tasklet_enqueue_cmd); + &tasklet_bh_api); if (isp_res->irq_handle < 1) rc = -ENOMEM; } @@ -606,7 +606,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) cam_vfe_irq_err_top_half, cam_ife_mgr_do_tasklet, core_info->tasklet_info, - cam_tasklet_enqueue_cmd); + &tasklet_bh_api); if (core_info->irq_err_handle < 1) { CAM_ERR(CAM_ISP, "Error handle subscribe failure"); rc = -ENOMEM; @@ -639,10 +639,11 @@ int cam_vfe_stop(void *hw_priv, void *stop_args, uint32_t arg_size) if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { cam_irq_controller_unsubscribe_irq( core_info->vfe_irq_controller, isp_res->irq_handle); + isp_res->irq_handle = 0; + rc = core_info->vfe_top->hw_ops.stop( core_info->vfe_top->top_priv, isp_res, sizeof(struct cam_isp_resource_node)); - } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { rc = core_info->vfe_bus->hw_ops.stop(isp_res, NULL, 0); } else { diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c index 74627b8d32ef322f32d7643e442b8c1be78994db..66b647d3136b2f0a90ec6322fffaab941a679665 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.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 @@ -21,6 +21,8 @@ static struct cam_hw_intf *cam_vfe_hw_list[CAM_VFE_HW_NUM_MAX] = {0, 0, 0, 0}; +static char vfe_dev_name[8]; + int cam_vfe_probe(struct platform_device *pdev) { struct cam_hw_info *vfe_hw = NULL; @@ -44,9 +46,14 @@ int cam_vfe_probe(struct platform_device *pdev) rc = -ENOMEM; goto free_vfe_hw_intf; } + + memset(vfe_dev_name, 0, sizeof(vfe_dev_name)); + snprintf(vfe_dev_name, sizeof(vfe_dev_name), + "vfe%1u", vfe_hw_intf->hw_idx); + vfe_hw->soc_info.pdev = pdev; vfe_hw->soc_info.dev = &pdev->dev; - vfe_hw->soc_info.dev_name = pdev->name; + vfe_hw->soc_info.dev_name = vfe_dev_name; vfe_hw_intf->hw_priv = vfe_hw; vfe_hw_intf->hw_ops.get_hw_caps = cam_vfe_get_hw_caps; vfe_hw_intf->hw_ops.init = cam_vfe_init_hw; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c index 0af32ad5d5463e18ba91b4a66afa4503be8aa1b6..d002f84015de17494f9e8bc7849f98bd08f08f1c 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.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 @@ -32,6 +32,7 @@ static struct platform_driver cam_vfe170_driver = { .name = "cam_vfe170", .owner = THIS_MODULE, .of_match_table = cam_vfe170_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c index 3c8abbf065ab52ce1eff6d5f3c2225b89eb68609..ab692cf095e4729a5f70a6c08ba30c7403996570 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.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 @@ -32,6 +32,7 @@ static struct platform_driver cam_vfe170_driver = { .name = "cam_vfe_lite170", .owner = THIS_MODULE, .of_match_table = cam_vfe170_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index 3c37b83a22561e9e3dcc16c5294ef1b47732c50c..67b572e039d8bbebf0df24d356fcf74e3e6bc863 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1084,7 +1084,7 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) bus_irq_reg_mask, wm_res, wm_res->top_half_handler, cam_ife_mgr_do_tasklet_buf_done, - wm_res->tasklet_info, cam_tasklet_enqueue_cmd); + wm_res->tasklet_info, &tasklet_bh_api); if (wm_res->irq_handle < 0) { CAM_ERR(CAM_ISP, "Subscribe IRQ failed for WM %d", rsrc_data->index); @@ -1132,7 +1132,8 @@ static int cam_vfe_bus_stop_wm(struct cam_isp_resource_node *wm_res) /* Disble WM */ /* Disable all register access, reply on global reset */ - CAM_DBG(CAM_ISP, "irq_enabled %d", rsrc_data->irq_enabled); + CAM_DBG(CAM_ISP, "WM res %d irq_enabled %d", + rsrc_data->index, rsrc_data->irq_enabled); /* Unsubscribe IRQ */ if (rsrc_data->irq_enabled) rc = cam_irq_controller_unsubscribe_irq( @@ -1565,7 +1566,7 @@ static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp) bus_irq_reg_mask, comp_grp, comp_grp->top_half_handler, cam_ife_mgr_do_tasklet_buf_done, - comp_grp->tasklet_info, cam_tasklet_enqueue_cmd); + comp_grp->tasklet_info, &tasklet_bh_api); if (comp_grp->irq_handle < 0) { CAM_ERR(CAM_ISP, "Subscribe IRQ failed for comp_grp %d", rsrc_data->comp_grp_type); @@ -2251,11 +2252,13 @@ static int cam_vfe_bus_ver2_handle_irq(uint32_t evt_id, struct cam_irq_th_payload *th_payload) { struct cam_vfe_bus_ver2_priv *bus_priv; + int rc = 0; bus_priv = th_payload->handler_priv; CAM_DBG(CAM_ISP, "Enter"); - return cam_irq_controller_handle_irq(evt_id, + rc = cam_irq_controller_handle_irq(evt_id, bus_priv->common_data.bus_irq_controller); + return (rc == IRQ_HANDLED) ? 0 : -EINVAL; } static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c index 8bc9bd23a039ec9c129157d5fe0d8bf5c581b9a7..b554fe48de3c29c59c36a7c86f6baf822e852fd3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -39,6 +39,7 @@ struct cam_vfe_mux_camif_data { uint32_t first_line; uint32_t last_pixel; uint32_t last_line; + bool enable_sof_irq_debug; }; static int cam_vfe_camif_validate_pix_pattern(uint32_t pattern) @@ -359,6 +360,23 @@ static int cam_vfe_camif_resource_stop( return rc; } +static int cam_vfe_camif_sof_irq_debug( + struct cam_isp_resource_node *rsrc_node, void *cmd_args) +{ + struct cam_vfe_mux_camif_data *camif_priv; + uint32_t *enable_sof_irq = (uint32_t *)cmd_args; + + camif_priv = + (struct cam_vfe_mux_camif_data *)rsrc_node->res_priv; + + if (*enable_sof_irq == 1) + camif_priv->enable_sof_irq_debug = true; + else + camif_priv->enable_sof_irq_debug = false; + + return 0; +} + static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, uint32_t cmd_type, void *cmd_args, uint32_t arg_size) { @@ -377,6 +395,9 @@ static int cam_vfe_camif_process_cmd(struct cam_isp_resource_node *rsrc_node, case CAM_ISP_HW_CMD_GET_REG_DUMP: rc = cam_vfe_camif_reg_dump(rsrc_node); break; + case CAM_ISP_HW_CMD_SOF_IRQ_DEBUG: + rc = cam_vfe_camif_sof_irq_debug(rsrc_node, cmd_args); + break; default: CAM_ERR(CAM_ISP, "unsupported process command:%d", cmd_type); @@ -419,7 +440,11 @@ static int cam_vfe_camif_handle_irq_bottom_half(void *handler_priv, switch (payload->evt_id) { case CAM_ISP_HW_EVENT_SOF: if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { - CAM_DBG(CAM_ISP, "Received SOF"); + if (camif_priv->enable_sof_irq_debug) + CAM_ERR_RATE_LIMIT(CAM_ISP, "Received SOF"); + else + CAM_DBG(CAM_ISP, "Received SOF"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; } break; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c index be0ca184113c9b64a12d3434b596fecdf2c6d800..47a04388ea8da1af7fa7381c7abcb5778a01047d 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -107,14 +107,11 @@ static int cam_vfe_top_set_hw_clk_rate( if (max_clk_rate == top_priv->hw_clk_rate) return 0; - CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%lld", + CAM_DBG(CAM_ISP, "VFE: Clock name=%s idx=%d clk=%llu", soc_info->clk_name[soc_info->src_clk_idx], soc_info->src_clk_idx, max_clk_rate); - rc = cam_soc_util_set_clk_rate( - soc_info->clk[soc_info->src_clk_idx], - soc_info->clk_name[soc_info->src_clk_idx], - max_clk_rate); + rc = cam_soc_util_set_src_clk_rate(soc_info, max_clk_rate); if (!rc) top_priv->hw_clk_rate = max_clk_rate; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c index 60feeacde477fd415b531f603b75f4f9e0e2ca30..46cc08f7ea5fea95509ff0a8e1971aea38397dbe 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/cam_jpeg_dev.c @@ -138,6 +138,7 @@ static struct platform_driver jpeg_driver = { .name = "cam_jpeg", .owner = THIS_MODULE, .of_match_table = cam_jpeg_dt_match, + .suppress_bind_attrs = true, }, }; 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 97d076a78c04dae995109359300a63a2ec844f51..f0913b2df834e44b87499334756f658ef9739946 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 @@ -729,15 +729,59 @@ static int cam_jpeg_mgr_prepare_hw_update(void *hw_mgr_priv, return rc; } +static void cam_jpeg_mgr_stop_deinit_dev(struct cam_jpeg_hw_mgr *hw_mgr, + struct cam_jpeg_hw_cfg_req *p_cfg_req, uint32_t dev_type) +{ + int rc = 0; + struct cam_jpeg_set_irq_cb irq_cb; + + /* stop reset Unregister CB and deinit */ + irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; + irq_cb.data = NULL; + irq_cb.b_set_cb = false; + if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.process_cmd( + hw_mgr->devices[dev_type][0]->hw_priv, + CAM_JPEG_CMD_SET_IRQ_CB, + &irq_cb, sizeof(irq_cb)); + if (rc) + CAM_ERR(CAM_JPEG, "SET_IRQ_CB fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "process_cmd null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "stop fail %d", rc); + } else { + CAM_ERR(CAM_JPEG, "op stop null %d", dev_type); + } + + if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { + rc = hw_mgr->devices[dev_type][0]->hw_ops.deinit( + hw_mgr->devices[dev_type][0]->hw_priv, + NULL, 0); + if (rc) + CAM_ERR(CAM_JPEG, "Failed to Deinit %d HW %d", + dev_type, rc); + } else { + CAM_ERR(CAM_JPEG, "op deinit null %d", dev_type); + } + + hw_mgr->device_in_use[dev_type][0] = false; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; +} + static int cam_jpeg_mgr_flush(void *hw_mgr_priv, struct cam_jpeg_hw_ctx_data *ctx_data) { - int rc = 0; struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; uint32_t dev_type; struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; struct cam_jpeg_hw_cfg_req *cfg_req = NULL, *req_temp = NULL; - struct cam_jpeg_set_irq_cb irq_cb; CAM_DBG(CAM_JPEG, "E: JPEG flush ctx"); @@ -753,75 +797,40 @@ static int cam_jpeg_mgr_flush(void *hw_mgr_priv, p_cfg_req != NULL) { if ((struct cam_jpeg_hw_ctx_data *) p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) { - /* stop reset Unregister CB and deinit */ - irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_cb; - irq_cb.data = NULL; - irq_cb.b_set_cb = false; - if (hw_mgr->devices[dev_type][0]->hw_ops.process_cmd) { - rc = hw_mgr->devices[dev_type][0]-> - hw_ops.process_cmd( - hw_mgr->devices[dev_type][0]->hw_priv, - CAM_JPEG_CMD_SET_IRQ_CB, - &irq_cb, sizeof(irq_cb)); - if (rc) - CAM_ERR(CAM_JPEG, - "CMD_SET_IRQ_CB failed %d", rc); - - } else { - CAM_ERR(CAM_JPEG, "process_cmd null "); - } - - if (hw_mgr->devices[dev_type][0]->hw_ops.stop) { - rc = hw_mgr->devices[dev_type][0]->hw_ops.stop( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_JPEG, "stop fail %d", rc); - } else { - CAM_ERR(CAM_JPEG, "op stop null "); - } - - if (hw_mgr->devices[dev_type][0]->hw_ops.deinit) { - rc = hw_mgr->devices[dev_type][0] - ->hw_ops.deinit( - hw_mgr->devices[dev_type][0]->hw_priv, - NULL, 0); - if (rc) - CAM_ERR(CAM_JPEG, - "Failed to Deinit %d HW", - dev_type); - } else { - CAM_ERR(CAM_JPEG, "op deinit null"); - } + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); } - - hw_mgr->device_in_use[dev_type][0] = false; - p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; - hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; } list_for_each_entry_safe(cfg_req, req_temp, &hw_mgr->hw_config_req_list, list) { - if ((cfg_req) && ((struct cam_jpeg_hw_ctx_data *) - cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data)) + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) continue; list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); } - CAM_DBG(CAM_JPEG, "X: JPEG flush ctx with rc: %d", rc); + CAM_DBG(CAM_JPEG, "X: JPEG flush ctx"); - return rc; + return 0; } - static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, struct cam_jpeg_hw_ctx_data *ctx_data, struct cam_hw_flush_args *flush_args) { struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; - struct cam_jpeg_hw_cfg_req *cfg_req, *req_temp; - int64_t request_id; + struct cam_jpeg_hw_cfg_req *cfg_req = NULL; + struct cam_jpeg_hw_cfg_req *req_temp = NULL; + int64_t request_id = 0; + uint32_t dev_type; + struct cam_jpeg_hw_cfg_req *p_cfg_req = NULL; + bool b_req_found = false; CAM_DBG(CAM_JPEG, "E: JPEG flush req"); @@ -833,21 +842,54 @@ static int cam_jpeg_mgr_flush_req(void *hw_mgr_priv, if (flush_args->num_req_pending) return 0; - request_id = *(int64_t *)flush_args->flush_req_active[0]; + request_id = (int64_t)flush_args->flush_req_active[0]; + + if (!flush_args->num_req_active) + return 0; + + if (request_id <= 0) { + CAM_ERR(CAM_JPEG, "Invalid red id %lld", request_id); + return -EINVAL; + } + + dev_type = ctx_data->jpeg_dev_acquire_info.dev_type; + + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + if (hw_mgr->device_in_use[dev_type][0] == true && + p_cfg_req != NULL) { + if (((struct cam_jpeg_hw_ctx_data *) + p_cfg_req->hw_cfg_args.ctxt_to_hw_map == ctx_data) && + (p_cfg_req->req_id == request_id)) { + cam_jpeg_mgr_stop_deinit_dev(hw_mgr, p_cfg_req, + dev_type); + list_del_init(&p_cfg_req->list); + list_add_tail(&p_cfg_req->list, + &hw_mgr->free_req_list); + b_req_found = true; + } + } + list_for_each_entry_safe(cfg_req, req_temp, &hw_mgr->hw_config_req_list, list) { - if ((cfg_req) && (cfg_req->hw_cfg_args.ctxt_to_hw_map - != ctx_data)) + if ((struct cam_jpeg_hw_ctx_data *) + cfg_req->hw_cfg_args.ctxt_to_hw_map != ctx_data) continue; if (cfg_req->req_id != request_id) continue; list_del_init(&cfg_req->list); + list_add_tail(&cfg_req->list, &hw_mgr->free_req_list); + b_req_found = true; + break; } - CAM_DBG(CAM_JPEG, "X: JPEG flush req"); + if (!b_req_found) { + CAM_ERR(CAM_JPEG, "req not found %lld", request_id); + return -EINVAL; + } + CAM_DBG(CAM_JPEG, "X: JPEG flush req"); return 0; } @@ -887,7 +929,6 @@ static int cam_jpeg_mgr_hw_flush(void *hw_mgr_priv, void *flush_hw_args) break; case CAM_FLUSH_TYPE_REQ: rc = cam_jpeg_mgr_flush_req(hw_mgr_priv, ctx_data, flush_args); - CAM_ERR(CAM_JPEG, "Flush per request is not supported"); break; default: CAM_ERR(CAM_JPEG, "Invalid flush type: %d", @@ -956,7 +997,6 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) if (hw_mgr->cdm_info[dev_type][0].ref_cnt == 0) { mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_JPEG, "Error Unbalanced deinit"); - kfree(ctx_data->cdm_cmd); return -EFAULT; } @@ -978,10 +1018,13 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) mutex_unlock(&hw_mgr->hw_mgr_mutex); CAM_ERR(CAM_JPEG, "JPEG release ctx failed"); kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; + return -EINVAL; } kfree(ctx_data->cdm_cmd); + ctx_data->cdm_cmd = NULL; CAM_DBG(CAM_JPEG, "handle %llu", ctx_data); return rc; @@ -989,7 +1032,7 @@ static int cam_jpeg_mgr_release_hw(void *hw_mgr_priv, void *release_hw_args) static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { - int rc; + int rc = 0; int32_t ctx_id = 0; struct cam_jpeg_hw_mgr *hw_mgr = hw_mgr_priv; struct cam_jpeg_hw_ctx_data *ctx_data = NULL; @@ -1171,7 +1214,7 @@ static int cam_jpeg_setup_workqs(void) "jpeg_command_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_frame, - CRM_WORKQ_USAGE_NON_IRQ); + CRM_WORKQ_USAGE_NON_IRQ, 0); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); goto work_process_frame_failed; @@ -1181,7 +1224,7 @@ static int cam_jpeg_setup_workqs(void) "jpeg_message_queue", CAM_JPEG_WORKQ_NUM_TASK, &g_jpeg_hw_mgr.work_process_irq_cb, - CRM_WORKQ_USAGE_IRQ); + CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_JPEG, "unable to create a worker %d", rc); goto work_process_irq_cb_failed; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c index ef10406b823a9232e68184a1ae8f30281ab7b63d..fd4fdab19fa73552892e249c89e52c0a37534583 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -220,6 +220,7 @@ static struct platform_driver cam_jpeg_dma_driver = { .name = "cam-jpeg-dma", .owner = THIS_MODULE, .of_match_table = cam_jpeg_dma_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index 9fa691b2bff646d040771ac1bca671fa39015bb5..7fcc1ada1a36f897d857047cf1cc533ad7d8b988 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -349,7 +349,7 @@ int cam_jpeg_enc_stop_hw(void *data, hw_info = core_info->jpeg_enc_hw_info; mem_base = soc_info->reg_map[0].mem_base; - mutex_unlock(&core_info->core_mutex); + mutex_lock(&core_info->core_mutex); spin_lock(&jpeg_enc_dev->hw_lock); if (core_info->core_state == CAM_JPEG_ENC_CORE_ABORTING) { CAM_ERR(CAM_JPEG, "alrady stopping"); diff --git a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c index d1eb526428e29d7841dcf184702376653422d90d..d4daa6dde308957bfb2561ae340211a9f942bd3c 100644 --- a/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c +++ b/drivers/media/platform/msm/camera/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -218,6 +218,7 @@ static struct platform_driver cam_jpeg_enc_driver = { .name = "cam-jpeg-enc", .owner = THIS_MODULE, .of_match_table = cam_jpeg_enc_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c index 5be16ef6a174403cd94b5427317336f2248636a5..a4ee1040e4c86388a73cef7050f2c1660778eed4 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/cam_lrme_dev.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 @@ -214,6 +214,7 @@ static struct platform_driver cam_lrme_driver = { .name = "cam_lrme", .owner = THIS_MODULE, .of_match_table = cam_lrme_dt_match, + .suppress_bind_attrs = true, }, }; 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 a60661e04cd38fb3332d165ca52c32e89e9c4645..0f34c9f15b56acf213b6987c56515e88c9512c83 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 @@ -989,7 +989,8 @@ int cam_lrme_mgr_register_device( CAM_DBG(CAM_LRME, "Create submit workq for %s", buf); rc = cam_req_mgr_workq_create(buf, CAM_LRME_WORKQ_NUM_TASK, - &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ); + &hw_device->work, CRM_WORKQ_USAGE_NON_IRQ, + 0); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a worker, rc=%d", rc); diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c index 6f98354decbc12a3bbeb5df2e604edfb0c523f63..595bb8182c8fbf58f88b188f2d69f14a96a2c0b9 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -1118,7 +1118,7 @@ irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) if (!data) { CAM_ERR(CAM_LRME, "Invalid data in IRQ callback"); - return -EINVAL; + return IRQ_NONE; } lrme_hw = (struct cam_hw_info *)data; @@ -1179,7 +1179,7 @@ irqreturn_t cam_lrme_hw_irq(int irq_num, void *data) task = cam_req_mgr_workq_get_task(lrme_core->work); if (!task) { CAM_ERR(CAM_LRME, "no empty task available"); - return -ENOMEM; + return IRQ_NONE; } work_data = (struct cam_lrme_hw_work_data *)task->payload; work_data->top_irq_status = top_irq_status; diff --git a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index da42c84f3835a1c9fb501f5a70c88809216345f8..ec4297822fb7c857f0e2cb365648f8abf88eab0e 100644 --- a/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/media/platform/msm/camera/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.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 @@ -28,8 +28,6 @@ #include "cam_mem_mgr_api.h" #include "cam_smmu_api.h" -#define CAM_LRME_HW_WORKQ_NUM_TASK 30 - static int cam_lrme_hw_dev_util_cdm_acquire(struct cam_lrme_core *lrme_core, struct cam_hw_info *lrme_hw) { @@ -122,7 +120,7 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) rc = cam_req_mgr_workq_create("cam_lrme_hw_worker", CAM_LRME_HW_WORKQ_NUM_TASK, - &lrme_core->work, CRM_WORKQ_USAGE_IRQ); + &lrme_core->work, CRM_WORKQ_USAGE_IRQ, 0); if (rc) { CAM_ERR(CAM_LRME, "Unable to create a workq, rc=%d", rc); goto free_memory; @@ -302,6 +300,7 @@ static struct platform_driver cam_lrme_hw_driver = { .name = "cam_lrme_hw", .owner = THIS_MODULE, .of_match_table = cam_lrme_hw_dt_match, + .suppress_bind_attrs = true, }, }; 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 93e4249cc4273d3e93009d87ff1432d091d3dcaf..d192018bf2f2edac9fb3ca352f1cc754304aa009 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 @@ -30,12 +30,12 @@ static int cam_mem_util_map_cpu_va(struct ion_handle *hdl, { *vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl); if (IS_ERR_OR_NULL((void *)*vaddr)) { - CAM_ERR(CAM_CRM, "kernel map fail"); + CAM_ERR(CAM_MEM, "kernel map fail"); return -ENOSPC; } if (ion_handle_get_size(tbl.client, hdl, len)) { - CAM_ERR(CAM_CRM, "kernel get len failed"); + CAM_ERR(CAM_MEM, "kernel get len failed"); ion_unmap_kernel(tbl.client, hdl); return -ENOSPC; } @@ -65,7 +65,7 @@ static int cam_mem_util_client_create(void) tbl.client = msm_ion_client_create("camera_global_pool"); if (IS_ERR_OR_NULL(tbl.client)) { - CAM_ERR(CAM_CRM, "fail to create client"); + CAM_ERR(CAM_MEM, "fail to create client"); rc = -EINVAL; } @@ -88,7 +88,7 @@ int cam_mem_mgr_init(void) rc = cam_mem_util_client_create(); if (rc < 0) { - CAM_ERR(CAM_CRM, "fail to create ion client"); + CAM_ERR(CAM_MEM, "fail to create ion client"); goto client_fail; } @@ -175,7 +175,7 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, iova_ptr, len_ptr); if (rc < 0) - CAM_ERR(CAM_CRM, "fail to get buf hdl :%d", buf_handle); + CAM_ERR(CAM_MEM, "fail to get buf hdl :%d", buf_handle); handle_mismatch: mutex_unlock(&tbl.bufq[idx].q_lock); @@ -209,7 +209,7 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, size_t *len) ion_hdl = tbl.bufq[idx].i_hdl; if (!ion_hdl) { - CAM_ERR(CAM_CRM, "Invalid ION handle"); + CAM_ERR(CAM_MEM, "Invalid ION handle"); rc = -EINVAL; goto exit_func; } @@ -264,7 +264,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl, &ion_flag); if (rc) { - CAM_ERR(CAM_CRM, "cache get flags failed %d", rc); + CAM_ERR(CAM_MEM, "cache get flags failed %d", rc); goto fail; } @@ -280,7 +280,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) ion_cache_ops = ION_IOC_CLEAN_INV_CACHES; break; default: - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "invalid cache ops :%d", cmd->mem_cache_ops); rc = -EINVAL; goto fail; @@ -292,7 +292,7 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) tbl.bufq[idx].len, ion_cache_ops); if (rc) - CAM_ERR(CAM_CRM, "cache operation failed %d", rc); + CAM_ERR(CAM_MEM, "cache operation failed %d", rc); } fail: mutex_unlock(&tbl.bufq[idx].q_lock); @@ -310,7 +310,7 @@ static int cam_mem_util_get_dma_buf(size_t len, int rc = 0; if (!hdl || !buf) { - CAM_ERR(CAM_CRM, "Invalid params"); + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } @@ -320,7 +320,7 @@ static int cam_mem_util_get_dma_buf(size_t len, *buf = ion_share_dma_buf(tbl.client, *hdl); if (IS_ERR_OR_NULL(*buf)) { - CAM_ERR(CAM_CRM, "get dma buf fail"); + CAM_ERR(CAM_MEM, "get dma buf fail"); rc = -EINVAL; goto get_buf_fail; } @@ -343,7 +343,7 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, int rc = 0; if (!hdl || !fd) { - CAM_ERR(CAM_CRM, "Invalid params"); + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } @@ -353,7 +353,7 @@ static int cam_mem_util_get_dma_buf_fd(size_t len, *fd = ion_share_dma_buf_fd(tbl.client, *hdl); if (*fd < 0) { - CAM_ERR(CAM_CRM, "get fd fail"); + CAM_ERR(CAM_MEM, "get fd fail"); rc = -EINVAL; goto get_fd_fail; } @@ -400,19 +400,19 @@ 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_CRM, "Invalid flags"); + CAM_ERR(CAM_MEM, "Invalid flags"); return -EINVAL; } if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { - CAM_ERR(CAM_CRM, "Num of mmu hdl exceeded maximum(%d)", + CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", CAM_MEM_MMU_MAX_HANDLE); return -EINVAL; } if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { - CAM_ERR(CAM_CRM, "Kernel mapping in secure mode not allowed"); + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); return -EINVAL; } @@ -422,24 +422,24 @@ static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd) { if (!cmd->flags) { - CAM_ERR(CAM_CRM, "Invalid flags"); + CAM_ERR(CAM_MEM, "Invalid flags"); return -EINVAL; } if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { - CAM_ERR(CAM_CRM, "Num of mmu hdl exceeded maximum(%d)", + CAM_ERR(CAM_MEM, "Num of mmu hdl exceeded maximum(%d)", CAM_MEM_MMU_MAX_HANDLE); return -EINVAL; } if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE && cmd->flags & CAM_MEM_FLAG_KMD_ACCESS) { - CAM_ERR(CAM_CRM, "Kernel mapping in secure mode not allowed"); + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); return -EINVAL; } if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Shared memory buffers are not allowed to be mapped"); return -EINVAL; } @@ -460,7 +460,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, int dir = cam_mem_util_get_dma_dir(flags); if (dir < 0) { - CAM_ERR(CAM_CRM, "fail to map DMA direction"); + CAM_ERR(CAM_MEM, "fail to map DMA direction"); return dir; } @@ -474,7 +474,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, len); if (rc < 0) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Failed to securely map to smmu"); goto multi_map_fail; } @@ -489,7 +489,7 @@ static int cam_mem_util_map_hw_va(uint32_t flags, region); if (rc < 0) { - CAM_ERR(CAM_CRM, "Failed to map to smmu"); + CAM_ERR(CAM_MEM, "Failed to map to smmu"); goto multi_map_fail; } } @@ -519,14 +519,14 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) size_t len; if (!cmd) { - CAM_ERR(CAM_CRM, " Invalid argument"); + CAM_ERR(CAM_MEM, " Invalid argument"); return -EINVAL; } len = cmd->len; rc = cam_mem_util_check_flags(cmd); if (rc) { - CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); return rc; } @@ -534,12 +534,13 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) &ion_hdl, &ion_fd); if (rc) { - CAM_ERR(CAM_CRM, "Ion allocation failed"); + CAM_ERR(CAM_MEM, "Ion allocation failed"); return rc; } idx = cam_mem_get_slot(); if (idx < 0) { + CAM_ERR(CAM_MEM, "Failed to get slot"); rc = -ENOMEM; goto slot_fail; } @@ -594,7 +595,7 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) cmd->out.fd = tbl.bufq[idx].fd; cmd->out.vaddr = 0; - CAM_DBG(CAM_CRM, "buf handle: %x, fd: %d, len: %zu", + CAM_DBG(CAM_MEM, "buf handle: %x, fd: %d, len: %zu", cmd->out.buf_handle, cmd->out.fd, tbl.bufq[idx].len); @@ -616,7 +617,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) size_t len = 0; if (!cmd || (cmd->fd < 0)) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } @@ -625,13 +626,13 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) rc = cam_mem_util_check_map_flags(cmd); if (rc) { - CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); return rc; } ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd); if (IS_ERR_OR_NULL((void *)(ion_hdl))) { - CAM_ERR(CAM_CRM, "Failed to import ion fd"); + CAM_ERR(CAM_MEM, "Failed to import ion fd"); return -EINVAL; } @@ -702,7 +703,7 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, int rc = -EINVAL; if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index"); + CAM_ERR(CAM_MEM, "Incorrect index"); return rc; } @@ -726,7 +727,7 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, rc = cam_smmu_unmap_kernel_iova(mmu_hdls[i], tbl.bufq[idx].dma_buf, region); } else { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "invalid caller for unmapping : %d", client); rc = -EINVAL; @@ -739,7 +740,7 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, return rc; unmap_end: - CAM_ERR(CAM_CRM, "unmapping failed"); + CAM_ERR(CAM_MEM, "unmapping failed"); return rc; } @@ -762,11 +763,11 @@ static int cam_mem_mgr_cleanup_table(void) mutex_lock(&tbl.m_lock); for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { if (!tbl.bufq[i].active) { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Buffer inactive at idx=%d, continuing", i); continue; } else { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Active buffer at idx=%d, possible leak needs unmapping", i); cam_mem_mgr_unmap_active_buf(i); @@ -817,16 +818,16 @@ static int cam_mem_util_unmap(int32_t idx, enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index"); + CAM_ERR(CAM_MEM, "Incorrect index"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); + CAM_DBG(CAM_MEM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); mutex_lock(&tbl.m_lock); if ((!tbl.bufq[idx].active) && (tbl.bufq[idx].vaddr) == 0) { - CAM_WARN(CAM_CRM, "Buffer at idx=%d is already unmapped,", + CAM_WARN(CAM_MEM, "Buffer at idx=%d is already unmapped,", idx); mutex_unlock(&tbl.m_lock); return 0; @@ -858,7 +859,7 @@ static int cam_mem_util_unmap(int32_t idx, memset(tbl.bufq[idx].hdls, 0, sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE); - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Ion handle at idx = %d freeing = %pK, fd = %d, imported %d dma_buf %pK", idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd, tbl.bufq[idx].is_imported, @@ -889,28 +890,28 @@ int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd) int rc; if (!cmd) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } idx = CAM_MEM_MGR_GET_HDL_IDX(cmd->buf_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); return -EINVAL; } if (!tbl.bufq[idx].active) { - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != cmd->buf_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Releasing hdl = %u", cmd->buf_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %u", cmd->buf_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_USER); return rc; @@ -936,14 +937,14 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; if (!inp || !out) { - CAM_ERR(CAM_CRM, "Invalid params"); + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } if (!(inp->flags & CAM_MEM_FLAG_HW_READ_WRITE || inp->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS || inp->flags & CAM_MEM_FLAG_CACHE)) { - CAM_ERR(CAM_CRM, "Invalid flags for request mem"); + CAM_ERR(CAM_MEM, "Invalid flags for request mem"); return -EINVAL; } @@ -963,20 +964,20 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, &buf); if (rc) { - CAM_ERR(CAM_CRM, "ION alloc failed for shared buffer"); + CAM_ERR(CAM_MEM, "ION alloc failed for shared buffer"); goto ion_fail; } else { - CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + CAM_DBG(CAM_MEM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); } rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len); if (rc) { - CAM_ERR(CAM_CRM, "Failed to get kernel vaddr"); + CAM_ERR(CAM_MEM, "Failed to get kernel vaddr"); goto map_fail; } if (!inp->smmu_hdl) { - CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); rc = -EINVAL; goto smmu_fail; } @@ -997,7 +998,7 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, region); if (rc < 0) { - CAM_ERR(CAM_CRM, "SMMU mapping failed"); + CAM_ERR(CAM_MEM, "SMMU mapping failed"); goto smmu_fail; } @@ -1054,32 +1055,32 @@ int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp) int rc; if (!inp) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); return -EINVAL; } if (!tbl.bufq[idx].active) { if (tbl.bufq[idx].vaddr == 0) { - CAM_ERR(CAM_CRM, "buffer is released already"); + CAM_ERR(CAM_MEM, "buffer is released already"); return 0; } - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != inp->mem_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); return rc; @@ -1103,17 +1104,17 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, int32_t num_hdl = 0; if (!inp || !out) { - CAM_ERR(CAM_CRM, "Invalid param(s)"); + CAM_ERR(CAM_MEM, "Invalid param(s)"); return -EINVAL; } if (!inp->smmu_hdl) { - CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); return -EINVAL; } if (region != CAM_SMMU_REGION_SECHEAP) { - CAM_ERR(CAM_CRM, "Only secondary heap supported"); + CAM_ERR(CAM_MEM, "Only secondary heap supported"); return -EINVAL; } @@ -1127,10 +1128,10 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, &buf); if (rc) { - CAM_ERR(CAM_CRM, "ION alloc failed for sec heap buffer"); + CAM_ERR(CAM_MEM, "ION alloc failed for sec heap buffer"); goto ion_fail; } else { - CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + CAM_DBG(CAM_MEM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); } rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl, @@ -1139,7 +1140,7 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, &request_len); if (rc) { - CAM_ERR(CAM_CRM, "Reserving secondary heap failed"); + CAM_ERR(CAM_MEM, "Reserving secondary heap failed"); goto smmu_fail; } @@ -1195,38 +1196,38 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) int32_t smmu_hdl; if (!inp) { - CAM_ERR(CAM_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } if (inp->region != CAM_SMMU_REGION_SECHEAP) { - CAM_ERR(CAM_CRM, "Only secondary heap supported"); + CAM_ERR(CAM_MEM, "Only secondary heap supported"); return -EINVAL; } idx = CAM_MEM_MGR_GET_HDL_IDX(inp->mem_handle); if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index extracted from mem handle"); return -EINVAL; } if (!tbl.bufq[idx].active) { if (tbl.bufq[idx].vaddr == 0) { - CAM_ERR(CAM_CRM, "buffer is released already"); + CAM_ERR(CAM_MEM, "buffer is released already"); return 0; } - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != inp->mem_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } if (tbl.bufq[idx].num_hdl != 1) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Sec heap region should have only one smmu hdl"); return -ENODEV; } @@ -1234,22 +1235,22 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) memcpy(&smmu_hdl, tbl.bufq[idx].hdls, sizeof(int32_t)); if (inp->smmu_hdl != smmu_hdl) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Passed SMMU handle doesn't match with internal hdl"); return -ENODEV; } rc = cam_smmu_release_sec_heap(inp->smmu_hdl); if (rc) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Sec heap region release failed"); return -ENODEV; } - CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); if (rc) - CAM_ERR(CAM_CRM, "unmapping secondary heap failed"); + CAM_ERR(CAM_MEM, "unmapping secondary heap failed"); return rc; } diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 4602d6c135a5f3da484980687a2937887e3db2be..346cd5678379711d342af086b01e3b7a775381ea 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 @@ -482,7 +482,8 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, trace_cam_req_mgr_apply_request(link, &apply_req, dev); apply_req.trigger_point = trigger; - CAM_DBG(CAM_CRM, "SEND: link_hdl: %x pd %d req_id %lld", + CAM_DBG(CAM_REQ, + "SEND: link_hdl: %x pd %d req_id %lld", link->link_hdl, pd, apply_req.request_id); if (dev->ops && dev->ops->apply_req) { rc = dev->ops->apply_req(&apply_req); @@ -566,7 +567,7 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, if (!rc && traverse_data.result == link->pd_mask) { CAM_DBG(CAM_CRM, - "APPLY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld", + "READY: link_hdl= %x idx= %d, req_id= %lld :%lld :%lld", link->link_hdl, idx, apply_data[2].req_id, apply_data[1].req_id, @@ -742,13 +743,13 @@ static int __cam_req_mgr_process_sync_req( sync_link = link->sync_link; req_id = slot->req_id; - CAM_DBG(CAM_CRM, + 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); if (sync_link->sync_link_sof_skip) { - CAM_DBG(CAM_CRM, + 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; @@ -761,7 +762,7 @@ static int __cam_req_mgr_process_sync_req( __cam_req_mgr_sof_cnt_initialize(link); } else if ((link->frame_skip_flag) && (sync_link->sync_self_ref != -1)) { - CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values ", + 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); @@ -771,8 +772,8 @@ static int __cam_req_mgr_process_sync_req( rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); if (rc) { - CAM_DBG(CAM_CRM, - "Req: %lld [My link]not available link: %x, rc=%d", + CAM_DBG(CAM_REQ, + "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; @@ -794,8 +795,8 @@ static int __cam_req_mgr_process_sync_req( } if ((sync_slot_idx != -1) && - ((sync_link->req.in_q->slot[sync_slot_idx].status == - CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) { + ((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, @@ -804,7 +805,7 @@ static int __cam_req_mgr_process_sync_req( goto failure; } - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_REQ, "Req: %lld ready to apply on link: %x [validation successful]", req_id, link->link_hdl); /* @@ -819,7 +820,7 @@ static int __cam_req_mgr_process_sync_req( CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); } } else { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_REQ, "Req: %lld [Other link] not ready to apply on link: %x", req_id, sync_link->link_hdl); rc = -EPERM; @@ -862,7 +863,7 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link, * - if in applied_state, somthign wrong. * - if in no_req state, no new req */ - CAM_DBG(CAM_CRM, "SOF Req[%lld] idx %d req_status %d link_hdl %x", + CAM_DBG(CAM_REQ, "SOF Req[%lld] idx %d req_status %d link_hdl %x", in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, in_q->slot[in_q->rd_idx].status, link->link_hdl); @@ -1114,6 +1115,32 @@ static int __cam_req_mgr_reset_in_q(struct cam_req_mgr_req_data *req) return 0; } +/** + * __cam_req_mgr_notify_sof_freeze() + * + * @brief : Notify devices on link on detecting a SOF freeze + * @link : link on which the sof freeze was detected + * + */ +static void __cam_req_mgr_notify_sof_freeze( + struct cam_req_mgr_core_link *link) +{ + int i = 0; + struct cam_req_mgr_link_evt_data evt_data; + struct cam_req_mgr_connected_device *dev = NULL; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_SOF_FREEZE; + evt_data.dev_hdl = dev->dev_hdl; + evt_data.link_hdl = link->link_hdl; + evt_data.req_id = 0; + evt_data.u.error = CRM_KMD_ERR_FATAL; + if (dev->ops && dev->ops->process_evt) + dev->ops->process_evt(&evt_data); + } +} + /** * __cam_req_mgr_sof_freeze() * @@ -1138,6 +1165,7 @@ static void __cam_req_mgr_sof_freeze(unsigned long data) CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", session->session_hdl, link->link_hdl); + __cam_req_mgr_notify_sof_freeze(link); memset(&msg, 0, sizeof(msg)); msg.session_hdl = session->session_hdl; @@ -1453,7 +1481,7 @@ int cam_req_mgr_process_flush_req(void *priv, void *data) link = (struct cam_req_mgr_core_link *)priv; task_data = (struct crm_task_payload *)data; flush_info = (struct cam_req_mgr_flush_info *)&task_data->u; - CAM_DBG(CAM_CRM, "link_hdl %x req_id %lld type %d", + CAM_DBG(CAM_REQ, "link_hdl %x req_id %lld type %d", flush_info->link_hdl, flush_info->req_id, flush_info->flush_type); @@ -1652,7 +1680,7 @@ 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_CRM, "idx %d req_id %lld pd %d SLOT READY", + CAM_DBG(CAM_REQ, "idx %d req_id %lld pd %d SLOT READY", idx, add_req->req_id, tbl->pd); slot->state = CRM_REQ_STATE_READY; } @@ -1780,7 +1808,7 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) task_data = (struct crm_task_payload *)data; trigger_data = (struct cam_req_mgr_trigger_notify *)&task_data->u; - CAM_DBG(CAM_CRM, "link_hdl %x frame_id %lld, trigger %x\n", + CAM_DBG(CAM_REQ, "link_hdl %x frame_id %lld, trigger %x\n", trigger_data->link_hdl, trigger_data->frame_id, trigger_data->trigger); @@ -1823,6 +1851,30 @@ static int cam_req_mgr_process_trigger(void *priv, void *data) return rc; } +/** + * __cam_req_mgr_dev_handle_to_name() + * + * @brief : Finds device name based on the device handle + * @dev_hdl : Device handle whose name is to be found + * @link : Link on which the device is connected + * @return : String containing the device name + * + */ +static const char *__cam_req_mgr_dev_handle_to_name( + int32_t dev_hdl, struct cam_req_mgr_core_link *link) +{ + struct cam_req_mgr_connected_device *dev = NULL; + int i = 0; + + for (i = 0; i < link->num_devs; i++) { + dev = &link->l_dev[i]; + + if (dev_hdl == dev->dev_hdl) + return dev->dev_info.name; + } + + return "Invalid dev_hdl"; +} /* Linked devices' Callback section */ @@ -1848,8 +1900,6 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) return -EINVAL; } - CAM_DBG(CAM_CRM, "E: dev %x dev req %lld", - add_req->dev_hdl, add_req->req_id); link = (struct cam_req_mgr_core_link *) cam_get_device_priv(add_req->link_hdl); @@ -1858,9 +1908,13 @@ static int cam_req_mgr_cb_add_req(struct cam_req_mgr_add_request *add_req) return -EINVAL; } + CAM_DBG(CAM_REQ, "dev name %s dev_hdl %d dev req %lld", + __cam_req_mgr_dev_handle_to_name(add_req->dev_hdl, link), + add_req->dev_hdl, add_req->req_id); + mutex_lock(&link->lock); spin_lock_bh(&link->link_state_spin_lock); - if (link->state != CAM_CRM_LINK_STATE_READY) { + if (link->state < CAM_CRM_LINK_STATE_READY) { CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); rc = -EPERM; spin_unlock_bh(&link->link_state_spin_lock); @@ -1997,7 +2051,7 @@ static int cam_req_mgr_cb_notify_trigger( } spin_lock_bh(&link->link_state_spin_lock); - if (link->state != CAM_CRM_LINK_STATE_READY) { + if (link->state < CAM_CRM_LINK_STATE_READY) { CAM_WARN(CAM_CRM, "invalid link state:%d", link->state); spin_unlock_bh(&link->link_state_spin_lock); rc = -EPERM; @@ -2324,6 +2378,7 @@ int cam_req_mgr_destroy_session( int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) { int rc = 0; + int wq_flag = 0; char buf[128]; struct cam_create_dev_hdl root_dev; struct cam_req_mgr_core_session *cam_session; @@ -2394,8 +2449,9 @@ int cam_req_mgr_link(struct cam_req_mgr_link_info *link_info) /* Create worker for current link */ snprintf(buf, sizeof(buf), "%x-%x", link_info->session_hdl, link->link_hdl); + wq_flag = CAM_WORKQ_FLAG_HIGH_PRIORITY | CAM_WORKQ_FLAG_SERIAL; rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, - &link->workq, CRM_WORKQ_USAGE_NON_IRQ); + &link->workq, CRM_WORKQ_USAGE_NON_IRQ, wq_flag); if (rc < 0) { CAM_ERR(CAM_CRM, "FATAL: unable to create worker"); __cam_req_mgr_destroy_link_info(link); @@ -2497,7 +2553,7 @@ int cam_req_mgr_schedule_request( goto end; } - CAM_DBG(CAM_CRM, "link %x req %lld, sync_mode %d", + CAM_DBG(CAM_CRM, "link 0x%x req %lld, sync_mode %d", sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); task_data.type = CRM_WORKQ_TASK_SCHED_REQ; @@ -2514,8 +2570,8 @@ int cam_req_mgr_schedule_request( rc = cam_req_mgr_process_sched_req(link, &task_data); - CAM_DBG(CAM_CRM, "DONE dev %x req %lld sync_mode %d", - sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); + CAM_DBG(CAM_REQ, "Open req %lld on link 0x%x with sync_mode %d", + sched_req->req_id, sched_req->link_hdl, sched_req->sync_mode); end: mutex_unlock(&g_crm_core_dev->crm_lock); return rc; @@ -2589,6 +2645,9 @@ int cam_req_mgr_sync_config( link2->sync_link = link1; cam_session->sync_mode = sync_info->sync_mode; + CAM_DBG(CAM_REQ, + "Sync config on link1 0x%x & link2 0x%x with sync_mode %d", + link1->link_hdl, link2->link_hdl, cam_session->sync_mode); done: mutex_unlock(&cam_session->lock); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c index 9a93feba1ac5afbf68a4c981d6b8e9ec00abd21f..543e3329fc523ed68a9a5ec691f1b0ce2de64b30 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_dev.c @@ -591,6 +591,7 @@ static int cam_req_mgr_remove(struct platform_device *pdev) cam_v4l2_device_cleanup(); mutex_destroy(&g_dev.dev_lock); g_dev.state = false; + g_dev.subdev_nodes_created = false; return 0; } @@ -680,6 +681,7 @@ static struct platform_driver cam_req_mgr_driver = { .name = "cam_req_mgr", .owner = THIS_MODULE, .of_match_table = cam_req_mgr_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h index 1ca6cc598ec892f5260913a5b16118795a0d2dd3..99292125bc95f814b067d47a56dc5a5c3b6a290e 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_interface.h @@ -177,13 +177,18 @@ enum cam_req_mgr_device_id { /** * enum cam_req_mgr_link_evt_type - * @CAM_REQ_MGR_LINK_EVT_ERR: - * @CAM_REQ_MGR_LINK_EVT_MAX: + * @CAM_REQ_MGR_LINK_EVT_ERR : error on the link from any of the + * connected devices + * @CAM_REQ_MGR_LINK_EVT_PAUSE : to pause the link + * @CAM_REQ_MGR_LINK_EVT_RESUME : resumes the link which was paused + * @CAM_REQ_MGR_LINK_EVT_SOF_FREEZE : request manager has detected an sof freeze + * @CAM_REQ_MGR_LINK_EVT_MAX : invalid event type */ enum cam_req_mgr_link_evt_type { CAM_REQ_MGR_LINK_EVT_ERR, CAM_REQ_MGR_LINK_EVT_PAUSE, CAM_REQ_MGR_LINK_EVT_RESUME, + CAM_REQ_MGR_LINK_EVT_SOF_FREEZE, CAM_REQ_MGR_LINK_EVT_MAX, }; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c index 066efd6fa3e721cb005c819a28bddc3fce13eb91..3798ef8e6d5fd2678c212da2496612e47f09f837 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.c @@ -178,9 +178,10 @@ int cam_req_mgr_workq_enqueue_task(struct crm_workq_task *task, } int cam_req_mgr_workq_create(char *name, int32_t num_tasks, - struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq) + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags) { - int32_t i; + int32_t i, wq_flags = 0, max_active_tasks = 0; struct crm_workq_task *task; struct cam_req_mgr_core_workq *crm_workq = NULL; char buf[128] = "crm_workq-"; @@ -192,10 +193,17 @@ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, if (crm_workq == NULL) return -ENOMEM; + wq_flags |= WQ_UNBOUND; + if (flags & CAM_WORKQ_FLAG_HIGH_PRIORITY) + wq_flags |= WQ_HIGHPRI; + + if (flags & CAM_WORKQ_FLAG_SERIAL) + max_active_tasks = 1; + strlcat(buf, name, sizeof(buf)); CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name); crm_workq->job = alloc_workqueue(buf, - WQ_HIGHPRI | WQ_UNBOUND, 0, NULL); + wq_flags, max_active_tasks, NULL); if (!crm_workq->job) { kfree(crm_workq); return -ENOMEM; diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h index eb3b804f97a9540ad5081b5ff31ca26cd817b662..af76ae467346a9f8efa487ee7233c6be75c49bea 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_workq.h @@ -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 @@ -23,6 +23,15 @@ #include "cam_req_mgr_core.h" +/* Flag to create a high priority workq */ +#define CAM_WORKQ_FLAG_HIGH_PRIORITY (1 << 0) + +/* This flag ensures only one task from a given + * workq will execute at any given point on any + * given CPU. + */ +#define CAM_WORKQ_FLAG_SERIAL (1 << 1) + /* Task priorities, lower the number higher the priority*/ enum crm_task_priority { CRM_TASK_PRIORITY_0, @@ -101,11 +110,14 @@ struct cam_req_mgr_core_workq { * @num_task : Num_tasks to be allocated for workq * @workq : Double pointer worker * @in_irq : Set to one if workq might be used in irq context + * @flags : Bitwise OR of Flags for workq behavior. + * e.g. CAM_REQ_MGR_WORKQ_HIGH_PRIORITY | CAM_REQ_MGR_WORKQ_SERIAL * This function will allocate and create workqueue and pass * the workq pointer to caller. */ int cam_req_mgr_workq_create(char *name, int32_t num_tasks, - struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq); + struct cam_req_mgr_core_workq **workq, enum crm_workq_context in_irq, + int flags); /** * cam_req_mgr_workq_destroy() 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 a34d70c50a948cd9acbe77cf11a9b72552557d48..ed0a26b70effc1c7c37f2402b146531fff45e32e 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 @@ -53,6 +53,8 @@ int32_t cam_actuator_construct_default_power_setting( free_power_settings: kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; return rc; } @@ -268,7 +270,10 @@ int32_t cam_actuator_apply_settings(struct cam_actuator_ctrl_t *a_ctrl, CAM_ERR(CAM_ACTUATOR, "Failed to apply settings: %d", rc); - return rc; + } else { + CAM_DBG(CAM_ACTUATOR, + "Success:request ID: %d", + i2c_set->request_id); } } @@ -358,6 +363,28 @@ int32_t cam_actuator_establish_link( return 0; } +static void cam_actuator_update_req_mgr( + struct cam_actuator_ctrl_t *a_ctrl, + struct cam_packet *csl_packet) +{ + struct cam_req_mgr_add_request add_req; + + add_req.link_hdl = a_ctrl->bridge_intf.link_hdl; + add_req.req_id = csl_packet->header.request_id; + add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl; + add_req.skip_before_applying = 0; + + if (a_ctrl->bridge_intf.crm_cb && + a_ctrl->bridge_intf.crm_cb->add_req) { + a_ctrl->bridge_intf.crm_cb->add_req(&add_req); + CAM_DBG(CAM_ACTUATOR, "Request Id: %lld added to CRM", + add_req.req_id); + } else { + CAM_ERR(CAM_ACTUATOR, "Can't add Request ID: %lld to CRM", + csl_packet->header.request_id); + } +} + int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) { if (!info) { @@ -367,7 +394,7 @@ int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) info->dev_id = CAM_REQ_MGR_DEVICE_ACTUATOR; strlcpy(info->name, CAM_ACTUATOR_NAME, sizeof(info->name)); - info->p_delay = 0; + info->p_delay = 1; info->trigger = CAM_TRIGGER_POINT_SOF; return 0; @@ -390,7 +417,6 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, struct i2c_data_settings *i2c_data = NULL; struct i2c_settings_array *i2c_reg_settings = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; - struct cam_req_mgr_add_request add_req; struct cam_actuator_soc_private *soc_private = NULL; struct cam_sensor_power_ctrl_t *power_info = NULL; @@ -554,6 +580,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, "Auto move lens parsing failed: %d", rc); return rc; } + cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; case CAM_ACTUATOR_PACKET_MANUAL_MOVE_LENS: if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { @@ -563,11 +590,13 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, a_ctrl->cam_act_state); return rc; } + + a_ctrl->setting_apply_state = ACT_APPLY_SETTINGS_LATER; i2c_data = &(a_ctrl->i2c_data); i2c_reg_settings = &i2c_data->per_frame[ csl_packet->header.request_id % MAX_PER_FRAME_ARRAY]; - i2c_data->init_settings.request_id = + i2c_reg_settings->request_id = csl_packet->header.request_id; i2c_reg_settings->is_settings_valid = 1; offset = (uint32_t *)&csl_packet->payload; @@ -582,20 +611,19 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, "Manual move lens parsing failed: %d", rc); return rc; } + + cam_actuator_update_req_mgr(a_ctrl, csl_packet); break; - } + case CAM_PKT_NOP_OPCODE: + if (a_ctrl->cam_act_state < CAM_ACTUATOR_CONFIG) { + CAM_WARN(CAM_ACTUATOR, + "Received NOP packets in invalid state: %d", + a_ctrl->cam_act_state); + return -EINVAL; + } - if ((csl_packet->header.op_code & 0xFFFFFF) != - CAM_ACTUATOR_PACKET_OPCODE_INIT) { - add_req.link_hdl = a_ctrl->bridge_intf.link_hdl; - add_req.req_id = csl_packet->header.request_id; - add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl; - add_req.skip_before_applying = 0; - if (a_ctrl->bridge_intf.crm_cb && - a_ctrl->bridge_intf.crm_cb->add_req) - a_ctrl->bridge_intf.crm_cb->add_req(&add_req); - CAM_DBG(CAM_ACTUATOR, "Req Id: %lld added to Bridge", - add_req.req_id); + cam_actuator_update_req_mgr(a_ctrl, csl_packet); + break; } return rc; @@ -632,6 +660,8 @@ void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; } @@ -641,12 +671,19 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, { int rc = 0; struct cam_control *cmd = (struct cam_control *)arg; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; if (!a_ctrl || !cmd) { - CAM_ERR(CAM_ACTUATOR, " Invalid Args"); + CAM_ERR(CAM_ACTUATOR, "Invalid Args"); return -EINVAL; } + soc_private = + (struct cam_actuator_soc_private *)a_ctrl->soc_info.soc_private; + + power_info = &soc_private->power_info; + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { CAM_ERR(CAM_ACTUATOR, "Invalid handle type: %d", cmd->handle_type); @@ -729,6 +766,12 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, a_ctrl->bridge_intf.link_hdl = -1; a_ctrl->bridge_intf.session_hdl = -1; a_ctrl->cam_act_state = CAM_ACTUATOR_INIT; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; } break; case CAM_QUERY_CAP: { @@ -835,6 +878,11 @@ int32_t cam_actuator_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + if (a_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_ACTUATOR, "i2c frame data is NULL"); + return -EINVAL; + } + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { i2c_set = &(a_ctrl->i2c_data.per_frame[i]); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c index 96fdfeb1b4bab9441011a086d06d401aeea0c438..7d23f900199e0c7620be4e94244f0dab721b05dd 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_dev.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 @@ -252,6 +252,8 @@ static int32_t cam_actuator_platform_remove(struct platform_device *pdev) 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); kfree(a_ctrl->i2c_data.per_frame); a_ctrl->i2c_data.per_frame = NULL; @@ -284,6 +286,8 @@ static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) 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; kfree(a_ctrl); return rc; @@ -393,6 +397,7 @@ static struct platform_driver cam_actuator_platform_driver = { .name = "qcom,actuator", .owner = THIS_MODULE, .of_match_table = cam_actuator_driver_dt_match, + .suppress_bind_attrs = true, }, .remove = cam_actuator_platform_remove, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c index b47f4f35b1089ececc3b865ce8f1b61edea6d15c..058e3528e248b5d010b39e267f6a8789ab89e8fc 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c @@ -1410,7 +1410,7 @@ static int32_t cam_cci_read_bytes(struct v4l2_subdev *sd, else rc = cam_cci_read(sd, c_ctrl); - if (!rc) { + if (rc) { CAM_ERR(CAM_CCI, "failed to read rc:%d", rc); goto ERROR; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index c8ca85dafdbaafc0814ef4f2d81764ccd665142d..ce7ac3f0b820bfd05157c508b9ab6492b5e5ad8c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -373,6 +373,7 @@ static struct platform_driver cci_driver = { .name = CAMX_CCI_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_cci_dt_match, + .suppress_bind_attrs = true, }, }; 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 2688cd57db8981e054ca062caa282eb893f260b8..bc61df42bb946f02c9ca312a29a589976f525def 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 @@ -177,7 +177,7 @@ irqreturn_t cam_csiphy_irq(int irq_num, void *data) if (!csiphy_dev) { CAM_ERR(CAM_CSIPHY, "Invalid Args"); - return -EINVAL; + return IRQ_NONE; } soc_info = &csiphy_dev->soc_info; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c index e2f061f49a3149bd5575bd824221197f4b05c288..32bb34bb257b720fba9f91052249b1af3a535e48 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.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 @@ -233,6 +233,7 @@ static struct platform_driver csiphy_driver = { .name = CAMX_CSIPHY_DEV_NAME, .owner = THIS_MODULE, .of_match_table = cam_csiphy_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index afe4239b2d7196c2a4197daf413d82a2e5fd6d7f..9c85af39bd8ccdec9afdf37ae00962a74be691bf 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -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 @@ -198,7 +198,6 @@ struct cam_csiphy_param { * @csiphy_reg_ptr: Regulator structure * @csiphy_3p_clk_info: 3Phase clock information * @csiphy_3p_clk: 3Phase clocks structure - * @csiphy_clk_index: Timer Src clk index * @csi_3phase: Is it a 3Phase mode * @ref_count: Reference count * @clk_lane: Clock lane @@ -216,7 +215,6 @@ struct csiphy_device { uint32_t csiphy_max_clk; struct msm_cam_clk_info csiphy_3p_clk_info[2]; struct clk *csiphy_3p_clk[2]; - uint32_t csiphy_clk_index; unsigned char csi_3phase; int32_t ref_count; uint16_t lane_mask[MAX_CSIPHY]; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c index 6db5a9796606bfb23b61e6a9abd14e680bd9ae48..28326ecadd2cc66cb38b0d2be962aed883241d25 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_soc.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 @@ -97,10 +97,8 @@ int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) return rc; } - rc = cam_soc_util_set_clk_rate( - soc_info->clk[csiphy_dev->csiphy_clk_index], - soc_info->clk_name[csiphy_dev->csiphy_clk_index], - soc_info->clk_rate[0][csiphy_dev->csiphy_clk_index]); + rc = cam_soc_util_set_src_clk_rate(soc_info, + soc_info->clk_rate[0][soc_info->src_clk_idx]); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "csiphy_clk_set_rate failed rc: %d", rc); @@ -208,16 +206,14 @@ int32_t cam_csiphy_parse_dt_info(struct platform_device *pdev, continue; } - if (!strcmp(soc_info->clk_name[i], - "csiphy_timer_src_clk")) { - csiphy_dev->csiphy_max_clk = - soc_info->clk_rate[0][clk_cnt]; - csiphy_dev->csiphy_clk_index = clk_cnt; - } CAM_DBG(CAM_CSIPHY, "clk_rate[%d] = %d", clk_cnt, soc_info->clk_rate[0][clk_cnt]); clk_cnt++; } + + csiphy_dev->csiphy_max_clk = + soc_info->clk_rate[0][soc_info->src_clk_idx]; + rc = cam_soc_util_request_platform_resource(&csiphy_dev->soc_info, cam_csiphy_irq, csiphy_dev); 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 7f94f8d8c80d421ad659a60cdb22acacf0443fa0..c8730cab765c383ec4fcc4f52ee770a678d8a3a7 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 @@ -785,6 +785,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; break; @@ -838,6 +840,8 @@ void cam_eeprom_shutdown(struct cam_eeprom_ctrl_t *e_ctrl) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; } e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c index b8c32d4ce3b7736e04bc3dd7f70bec81de549c95..cc34a70893db053c0d31d302edf0074f78422a14 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -508,6 +508,7 @@ static struct platform_driver cam_eeprom_platform_driver = { .name = "qcom,eeprom", .owner = THIS_MODULE, .of_match_table = cam_eeprom_dt_match, + .suppress_bind_attrs = true, }, .probe = cam_eeprom_platform_driver_probe, .remove = cam_eeprom_platform_driver_remove, diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c index 5a6a4010231d1d7224b3daa8ed62fa847f1aabb9..afab016756f658b72e9b948a8d0a0c7299e58ebe 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_soc.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 @@ -135,7 +135,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; } - map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + map = vzalloc((sizeof(*map) * data->num_map)); if (!map) { rc = -ENOMEM; return rc; @@ -184,7 +184,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, data->num_data += map[i].mem.valid_size; } - data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + data->mapdata = vzalloc(data->num_data); if (!data->mapdata) { rc = -ENOMEM; goto ERROR; @@ -192,7 +192,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; ERROR: - kfree(data->map); + vfree(data->map); memset(data, 0, sizeof(*data)); return rc; } 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 9b748268a448e84f6ec3e21eb02375cee8596e42..4a9cfb0457b280b46e04024e7a951a74b5f2c561 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 @@ -151,7 +151,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, else curr = soc_private->torch_op_current[i]; - CAM_DBG(CAM_FLASH, + CAM_DBG(CAM_PERF, "Led_Current[%d] = %d", i, curr); cam_res_mgr_led_trigger_event( flash_ctrl->torch_trigger[i], @@ -169,7 +169,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, else curr = soc_private->flash_op_current[i]; - CAM_DBG(CAM_FLASH, "LED flash_current[%d]: %d", + CAM_DBG(CAM_PERF, "LED flash_current[%d]: %d", i, curr); cam_res_mgr_led_trigger_event( flash_ctrl->flash_trigger[i], @@ -191,25 +191,11 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) { - int i = 0; - if (!flash_ctrl) { CAM_ERR(CAM_FLASH, "Flash control Null"); return -EINVAL; } - for (i = 0; i < flash_ctrl->flash_num_sources; i++) - if (flash_ctrl->flash_trigger[i]) - cam_res_mgr_led_trigger_event( - flash_ctrl->flash_trigger[i], - LED_OFF); - - for (i = 0; i < flash_ctrl->torch_num_sources; i++) - if (flash_ctrl->torch_trigger[i]) - cam_res_mgr_led_trigger_event( - flash_ctrl->torch_trigger[i], - LED_OFF); - if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, LED_SWITCH_OFF); @@ -352,6 +338,10 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, if (fctrl->nrt_info.cmn_attr.cmd_type == CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE) { flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_INIT_FIRE req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { if (fctrl->flash_state != @@ -395,6 +385,10 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, } else if (fctrl->nrt_info.cmn_attr.cmd_type == CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) { flash_data = &fctrl->nrt_info; + CAM_DBG(CAM_REQ, + "FLASH_WIDGET req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); + if (flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIRELOW) { rc = cam_flash_low(fctrl, flash_data); @@ -425,6 +419,8 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, goto nrt_del_req; } } + CAM_DBG(CAM_REQ, "FLASH_RER req_id: %u", req_id); + num_iterations = flash_data->num_iterations; for (i = 0; i < num_iterations; i++) { /* Turn On Torch */ @@ -459,6 +455,8 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, } else { frame_offset = req_id % MAX_PER_FRAME_ARRAY; flash_data = &fctrl->per_frame[frame_offset]; + CAM_DBG(CAM_REQ, "FLASH_RT req_id: %u flash_opcode: %d", + req_id, flash_data->opcode); if ((flash_data->opcode == CAMERA_SENSOR_FLASH_OP_FIREHIGH) && (flash_data->cmn_attr.is_settings_valid) && @@ -496,8 +494,14 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, "Flash off failed %d", rc); goto apply_setting_err; } + } else if (flash_data->opcode == CAM_PKT_NOP_OPCODE) { + flash_data->opcode = 0; + CAM_DBG(CAM_FLASH, "NOP Packet"); } else { - CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id); + rc = -EINVAL; + CAM_ERR(CAM_FLASH, "Invalid opcode: %d req_id: %llu", + flash_data->opcode, req_id); + goto apply_setting_err; } } @@ -768,17 +772,20 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) break; } case CAM_PKT_NOP_OPCODE: { + frm_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; if ((fctrl->flash_state == CAM_FLASH_STATE_INIT) || (fctrl->flash_state == CAM_FLASH_STATE_ACQUIRE)) { CAM_WARN(CAM_FLASH, "Rxed NOP packets without linking"); - frm_offset = csl_packet->header.request_id % - MAX_PER_FRAME_ARRAY; fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; return 0; } + fctrl->per_frame[frm_offset].cmn_attr.is_settings_valid = false; + fctrl->per_frame[frm_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frm_offset].opcode = CAM_PKT_NOP_OPCODE; CAM_DBG(CAM_FLASH, "NOP Packet is Received: req_id: %u", csl_packet->header.request_id); goto update_req_mgr; @@ -928,19 +935,15 @@ int cam_flash_apply_request(struct cam_req_mgr_apply_request *apply) fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(apply->dev_hdl); if (!fctrl) { CAM_ERR(CAM_FLASH, "Device data is NULL"); - rc = -EINVAL; - goto free_resource; + return -EINVAL; } - if (!(apply->report_if_bubble)) { - mutex_lock(&fctrl->flash_wq_mutex); - rc = cam_flash_apply_setting(fctrl, apply->request_id); - if (rc) - CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", - rc); - mutex_unlock(&fctrl->flash_wq_mutex); - } + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, apply->request_id); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); -free_resource: return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c index f9411fcfa4b35e1a17c8fc300231cf0ef83eac7f..d9b5f6406058b0fca7bc54085b05ade6bd5936b8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -394,6 +394,7 @@ static struct platform_driver cam_flash_platform_driver = { .name = "CAM-FLASH-DRIVER", .owner = THIS_MODULE, .of_match_table = cam_flash_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h index 92726a9a125c6c484a0ebec4022ef3d4f5509a24..4adc1b2e32a91831d0ff88db22aa1593191b7929 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -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 @@ -78,10 +78,10 @@ struct cam_flash_intf_params { * @cmd_type : Command buffer type */ struct cam_flash_common_attr { - bool is_settings_valid; - int32_t request_id; - uint16_t count; - uint8_t cmd_type; + bool is_settings_valid; + uint64_t request_id; + uint16_t count; + uint8_t cmd_type; }; /** 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 dfcb9fcba4b78e2a774a372127c2a1480b167b04..c2d2e5f42abe31bd17725b2e72e9d46175b89227 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 @@ -55,6 +55,8 @@ int32_t cam_ois_construct_default_power_setting( free_power_settings: kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; return rc; } @@ -637,10 +639,9 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) { int rc = 0; - struct cam_ois_soc_private *soc_private = + struct cam_ois_soc_private *soc_private = (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; - struct cam_sensor_power_ctrl_t *power_info = - &soc_private->power_info; + struct cam_sensor_power_ctrl_t *power_info = &soc_private->power_info; if (o_ctrl->cam_ois_state == CAM_OIS_INIT) return; @@ -665,6 +666,8 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; o_ctrl->cam_ois_state = CAM_OIS_INIT; } @@ -678,11 +681,13 @@ void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) */ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) { - int rc = 0; - struct cam_ois_query_cap_t ois_cap = {0}; - struct cam_control *cmd = (struct cam_control *)arg; + int rc = 0; + struct cam_ois_query_cap_t ois_cap = {0}; + struct cam_control *cmd = (struct cam_control *)arg; + struct cam_ois_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; - if (!o_ctrl || !arg) { + if (!o_ctrl || !cmd) { CAM_ERR(CAM_OIS, "Invalid arguments"); return -EINVAL; } @@ -693,6 +698,10 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) return -EINVAL; } + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + mutex_lock(&(o_ctrl->ois_mutex)); switch (cmd->op_code) { case CAM_QUERY_CAP: @@ -763,6 +772,13 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) o_ctrl->bridge_intf.link_hdl = -1; o_ctrl->bridge_intf.session_hdl = -1; o_ctrl->cam_ois_state = CAM_OIS_INIT; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; break; case CAM_STOP_DEV: if (o_ctrl->cam_ois_state != CAM_OIS_START) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c index d742acf7813d928a15baaa4050b92f6618bf2d78..5d16a4e54d045097b82345f00a8021f2152b379e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_dev.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 @@ -240,6 +240,8 @@ static int cam_ois_i2c_driver_remove(struct i2c_client *client) 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); @@ -341,6 +343,8 @@ static int cam_ois_platform_driver_remove(struct platform_device *pdev) 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); kfree(o_ctrl); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c index bb3789b12dccb79a1e992632f499a946ad4233a7..d03faef4d3a6d5c570e3538cd21353642162544c 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.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 @@ -718,6 +718,7 @@ static struct platform_driver cam_res_mgr_driver = { .name = "cam_res_mgr", .owner = THIS_MODULE, .of_match_table = cam_res_mgr_dt_match, + .suppress_bind_attrs = true, }, }; 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 2133932dde579be7e1d81f40d34e398efe961a2c..a2431be711766226db02a99c58c00ac7cace8d8d 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 @@ -17,7 +17,6 @@ #include "cam_soc_util.h" #include "cam_trace.h" - static void cam_sensor_update_req_mgr( struct cam_sensor_ctrl_t *s_ctrl, struct cam_packet *csl_packet) @@ -500,8 +499,8 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) &s_ctrl->sensordata->power_info; int rc = 0; - s_ctrl->is_probe_succeed = 0; - if (s_ctrl->sensor_state == CAM_SENSOR_INIT) + if ((s_ctrl->sensor_state == CAM_SENSOR_INIT) && + (s_ctrl->is_probe_succeed == 0)) return; cam_sensor_release_resource(s_ctrl); @@ -515,14 +514,15 @@ void cam_sensor_shutdown(struct cam_sensor_ctrl_t *s_ctrl) s_ctrl->bridge_intf.device_hdl = -1; s_ctrl->bridge_intf.link_hdl = -1; s_ctrl->bridge_intf.session_hdl = -1; - kfree(power_info->power_setting); kfree(power_info->power_down_setting); power_info->power_setting = NULL; power_info->power_down_setting = NULL; - + power_info->power_setting_size = 0; + power_info->power_down_setting_size = 0; s_ctrl->streamon_count = 0; s_ctrl->streamoff_count = 0; + s_ctrl->is_probe_succeed = 0; s_ctrl->sensor_state = CAM_SENSOR_INIT; } @@ -561,8 +561,6 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, { int rc = 0; struct cam_control *cmd = (struct cam_control *)arg; - struct cam_sensor_power_setting *pu = NULL; - struct cam_sensor_power_setting *pd = NULL; struct cam_sensor_power_ctrl_t *power_info = &s_ctrl->sensordata->power_info; if (!s_ctrl || !arg) { @@ -592,19 +590,15 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = cam_handle_mem_ptr(cmd->handle, s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Get Buffer Handle Failed"); - kfree(pu); - kfree(pd); goto release_mutex; } } else { CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", cmd->handle_type); - return -EINVAL; + rc = -EINVAL; + goto release_mutex; } - pu = power_info->power_setting; - pd = power_info->power_down_setting; - /* Parse and fill vreg params for powerup settings */ rc = msm_camera_fill_vreg_params( &s_ctrl->soc_info, @@ -614,9 +608,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "Fail in filling vreg params for PUP rc %d", rc); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* Parse and fill vreg params for powerdown settings*/ @@ -628,18 +620,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "Fail in filling vreg params for PDOWN rc %d", rc); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* Power up and probe sensor */ rc = cam_sensor_power_up(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "power up failed"); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* Match sensor ID */ @@ -647,13 +635,11 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, if (rc < 0) { cam_sensor_power_down(s_ctrl); msleep(20); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } CAM_INFO(CAM_SENSOR, - "Probe Succees,slot:%d,slave_addr:0x%x,sensor_id:0x%x", + "Probe success,slot:%d,slave_addr:0x%x,sensor_id:0x%x", s_ctrl->soc_info.index, s_ctrl->sensordata->slave_info.sensor_slave_addr, s_ctrl->sensordata->slave_info.sensor_id); @@ -661,9 +647,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, rc = cam_sensor_power_down(s_ctrl); if (rc < 0) { CAM_ERR(CAM_SENSOR, "fail in Sensor Power Down"); - kfree(pu); - kfree(pd); - goto release_mutex; + goto free_power_settings; } /* * Set probe succeeded flag to 1 so that no other camera shall @@ -677,6 +661,15 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, struct cam_sensor_acquire_dev sensor_acq_dev; struct cam_create_dev_hdl bridge_params; + if ((s_ctrl->is_probe_succeed == 0) || + (s_ctrl->sensor_state != CAM_SENSOR_INIT)) { + CAM_WARN(CAM_SENSOR, + "Not in right state to aquire %d", + s_ctrl->sensor_state); + rc = -EINVAL; + goto release_mutex; + } + if (s_ctrl->bridge_intf.device_hdl != -1) { CAM_ERR(CAM_SENSOR, "Device is already acquired"); rc = -EINVAL; @@ -885,6 +878,16 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, release_mutex: mutex_unlock(&(s_ctrl->cam_sensor_mutex)); return rc; + +free_power_settings: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + power_info->power_setting = NULL; + power_info->power_down_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; + mutex_unlock(&(s_ctrl->cam_sensor_mutex)); + return rc; } int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) @@ -961,6 +964,16 @@ int cam_sensor_power_up(struct cam_sensor_ctrl_t *s_ctrl) return -EINVAL; } + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, true); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + rc = cam_sensor_core_power_up(power_info, soc_info); if (rc < 0) { CAM_ERR(CAM_SENSOR, "power up the core is failed:%d", rc); @@ -998,6 +1011,16 @@ int cam_sensor_power_down(struct cam_sensor_ctrl_t *s_ctrl) return rc; } + if (s_ctrl->bob_pwm_switch) { + rc = cam_sensor_bob_pwm_mode_switch(soc_info, + s_ctrl->bob_reg_index, false); + if (rc) { + CAM_WARN(CAM_SENSOR, + "BoB PWM setup failed rc: %d", rc); + rc = 0; + } + } + camera_io_release(&(s_ctrl->io_master_info)); return rc; @@ -1130,7 +1153,7 @@ int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) CAM_ERR(CAM_SENSOR, "Device data is NULL"); return -EINVAL; } - CAM_DBG(CAM_SENSOR, " Req Id: %lld", apply->request_id); + CAM_DBG(CAM_REQ, " Sensor update req id: %lld", apply->request_id); trace_cam_apply_req("Sensor", apply->request_id); rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); @@ -1154,6 +1177,11 @@ int32_t cam_sensor_flush_request(struct cam_req_mgr_flush_request *flush_req) return -EINVAL; } + if (s_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + return -EINVAL; + } + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { i2c_set = &(s_ctrl->i2c_data.per_frame[i]); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c index b60111af16206aaa5e38a73f50d39394c4fa35c3..6cf40f8b0f1086b94de3b299965eb065cb239ae8 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.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 @@ -339,6 +339,7 @@ static struct platform_driver cam_sensor_platform_driver = { .name = "qcom,camera", .owner = THIS_MODULE, .of_match_table = cam_sensor_driver_dt_match, + .suppress_bind_attrs = true, }, .remove = cam_sensor_platform_remove, }; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h index cc6070cdc1b6cefcfb1bd89845f870b4d6f5b26e..34f8b8dba69666119441aea4fea706d84f8964f7 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -92,6 +92,8 @@ struct intf_params { * @device_name: Sensor device structure * @streamon_count: Count to hold the number of times stream on called * @streamoff_count: Count to hold the number of times stream off called + * @bob_reg_index: Hold to BoB regulator index + * @bob_pwm_switch: Boolean flag to switch into PWM mode for BoB regulator */ struct cam_sensor_ctrl_t { struct platform_device *pdev; @@ -113,6 +115,8 @@ struct cam_sensor_ctrl_t { char device_name[20]; uint32_t streamon_count; uint32_t streamoff_count; + int bob_reg_index; + bool bob_pwm_switch; }; #endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c index 1c3ead0c25bff01606c1079d1e785566d3e25851..e997419359c5d0aba389e4d90e499f982ffa393a 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_soc.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 @@ -104,6 +104,7 @@ int32_t cam_sensor_get_sub_module_index(struct device_node *of_node, static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) { int32_t rc = 0; + int i = 0; struct cam_sensor_board_info *sensordata = NULL; struct device_node *of_node = s_ctrl->of_node; struct cam_hw_soc_info *soc_info = &s_ctrl->soc_info; @@ -135,6 +136,33 @@ static int32_t cam_sensor_driver_get_dt_data(struct cam_sensor_ctrl_t *s_ctrl) goto FREE_SENSOR_DATA; } + /* Store the index of BoB regulator if it is available */ + for (i = 0; i < soc_info->num_rgltr; i++) { + if (!strcmp(soc_info->rgltr_name[i], + "cam_bob")) { + CAM_DBG(CAM_SENSOR, + "i: %d cam_bob", i); + s_ctrl->bob_reg_index = i; + soc_info->rgltr[i] = devm_regulator_get(soc_info->dev, + soc_info->rgltr_name[i]); + if (IS_ERR_OR_NULL(soc_info->rgltr[i])) { + CAM_WARN(CAM_SENSOR, + "Regulator: %s get failed", + soc_info->rgltr_name[i]); + soc_info->rgltr[i] = NULL; + } else { + if (!of_property_read_bool(of_node, + "pwm-switch")) { + CAM_DBG(CAM_SENSOR, + "No BoB PWM switch param defined"); + s_ctrl->bob_pwm_switch = false; + } else { + s_ctrl->bob_pwm_switch = true; + } + } + } + } + /* Read subdev info */ rc = cam_sensor_get_sub_module_index(of_node, sensordata); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c index 1c6ab0b1d94bd55b95cdc2f10713022abca8d2b6..9145a1e52f3ef5d2ee2dd1796aa9869948092c4f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.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 @@ -245,9 +245,15 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, enum camera_sensor_i2c_type data_type) { int32_t rc = 0; - unsigned char buf[I2C_REG_MAX_BUF_SIZE]; + unsigned char *buf = NULL; uint8_t len = 0; + buf = kzalloc(I2C_REG_MAX_BUF_SIZE, GFP_KERNEL | GFP_DMA); + if (!buf) { + CAM_ERR(CAM_SENSOR, "Buffer memory allocation failed"); + return -ENOMEM; + } + CAM_DBG(CAM_SENSOR, "reg addr = 0x%x data type: %d", reg_setting->reg_addr, data_type); if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) { @@ -273,7 +279,8 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, len = 4; } else { CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); - return -EINVAL; + rc = -EINVAL; + goto deallocate_buffer; } CAM_DBG(CAM_SENSOR, "Data: 0x%x", reg_setting->reg_data); @@ -307,12 +314,16 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, len += 4; } else { CAM_ERR(CAM_SENSOR, "Invalid Data Type"); - return -EINVAL; + rc = -EINVAL; + goto deallocate_buffer; } rc = cam_qup_i2c_txdata(client, buf, len); if (rc < 0) CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + +deallocate_buffer: + kfree(buf); return rc; } diff --git a/drivers/media/platform/msm/camera/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 73a0cf71071e3ce14480fe6ede5a130ed7fb3860..46bda0589c52b12dbe3a838a13ebe40ca7c89313 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 @@ -711,8 +711,10 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, kzalloc(sizeof(struct cam_sensor_power_setting) * MAX_POWER_CONFIG, GFP_KERNEL); if (!power_info->power_down_setting) { - rc = -ENOMEM; - goto free_power_settings; + kfree(power_info->power_setting); + power_info->power_setting = NULL; + power_info->power_setting_size = 0; + return -ENOMEM; } while (tot_size < cmd_length) { @@ -722,11 +724,18 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, (struct cam_cmd_power *)ptr; power_info->power_setting_size += pwr_cmd->count; + if (power_info->power_setting_size > MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, + "Invalid: power up setting size %d", + power_info->power_setting_size); + rc = -EINVAL; + goto free_power_settings; + } scr = ptr + sizeof(struct cam_cmd_power); tot_size = tot_size + sizeof(struct cam_cmd_power); if (pwr_cmd->count == 0) - CAM_WARN(CAM_SENSOR, "Un expected Command"); + CAM_WARN(CAM_SENSOR, "pwr_up_size is zero"); for (i = 0; i < pwr_cmd->count; i++, pwr_up++) { power_info->power_setting[pwr_up].seq_type = @@ -746,7 +755,7 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, CAM_ERR(CAM_SENSOR, "Error: Cmd Buffer is wrong"); rc = -EINVAL; - goto free_power_down_settings; + goto free_power_settings; } CAM_DBG(CAM_SENSOR, "Seq Type[%d]: %d Config_val: %ld", pwr_up, @@ -814,9 +823,17 @@ 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); power_info->power_down_setting_size += pwr_cmd->count; + if (power_info->power_down_setting_size > + MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, + "Invalid: power down setting size %d", + power_info->power_down_setting_size); + rc = -EINVAL; + goto free_power_settings; + } if (pwr_cmd->count == 0) - CAM_ERR(CAM_SENSOR, "Invalid Command"); + CAM_ERR(CAM_SENSOR, "pwr_down size is zero"); for (i = 0; i < pwr_cmd->count; i++, pwr_down++) { pwr_settings = @@ -840,7 +857,7 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, CAM_ERR(CAM_SENSOR, "Command Buffer is wrong"); rc = -EINVAL; - goto free_power_down_settings; + goto free_power_settings; } CAM_DBG(CAM_SENSOR, "Seq Type[%d]: %d Config_val: %ld", @@ -854,16 +871,19 @@ int32_t cam_sensor_update_power_settings(void *cmd_buf, CAM_ERR(CAM_SENSOR, "Error: Un expected Header Type: %d", cmm_hdr->cmd_type); + rc = -EINVAL; + goto free_power_settings; } } return rc; -free_power_down_settings: - kfree(power_info->power_down_setting); - power_info->power_down_setting = NULL; free_power_settings: + kfree(power_info->power_down_setting); kfree(power_info->power_setting); + power_info->power_down_setting = NULL; power_info->power_setting = NULL; + power_info->power_down_setting_size = 0; + power_info->power_setting_size = 0; return rc; } @@ -1218,6 +1238,24 @@ int msm_camera_pinctrl_init( return 0; } +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag) +{ + int rc = 0; + uint32_t op_current = + (flag == true) ? soc_info->rgltr_op_mode[bob_reg_idx] : 0; + + if (soc_info->rgltr[bob_reg_idx] != NULL) { + rc = regulator_set_load(soc_info->rgltr[bob_reg_idx], + op_current); + if (rc) + CAM_WARN(CAM_SENSOR, + "BoB PWM SetLoad failed rc: %d", rc); + } + + return rc; +} + int msm_cam_sensor_handle_reg_gpio(int seq_type, struct msm_camera_gpio_num_info *gpio_num_info, int val) { @@ -1243,10 +1281,62 @@ int msm_cam_sensor_handle_reg_gpio(int seq_type, return 0; } +static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, + struct cam_hw_soc_info *soc_info, int32_t index) +{ + int32_t num_vreg = 0, j = 0, rc = 0, idx = 0; + struct cam_sensor_power_setting *ps = NULL; + struct cam_sensor_power_setting *pd = NULL; + + num_vreg = soc_info->num_rgltr; + + pd = &ctrl->power_down_setting[index]; + + for (j = 0; j < num_vreg; j++) { + if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { + ps = NULL; + for (idx = 0; idx < ctrl->power_setting_size; idx++) { + if (ctrl->power_setting[idx].seq_type == + pd->seq_type) { + ps = &ctrl->power_setting[idx]; + break; + } + } + + if (ps != NULL) { + CAM_DBG(CAM_SENSOR, "Disable MCLK Regulator"); + rc = cam_soc_util_regulator_disable( + soc_info->rgltr[j], + soc_info->rgltr_name[j], + soc_info->rgltr_min_volt[j], + soc_info->rgltr_max_volt[j], + soc_info->rgltr_op_mode[j], + soc_info->rgltr_delay[j]); + + if (rc) { + CAM_ERR(CAM_SENSOR, + "MCLK REG DISALBE FAILED: %d", + rc); + return rc; + } + + ps->data[0] = + soc_info->rgltr[j]; + + regulator_put( + soc_info->rgltr[j]); + soc_info->rgltr[j] = NULL; + } + } + } + + return rc; +} + int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, struct cam_hw_soc_info *soc_info) { - int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0; + int rc = 0, index = 0, no_gpio = 0, ret = 0, num_vreg, j = 0, i = 0; int32_t vreg_idx = -1; struct cam_sensor_power_setting *power_setting = NULL; struct msm_camera_gpio_num_info *gpio_num_info = NULL; @@ -1343,6 +1433,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_name[j], rc); soc_info->rgltr[j] = NULL; + goto power_up_failed; } rc = cam_soc_util_regulator_enable( @@ -1352,7 +1443,11 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_max_volt[j], soc_info->rgltr_op_mode[j], soc_info->rgltr_delay[j]); - + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg enable failed"); + goto power_up_failed; + } power_setting->data[0] = soc_info->rgltr[j]; } @@ -1433,6 +1528,7 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, rc); soc_info->rgltr[vreg_idx] = NULL; + goto power_up_failed; } rc = cam_soc_util_regulator_enable( @@ -1442,7 +1538,12 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_max_volt[vreg_idx], soc_info->rgltr_op_mode[vreg_idx], soc_info->rgltr_delay[vreg_idx]); - + if (rc) { + CAM_ERR(CAM_SENSOR, + "Reg Enable failed for %s", + soc_info->rgltr_name[vreg_idx]); + goto power_up_failed; + } power_setting->data[0] = soc_info->rgltr[vreg_idx]; } @@ -1485,6 +1586,18 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, CAM_DBG(CAM_SENSOR, "type %d", power_setting->seq_type); switch (power_setting->seq_type) { + case SENSOR_MCLK: + for (i = soc_info->num_clk - 1; i >= 0; i--) { + cam_soc_util_clk_disable(soc_info->clk[i], + soc_info->clk_name[i]); + } + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } + break; case SENSOR_RESET: case SENSOR_STANDBY: case SENSOR_CUSTOM_GPIO1: @@ -1517,11 +1630,21 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_op_mode[vreg_idx], soc_info->rgltr_delay[vreg_idx]); + if (rc) { + CAM_ERR(CAM_SENSOR, + "Fail to disalbe reg: %s", + soc_info->rgltr_name[vreg_idx]); + soc_info->rgltr[vreg_idx] = NULL; + msm_cam_sensor_handle_reg_gpio( + power_setting->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } power_setting->data[0] = soc_info->rgltr[vreg_idx]; - regulator_put( - soc_info->rgltr[vreg_idx]); + regulator_put(soc_info->rgltr[vreg_idx]); soc_info->rgltr[vreg_idx] = NULL; } else @@ -1547,8 +1670,8 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, if (ctrl->cam_pinctrl_status) { ret = pinctrl_select_state( - ctrl->pinctrl_info.pinctrl, - ctrl->pinctrl_info.gpio_state_suspend); + ctrl->pinctrl_info.pinctrl, + ctrl->pinctrl_info.gpio_state_suspend); if (ret) CAM_ERR(CAM_SENSOR, "cannot set pin to suspend state"); cam_res_mgr_shared_pinctrl_select_state(false); @@ -1587,54 +1710,6 @@ msm_camera_get_power_settings(struct cam_sensor_power_ctrl_t *ctrl, return ps; } -static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, - struct cam_hw_soc_info *soc_info, int32_t index) -{ - int32_t num_vreg = 0, j = 0, rc = 0, idx = 0; - struct cam_sensor_power_setting *ps = NULL; - struct cam_sensor_power_setting *pd = NULL; - - num_vreg = soc_info->num_rgltr; - - pd = &ctrl->power_down_setting[index]; - - for (j = 0; j < num_vreg; j++) { - if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { - - ps = NULL; - for (idx = 0; idx < - ctrl->power_setting_size; idx++) { - if (ctrl->power_setting[idx]. - seq_type == pd->seq_type) { - ps = &ctrl->power_setting[idx]; - break; - } - } - - if (ps != NULL) { - CAM_DBG(CAM_SENSOR, "Disable Regulator"); - - rc = cam_soc_util_regulator_disable( - soc_info->rgltr[j], - soc_info->rgltr_name[j], - soc_info->rgltr_min_volt[j], - soc_info->rgltr_max_volt[j], - soc_info->rgltr_op_mode[j], - soc_info->rgltr_delay[j]); - - ps->data[0] = - soc_info->rgltr[j]; - - regulator_put( - soc_info->rgltr[j]); - soc_info->rgltr[j] = NULL; - } - } - } - - return rc; -} - int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, struct cam_hw_soc_info *soc_info) { @@ -1657,8 +1732,14 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, return -EINVAL; } + if (ctrl->power_down_setting_size > MAX_POWER_CONFIG) { + CAM_ERR(CAM_SENSOR, "Invalid: power setting size %d", + ctrl->power_setting_size); + return -EINVAL; + } + for (index = 0; index < ctrl->power_down_setting_size; index++) { - CAM_DBG(CAM_SENSOR, "index %d", index); + CAM_DBG(CAM_SENSOR, "power_down_index %d", index); pd = &ctrl->power_down_setting[index]; if (!pd) { CAM_ERR(CAM_SENSOR, @@ -1668,21 +1749,20 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, } ps = NULL; - CAM_DBG(CAM_SENSOR, "type %d", pd->seq_type); + CAM_DBG(CAM_SENSOR, "seq_type %d", pd->seq_type); switch (pd->seq_type) { case SENSOR_MCLK: - ret = cam_config_mclk_reg(ctrl, soc_info, index); - if (ret < 0) { - CAM_ERR(CAM_SENSOR, - "config clk reg failed rc: %d", ret); - return ret; - } - //cam_soc_util_clk_disable_default(soc_info); for (i = soc_info->num_clk - 1; i >= 0; i--) { cam_soc_util_clk_disable(soc_info->clk[i], soc_info->clk_name[i]); } + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + continue; + } break; case SENSOR_RESET: case SENSOR_STANDBY: @@ -1722,7 +1802,19 @@ int msm_camera_power_down(struct cam_sensor_power_ctrl_t *ctrl, soc_info->rgltr_max_volt[ps->seq_val], soc_info->rgltr_op_mode[ps->seq_val], soc_info->rgltr_delay[ps->seq_val]); - + if (ret) { + CAM_ERR(CAM_SENSOR, + "Reg: %s disable failed", + soc_info->rgltr_name[ + ps->seq_val]); + soc_info->rgltr[ps->seq_val] = + NULL; + msm_cam_sensor_handle_reg_gpio( + pd->seq_type, + gpio_num_info, + GPIOF_OUT_INIT_LOW); + continue; + } ps->data[0] = soc_info->rgltr[ps->seq_val]; 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 c9ccc5c0cd7cdfd50bd0cc34e8a4f4da68bcdf3b..6c0287e48487d033264d8082ac3cc113c1d59556 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 @@ -58,4 +58,7 @@ int msm_camera_fill_vreg_params(struct cam_hw_soc_info *soc_info, int32_t cam_sensor_update_power_settings(void *cmd_buf, int cmd_length, struct cam_sensor_power_ctrl_t *power_info); + +int cam_sensor_bob_pwm_mode_switch(struct cam_hw_soc_info *soc_info, + int bob_reg_idx, bool flag); #endif /* _CAM_SENSOR_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index 5cd30082fd554cc8477e594bb00ad4dfbeeb1460..52da37f8239bd0e055aace61f75e2224886ca271 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 @@ -3394,6 +3394,7 @@ static struct platform_driver cam_smmu_driver = { .name = "msm_cam_smmu", .owner = THIS_MODULE, .of_match_table = msm_cam_smmu_dt_match, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c index 517b7dfe8128d86ead03ef4e0ce052470d0bb33c..e5df874b52aed56b49f01ab02d3ded7ac4f57ffe 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync.c @@ -36,7 +36,8 @@ int cam_sync_create(int32_t *sync_obj, const char *name) } while (bit); spin_lock_bh(&sync_dev->row_spinlocks[idx]); - rc = cam_sync_init_object(sync_dev->sync_table, idx, name); + rc = cam_sync_init_row(sync_dev->sync_table, idx, name, + CAM_SYNC_TYPE_INDV); if (rc) { CAM_ERR(CAM_SYNC, "Error: Unable to init row at idx = %ld", idx); @@ -46,6 +47,7 @@ int cam_sync_create(int32_t *sync_obj, const char *name) } *sync_obj = idx; + CAM_DBG(CAM_SYNC, "sync_obj: %i", *sync_obj); spin_unlock_bh(&sync_dev->row_spinlocks[idx]); return rc; @@ -165,26 +167,30 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) struct list_head sync_list; struct cam_signalable_info *list_info = NULL; struct cam_signalable_info *temp_list_info = NULL; + struct list_head parents_list; /* Objects to be signaled will be added into this list */ INIT_LIST_HEAD(&sync_list); if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { - CAM_ERR(CAM_SYNC, "Error: Out of range sync obj"); + CAM_ERR(CAM_SYNC, "Error: Out of range sync obj (0 <= %d < %d)", + sync_obj, CAM_SYNC_MAX_OBJS); return -EINVAL; } row = sync_dev->sync_table + sync_obj; + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); CAM_ERR(CAM_SYNC, "Error: accessing an uninitialized sync obj = %d", sync_obj); return -EINVAL; } - spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); if (row->type == CAM_SYNC_TYPE_GROUP) { spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); - CAM_ERR(CAM_SYNC, "Error: Signaling a GROUP sync object = %d", + CAM_ERR(CAM_SYNC, + "Error: Signaling a GROUP sync object = %d", sync_obj); return -EINVAL; } @@ -216,20 +222,36 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) return rc; } + /* copy parent list to local and release child lock */ + INIT_LIST_HEAD(&parents_list); + list_splice_init(&row->parents_list, &parents_list); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + if (list_empty(&parents_list)) + goto dispatch_cb; + /* * Now iterate over all parents of this object and if they too need to * be signaled add them to the list */ list_for_each_entry(parent_info, - &row->parents_list, + &parents_list, list) { parent_row = sync_dev->sync_table + parent_info->sync_id; spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); parent_row->remaining--; - parent_row->state = cam_sync_util_get_state( - parent_row->state, + rc = cam_sync_util_update_parent_state( + parent_row, status); + if (rc) { + CAM_ERR(CAM_SYNC, "Invalid parent state %d", + parent_row->state); + spin_unlock_bh( + &sync_dev->row_spinlocks[parent_info->sync_id]); + kfree(parent_info); + continue; + } if (!parent_row->remaining) { rc = cam_sync_util_add_to_signalable_list @@ -240,15 +262,13 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status) spin_unlock_bh( &sync_dev->row_spinlocks[ parent_info->sync_id]); - spin_unlock_bh( - &sync_dev->row_spinlocks[sync_obj]); - return rc; + continue; } } spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); +dispatch_cb: /* * Now dispatch the various sync objects collected so far, in our @@ -333,10 +353,8 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) return -EINVAL; } - rc = cam_sync_util_validate_merge(sync_obj, - num_objs); - if (rc < 0) { - CAM_ERR(CAM_SYNC, "Validation failed, Merge not allowed"); + if (num_objs <= 1) { + CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); return -EINVAL; } @@ -348,7 +366,6 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) } while (bit); spin_lock_bh(&sync_dev->row_spinlocks[idx]); - rc = cam_sync_init_group_object(sync_dev->sync_table, idx, sync_obj, num_objs); @@ -368,6 +385,7 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) int cam_sync_destroy(int32_t sync_obj) { + CAM_DBG(CAM_SYNC, "sync_obj: %i", sync_obj); return cam_sync_deinit_object(sync_dev->sync_table, sync_obj); } @@ -1048,6 +1066,7 @@ static struct platform_driver cam_sync_driver = { .driver = { .name = "cam_sync", .owner = THIS_MODULE, + .suppress_bind_attrs = true, }, }; diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c index ed69829575bbf68636392b8d7fea2848b9e386d3..f391c8c8d51d2564222a7888ec8efeff127f1063 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.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 @@ -31,169 +31,123 @@ int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, return rc; } -int cam_sync_init_object(struct sync_table_row *table, - uint32_t idx, - const char *name) +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type) { struct sync_table_row *row = table + idx; if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) return -EINVAL; + memset(row, 0, sizeof(*row)); + if (name) strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN); INIT_LIST_HEAD(&row->parents_list); INIT_LIST_HEAD(&row->children_list); - row->type = CAM_SYNC_TYPE_INDV; + row->type = type; row->sync_id = idx; row->state = CAM_SYNC_STATE_ACTIVE; row->remaining = 0; init_completion(&row->signaled); INIT_LIST_HEAD(&row->callback_list); INIT_LIST_HEAD(&row->user_payload_list); - CAM_DBG(CAM_SYNC, "Sync object Initialised: sync_id:%u row_state:%u ", - row->sync_id, row->state); + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u ", + row->name, row->sync_id, idx, row->state); return 0; } -uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table, +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, uint32_t *sync_objs, uint32_t num_objs) { - int i; + int i, rc = 0; + struct sync_child_info *child_info; + struct sync_parent_info *parent_info; + struct sync_table_row *row = table + idx; struct sync_table_row *child_row = NULL; - int success_count = 0; - int active_count = 0; - if (!table || !sync_objs) - return CAM_SYNC_STATE_SIGNALED_ERROR; + cam_sync_init_row(table, idx, "merged_fence", CAM_SYNC_TYPE_GROUP); /* - * We need to arrive at the state of the merged object based on - * counts of error, active and success states of all children objects + * While traversing for children, parent's row list is updated with + * child info and each child's row is updated with parent info. + * If any child state is ERROR or SUCCESS, it will not be added to list. */ for (i = 0; i < num_objs; i++) { child_row = table + sync_objs[i]; - switch (child_row->state) { - case CAM_SYNC_STATE_SIGNALED_ERROR: - return CAM_SYNC_STATE_SIGNALED_ERROR; - case CAM_SYNC_STATE_SIGNALED_SUCCESS: - success_count++; - break; - case CAM_SYNC_STATE_ACTIVE: - active_count++; - break; - default: + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + + /* validate child */ + if ((child_row->type == CAM_SYNC_TYPE_GROUP) || + (child_row->state == CAM_SYNC_STATE_INVALID)) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); CAM_ERR(CAM_SYNC, - "Invalid state of child object during merge"); - return CAM_SYNC_STATE_SIGNALED_ERROR; + "Invalid child fence:%i state:%u type:%u", + child_row->sync_id, child_row->state, + child_row->type); + rc = -EINVAL; + goto clean_children_info; } - } - if (active_count) - return CAM_SYNC_STATE_ACTIVE; - - if (success_count == num_objs) - return CAM_SYNC_STATE_SIGNALED_SUCCESS; - - return CAM_SYNC_STATE_SIGNALED_ERROR; -} - -static int cam_sync_util_get_group_object_remaining_count( - struct sync_table_row *table, - uint32_t *sync_objs, - uint32_t num_objs) -{ - int i; - struct sync_table_row *child_row = NULL; - int remaining_count = 0; - - if (!table || !sync_objs) - return -EINVAL; - - for (i = 0; i < num_objs; i++) { - child_row = table + sync_objs[i]; - if (child_row->state == CAM_SYNC_STATE_ACTIVE) - remaining_count++; - } - - return remaining_count; -} - -int cam_sync_init_group_object(struct sync_table_row *table, - uint32_t idx, - uint32_t *sync_objs, - uint32_t num_objs) -{ - int i; - int remaining; - struct sync_child_info *child_info; - struct sync_parent_info *parent_info; - struct sync_table_row *row = table + idx; - struct sync_table_row *child_row = NULL; - - INIT_LIST_HEAD(&row->parents_list); + /* check for child's state */ + if (child_row->state == CAM_SYNC_STATE_SIGNALED_ERROR) { + row->state = CAM_SYNC_STATE_SIGNALED_ERROR; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } + if (child_row->state != CAM_SYNC_STATE_ACTIVE) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + continue; + } - INIT_LIST_HEAD(&row->children_list); + row->remaining++; - /* - * While traversing parents and children, we allocate in a loop and in - * case allocation fails, we call the clean up function which frees up - * all memory allocation thus far - */ - for (i = 0; i < num_objs; i++) { + /* Add child info */ child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC); - if (!child_info) { - cam_sync_util_cleanup_children_list(row, - SYNC_LIST_CLEAN_ALL, 0); - return -ENOMEM; + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + rc = -ENOMEM; + goto clean_children_info; } - child_info->sync_id = sync_objs[i]; list_add_tail(&child_info->list, &row->children_list); - } - for (i = 0; i < num_objs; i++) { - /* This gets us the row corresponding to the sync object */ - child_row = table + sync_objs[i]; - spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + /* Add parent info */ parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC); if (!parent_info) { - cam_sync_util_cleanup_parents_list(child_row, - SYNC_LIST_CLEAN_ALL, 0); - cam_sync_util_cleanup_children_list(row, - SYNC_LIST_CLEAN_ALL, 0); spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); - return -ENOMEM; + rc = -ENOMEM; + goto clean_children_info; } parent_info->sync_id = idx; list_add_tail(&parent_info->list, &child_row->parents_list); spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); } - row->type = CAM_SYNC_TYPE_GROUP; - row->sync_id = idx; - row->state = cam_sync_util_get_group_object_state(table, - sync_objs, num_objs); - remaining = cam_sync_util_get_group_object_remaining_count(table, - sync_objs, num_objs); - if (remaining < 0) { - CAM_ERR(CAM_SYNC, "Failed getting remaining count"); - return -ENODEV; + if (!row->remaining) { + if (row->state != CAM_SYNC_STATE_SIGNALED_ERROR) + row->state = CAM_SYNC_STATE_SIGNALED_SUCCESS; + complete_all(&row->signaled); } - row->remaining = remaining; - - init_completion(&row->signaled); - INIT_LIST_HEAD(&row->callback_list); - INIT_LIST_HEAD(&row->user_payload_list); + return 0; - if (row->state != CAM_SYNC_STATE_ACTIVE) - complete_all(&row->signaled); +clean_children_info: + row->state = CAM_SYNC_STATE_INVALID; + for (i = i-1; i >= 0; i--) { + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + child_row = table + sync_objs[i]; + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + } - return 0; + cam_sync_util_cleanup_children_list(row, SYNC_LIST_CLEAN_ALL, 0); + return rc; } int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) @@ -209,12 +163,16 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) return -EINVAL; + CAM_DBG(CAM_SYNC, + "row name:%s sync_id:%i [idx:%u] row_state:%u", + row->name, row->sync_id, idx, row->state); + spin_lock_bh(&sync_dev->row_spinlocks[idx]); if (row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); CAM_ERR(CAM_SYNC, "Error: accessing an uninitialized sync obj: idx = %d", idx); - spin_unlock_bh(&sync_dev->row_spinlocks[idx]); return -EINVAL; } row->state = CAM_SYNC_STATE_INVALID; @@ -252,9 +210,9 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) spin_lock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); if (child_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&child_info->list); spin_unlock_bh(&sync_dev->row_spinlocks[ child_info->sync_id]); - list_del_init(&child_info->list); kfree(child_info); continue; } @@ -262,9 +220,8 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) cam_sync_util_cleanup_parents_list(child_row, SYNC_LIST_CLEAN_ONE, idx); - spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); - list_del_init(&child_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); kfree(child_info); } @@ -277,9 +234,9 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) spin_lock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); if (parent_row->state == CAM_SYNC_STATE_INVALID) { + list_del_init(&parent_info->list); spin_unlock_bh(&sync_dev->row_spinlocks[ parent_info->sync_id]); - list_del_init(&parent_info->list); kfree(parent_info); continue; } @@ -287,9 +244,8 @@ int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx) cam_sync_util_cleanup_children_list(parent_row, SYNC_LIST_CLEAN_ONE, idx); - spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); - list_del_init(&parent_info->list); + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); kfree(parent_info); } @@ -356,32 +312,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, sync_obj); } -int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs) -{ - int i; - struct sync_table_row *row = NULL; - - if (num_objs <= 1) { - CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); - return -EINVAL; - } - - for (i = 0; i < num_objs; i++) { - row = sync_dev->sync_table + sync_obj[i]; - spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - if (row->type == CAM_SYNC_TYPE_GROUP || - row->state == CAM_SYNC_STATE_INVALID) { - CAM_ERR(CAM_SYNC, - "Group obj %d can't be merged or obj UNINIT", - sync_obj[i]); - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - return -EINVAL; - } - spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); - } - return 0; -} - int cam_sync_util_add_to_signalable_list(int32_t sync_obj, uint32_t status, struct list_head *sync_list) @@ -402,34 +332,27 @@ int cam_sync_util_add_to_signalable_list(int32_t sync_obj, return 0; } -int cam_sync_util_get_state(int current_state, +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state) { - int result = CAM_SYNC_STATE_SIGNALED_ERROR; - - if (new_state != CAM_SYNC_STATE_SIGNALED_SUCCESS && - new_state != CAM_SYNC_STATE_SIGNALED_ERROR) - return CAM_SYNC_STATE_SIGNALED_ERROR; - - switch (current_state) { - case CAM_SYNC_STATE_INVALID: - result = CAM_SYNC_STATE_SIGNALED_ERROR; - break; + int rc = 0; + switch (parent_row->state) { case CAM_SYNC_STATE_ACTIVE: case CAM_SYNC_STATE_SIGNALED_SUCCESS: - if (new_state == CAM_SYNC_STATE_SIGNALED_ERROR) - result = CAM_SYNC_STATE_SIGNALED_ERROR; - else if (new_state == CAM_SYNC_STATE_SIGNALED_SUCCESS) - result = CAM_SYNC_STATE_SIGNALED_SUCCESS; + parent_row->state = new_state; break; case CAM_SYNC_STATE_SIGNALED_ERROR: - result = CAM_SYNC_STATE_SIGNALED_ERROR; + break; + + case CAM_SYNC_STATE_INVALID: + default: + rc = -EINVAL; break; } - return result; + return rc; } void cam_sync_util_cleanup_children_list(struct sync_table_row *row, diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h index ae7d5421e6b77820a2558154509a6df37b6e69f9..a9d6f86c170913bd5bfbc866e1c5dfee3589fe4e 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.h @@ -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 @@ -41,12 +41,11 @@ int cam_sync_util_find_and_set_empty_row(struct sync_device *sync_dev, * @param idx : Index of row to initialize * @param name : Optional string representation of the sync object. Should be * 63 characters or less - * + * @param type : type of row to be initialized * @return Status of operation. Negative in case of error. Zero otherwise. */ -int cam_sync_init_object(struct sync_table_row *table, - uint32_t idx, - const char *name); +int cam_sync_init_row(struct sync_table_row *table, + uint32_t idx, const char *name, uint32_t type); /** * @brief: Function to uninitialize a row in the sync table @@ -103,16 +102,6 @@ void cam_sync_util_send_v4l2_event(uint32_t id, void *payload, int len); -/** - * @brief: Function to validate sync merge arguments - * - * @param sync_obj : Array of sync objects to merge - * @param num_objs : Number of sync objects in the array - * - * @return Status of operation. Negative in case of error. Zero otherwise. - */ -int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs); - /** * @brief: Function which adds sync object information to the signalable list * @@ -135,7 +124,7 @@ int cam_sync_util_add_to_signalable_list(int32_t sync_obj, * * @return Next state of the sync object */ -int cam_sync_util_get_state(int current_state, +int cam_sync_util_update_parent_state(struct sync_table_row *parent_row, int new_state); /** diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c index 26f2ba12be9fb887773a9459a11237a317e32a39..4f326342e3a73695a0718d3c8a3e26cca2975e33 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundataion. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundataion. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -30,7 +30,7 @@ const char *cam_get_module_name(unsigned int module_id) name = "CAM-CORE"; break; case CAM_CRM: - name = "CAM_CRM"; + name = "CAM-CRM"; break; case CAM_CPAS: name = "CAM-CPAS"; @@ -86,6 +86,18 @@ const char *cam_get_module_name(unsigned int module_id) case CAM_OIS: name = "CAM-OIS"; break; + case CAM_IRQ_CTRL: + name = "CAM-IRQ-CTRL"; + break; + case CAM_MEM: + name = "CAM-MEM"; + break; + case CAM_PERF: + name = "CAM-PERF"; + break; + case CAM_REQ: + name = "CAM-REQ"; + break; default: name = "CAM"; break; diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h index 4e97100bfb6ae9654c2787a097e5f89d1a612db5..1ed7056cd09f651bc1ba22fa92404fb1a98b6021 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_debug_util.h @@ -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 @@ -35,6 +35,16 @@ #define CAM_CTXT (1 << 19) #define CAM_OIS (1 << 20) #define CAM_RES (1 << 21) +#define CAM_MEM (1 << 22) + +/* CAM_IRQ_CTRL: For events in irq controller */ +#define CAM_IRQ_CTRL (1 << 23) + +/* CAM_REQ: Tracks a request submitted to KMD */ +#define CAM_REQ (1 << 24) + +/* CAM_PERF: Used for performance (clock, BW etc) logs */ +#define CAM_PERF (1 << 25) #define STR_BUFFER_MAX_LENGTH 1024 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 30ab0754c47fac231fc8ff225f72d8a760753db0..db2629d2a2f90d60ea2e8c41cc1f9ec88412dc76 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, 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 @@ -171,6 +171,24 @@ 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); + 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); + return -EINVAL; + } + dst_cpu_addr = (uint32_t *)((uint8_t *)dst_cpu_addr + patch_desc[i].dst_offset); temp += patch_desc[i].src_offset; diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c index d0a13abb3ba67fd42a7dc5b783477764581015d2..a5456a9bec724bbf62cd9d92fe5b5515f2fa5ddb 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c @@ -72,6 +72,197 @@ uint32_t cam_soc_util_get_hw_revision_node(struct cam_hw_soc_info *soc_info) } #endif +static char supported_clk_info[256]; +static char debugfs_dir_name[64]; + +/** + * cam_soc_util_get_string_from_level() + * + * @brief: Returns the string for a given clk level + * + * @level: Clock level + * + * @return: String corresponding to the clk level + */ +static const char *cam_soc_util_get_string_from_level( + enum cam_vote_level level) +{ + switch (level) { + case CAM_SUSPEND_VOTE: + return ""; + case CAM_MINSVS_VOTE: + return "MINSVS[1]"; + case CAM_LOWSVS_VOTE: + return "LOWSVS[2]"; + case CAM_SVS_VOTE: + return "SVS[3]"; + case CAM_SVSL1_VOTE: + return "SVSL1[4]"; + case CAM_NOMINAL_VOTE: + return "NOM[5]"; + case CAM_TURBO_VOTE: + return "TURBO[6]"; + default: + return ""; + } +} + +/** + * cam_soc_util_get_supported_clk_levels() + * + * @brief: Returns the string of all the supported clk levels for + * the given device + * + * @soc_info: Device soc information + * + * @return: String containing all supported clk levels + */ +static const char *cam_soc_util_get_supported_clk_levels( + struct cam_hw_soc_info *soc_info) +{ + int i = 0; + + memset(supported_clk_info, 0, sizeof(supported_clk_info)); + strlcat(supported_clk_info, "Supported levels: ", + sizeof(supported_clk_info)); + + for (i = 0; i < CAM_MAX_VOTE; i++) { + if (soc_info->clk_level_valid[i] == true) { + strlcat(supported_clk_info, + cam_soc_util_get_string_from_level(i), + sizeof(supported_clk_info)); + strlcat(supported_clk_info, " ", + sizeof(supported_clk_info)); + } + } + + strlcat(supported_clk_info, "\n", sizeof(supported_clk_info)); + return supported_clk_info; +} + +static int cam_soc_util_clk_lvl_options_open(struct inode *inode, + struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t cam_soc_util_clk_lvl_options_read(struct file *file, + char __user *clk_info, size_t size_t, loff_t *loff_t) +{ + struct cam_hw_soc_info *soc_info = + (struct cam_hw_soc_info *)file->private_data; + const char *display_string = + cam_soc_util_get_supported_clk_levels(soc_info); + + return simple_read_from_buffer(clk_info, size_t, loff_t, display_string, + strlen(display_string)); +} + +static const struct file_operations cam_soc_util_clk_lvl_options = { + .open = cam_soc_util_clk_lvl_options_open, + .read = cam_soc_util_clk_lvl_options_read, +}; + +static int cam_soc_util_set_clk_lvl(void *data, u64 val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + if (val <= CAM_SUSPEND_VOTE || val >= CAM_MAX_VOTE) + return 0; + + if (soc_info->clk_level_valid[val] == true) + soc_info->clk_level_override = val; + else + soc_info->clk_level_override = 0; + + return 0; +} + +static int cam_soc_util_get_clk_lvl(void *data, u64 *val) +{ + struct cam_hw_soc_info *soc_info = (struct cam_hw_soc_info *)data; + + *val = soc_info->clk_level_override; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_soc_util_clk_lvl_control, + cam_soc_util_get_clk_lvl, cam_soc_util_set_clk_lvl, "%08llu"); + +/** + * cam_soc_util_create_clk_lvl_debugfs() + * + * @brief: Creates debugfs files to view/control device clk rates + * + * @soc_info: Device soc information + * + * @return: Success or failure + */ +static int cam_soc_util_create_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + struct dentry *dentry = NULL; + + if (!soc_info) { + CAM_ERR(CAM_UTIL, "soc info is NULL"); + return -EINVAL; + } + + if (soc_info->dentry) + return 0; + + memset(debugfs_dir_name, 0, sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, "clk_dir_", sizeof(debugfs_dir_name)); + strlcat(debugfs_dir_name, soc_info->dev_name, sizeof(debugfs_dir_name)); + + dentry = soc_info->dentry; + dentry = debugfs_create_dir(debugfs_dir_name, NULL); + if (!dentry) { + CAM_ERR(CAM_UTIL, "failed to create debug directory"); + return -ENOMEM; + } + + if (!debugfs_create_file("clk_lvl_options", 0444, + dentry, soc_info, &cam_soc_util_clk_lvl_options)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_options"); + goto err; + } + + if (!debugfs_create_file("clk_lvl_control", 0644, + dentry, soc_info, &cam_soc_util_clk_lvl_control)) { + CAM_ERR(CAM_UTIL, "failed to create clk_lvl_control"); + goto err; + } + + CAM_DBG(CAM_UTIL, "clk lvl debugfs for %s successfully created", + soc_info->dev_name); + + return 0; + +err: + debugfs_remove_recursive(dentry); + dentry = NULL; + return -ENOMEM; +} + +/** + * cam_soc_util_remove_clk_lvl_debugfs() + * + * @brief: Removes the debugfs files used to view/control + * device clk rates + * + * @soc_info: Device soc information + * + */ +static void cam_soc_util_remove_clk_lvl_debugfs( + struct cam_hw_soc_info *soc_info) +{ + debugfs_remove_recursive(soc_info->dentry); + soc_info->dentry = NULL; +} + int cam_soc_util_get_level_from_string(const char *string, enum cam_vote_level *level) { @@ -206,7 +397,18 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, return clk_set_flags(soc_info->clk[clk_index], flags); } -int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, +/** + * cam_soc_util_set_clk_rate() + * + * @brief: Sets the given rate for the clk requested for + * + * @clk: Clock structure information for which rate is to be set + * @clk_name: Name of the clock for which rate is being set + * @clk_rate Clock rate to be set + * + * @return: Success or failure + */ +static int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, int32_t clk_rate) { int rc = 0; @@ -250,6 +452,26 @@ int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, return rc; } +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, + int32_t clk_rate) +{ + int32_t src_clk_idx; + struct clk *clk = NULL; + + if (!soc_info || (soc_info->src_clk_idx < 0)) + return -EINVAL; + + if (soc_info->clk_level_override && clk_rate) + clk_rate = soc_info->clk_level_override; + + src_clk_idx = soc_info->src_clk_idx; + clk = soc_info->clk[src_clk_idx]; + + return cam_soc_util_set_clk_rate(clk, + soc_info->clk_name[src_clk_idx], clk_rate); + +} + int cam_soc_util_clk_put(struct clk **clk) { if (!(*clk)) { @@ -456,6 +678,7 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) int i, j, rc; int32_t num_clk_level_strings; const char *src_clk_str = NULL; + const char *clk_control_debugfs = NULL; const char *clk_cntl_lvl_string = NULL; enum cam_vote_level level; @@ -569,8 +792,7 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) if (rc || !src_clk_str) { CAM_DBG(CAM_UTIL, "No src_clk_str found"); rc = 0; - /* Bottom loop is dependent on src_clk_str. So return here */ - return rc; + goto end; } for (i = 0; i < soc_info->num_clk; i++) { @@ -582,6 +804,18 @@ static int cam_soc_util_get_dt_clk_info(struct cam_hw_soc_info *soc_info) } } + rc = of_property_read_string_index(of_node, + "clock-control-debugfs", 0, &clk_control_debugfs); + if (rc || !clk_control_debugfs) { + CAM_DBG(CAM_UTIL, "No clock_control_debugfs property found"); + rc = 0; + goto end; + } + + if (strcmp("true", clk_control_debugfs) == 0) + soc_info->clk_control_enable = true; + +end: return rc; } @@ -1269,6 +1503,9 @@ int cam_soc_util_request_platform_resource( goto put_clk; } + if (soc_info->clk_control_enable) + cam_soc_util_create_clk_lvl_debugfs(soc_info); + return rc; put_clk: @@ -1353,6 +1590,9 @@ int cam_soc_util_release_platform_resource(struct cam_hw_soc_info *soc_info) /* release for gpio */ cam_soc_util_request_gpio_table(soc_info, false); + if (soc_info->clk_control_enable) + cam_soc_util_remove_clk_lvl_debugfs(soc_info); + return 0; } diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h index 18fad8da9630f0dc7dfb3b0588088c60ffee650a..4c6ed4b5197a71295d1bea6f37a9f8ec5caf81a7 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "cam_io_util.h" @@ -156,6 +157,9 @@ struct cam_soc_gpio_data { * @clk_level_valid: Indicates whether corresponding level is valid * @gpio_data: Pointer to gpio info * @pinctrl_info: Pointer to pinctrl info + * @dentry: Debugfs entry + * @clk_level_override: Clk level set from debugfs + * @clk_control: Enable/disable clk rate control through debugfs * @soc_private: Soc private data */ struct cam_hw_soc_info { @@ -197,6 +201,10 @@ struct cam_hw_soc_info { struct cam_soc_gpio_data *gpio_data; struct cam_soc_pinctrl_info pinctrl_info; + struct dentry *dentry; + uint32_t clk_level_override; + bool clk_control_enable; + void *soc_private; }; @@ -370,17 +378,16 @@ int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, uint32_t clk_index, unsigned long flags); /** - * cam_soc_util_set_clk_rate() + * cam_soc_util_set_src_clk_rate() * - * @brief: Set the rate on a given clock. + * @brief: Set the rate on the source clock. * - * @clk: Clock that needs to be set - * @clk_name: Clocks name associated with clk - * @clk_rate: Clocks rate associated with clk + * @soc_info: Device soc information + * @clk_rate: Clock rate associated with the src clk * * @return: success or failure */ -int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, +int cam_soc_util_set_src_clk_rate(struct cam_hw_soc_info *soc_info, int32_t clk_rate); /** diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h index 90ec5666941e062e2cffef5b0e7a28c31e48212f..c7dc0b6b2d00c5c0778b0722ed3f7e80a010f1d4 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_trace.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_trace.h @@ -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 @@ -72,17 +72,19 @@ TRACE_EVENT(cam_isp_activated_irq, ); TRACE_EVENT(cam_icp_fw_dbg, - TP_PROTO(char *dbg_message), - TP_ARGS(dbg_message), + TP_PROTO(char *dbg_message, uint64_t timestamp), + TP_ARGS(dbg_message, timestamp), TP_STRUCT__entry( __string(dbg_message, dbg_message) + __field(uint64_t, timestamp) ), TP_fast_assign( __assign_str(dbg_message, dbg_message); + __entry->timestamp = timestamp; ), TP_printk( - "%s: ", - __get_str(dbg_message) + "%llu %s: ", + __entry->timestamp, __get_str(dbg_message) ) ); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c index 21bac16e08433cc3a0341684a0065107d56c32ad..b5a6f44f20fa5f3ff52c4816de427aa5e53cb4e8 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util_32.c @@ -25,12 +25,16 @@ int msm_isp_axi_create_stream( struct msm_vfe_axi_shared_data *axi_data, struct msm_vfe32_axi_stream_request_cmd *stream_cfg_cmd) { - uint32_t i = stream_cfg_cmd->stream_src; + int i, rc = -1; - if (i >= VFE_AXI_SRC_MAX) { - pr_err("%s:%d invalid stream_src %d\n", __func__, __LINE__, - stream_cfg_cmd->stream_src); - return -EINVAL; + for (i = 0; i < MAX_NUM_STREAM; i++) { + if (axi_data->stream_info[i].state == AVAILABLE) + break; + } + + if (i == MAX_NUM_STREAM) { + pr_err("%s: No free stream\n", __func__); + return rc; } if ((axi_data->stream_handle_cnt << 8) == 0) diff --git a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c index 7d37d7ed14dd0e6171056a7e2676bfc51a325cd4..0811efbcb130bc1f920ffb822d70eb78796cab47 100644 --- a/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_v2/jpeg_10/msm_jpeg_dev.c @@ -32,6 +32,8 @@ #define MSM_JPEG_NAME "jpeg" #define DEV_NAME_LEN 10 +static char devname[DEV_NAME_LEN]; + static int msm_jpeg_open(struct inode *inode, struct file *filp) { int rc = 0; @@ -159,7 +161,6 @@ static int msm_jpeg_init_dev(struct platform_device *pdev) struct msm_jpeg_device *msm_jpeg_device_p; const struct of_device_id *device_id; const struct msm_jpeg_priv_data *priv_data; - char devname[DEV_NAME_LEN]; msm_jpeg_device_p = kzalloc(sizeof(struct msm_jpeg_device), GFP_ATOMIC); if (!msm_jpeg_device_p) { diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 1ad2f2578445399505e659da838836b675706201..85ca27540c3e980a8f2b4588dbc6f92922999974 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -949,9 +949,14 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) if (irq_status & 0x8) { tx_level = msm_camera_io_r(cpp_dev->base + MSM_CPP_MICRO_FIFO_TX_STAT) >> 2; - for (i = 0; i < tx_level; i++) { - tx_fifo[i] = msm_camera_io_r(cpp_dev->base + - MSM_CPP_MICRO_FIFO_TX_DATA); + if (tx_level < MSM_CPP_TX_FIFO_LEVEL) { + for (i = 0; i < tx_level; i++) { + tx_fifo[i] = msm_camera_io_r(cpp_dev->base + + MSM_CPP_MICRO_FIFO_TX_DATA); + } + } else { + pr_err("Fatal invalid tx level %d", tx_level); + goto err; } spin_lock_irqsave(&cpp_dev->tasklet_lock, flags); queue_cmd = &cpp_dev->tasklet_queue_cmd[cpp_dev->taskletq_idx]; @@ -1006,6 +1011,7 @@ static irqreturn_t msm_cpp_irq(int irq_num, void *data) pr_debug("DEBUG_R1: 0x%x\n", msm_camera_io_r(cpp_dev->base + 0x8C)); } +err: msm_camera_io_w(irq_status, cpp_dev->base + MSM_CPP_MICRO_IRQGEN_CLR); return IRQ_HANDLED; } diff --git a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c index cd162362e418416f291b1ccb6211d4b7c05fabe1..f4305ea53c30a2385b4e7815edaeb5bafe400e4c 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c +++ b/drivers/media/platform/msm/camera_v2/sensor/eeprom/msm_eeprom.c @@ -788,11 +788,101 @@ static struct v4l2_subdev_ops msm_eeprom_subdev_ops = { .core = &msm_eeprom_subdev_core_ops, }; +static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) +{ + int rc = 0, i = 0; + struct msm_eeprom_board_info *eb_info; + struct msm_camera_power_ctrl_t *power_info = + &e_ctrl->eboard_info->power_info; + struct device_node *of_node = NULL; + struct msm_camera_gpio_conf *gconf = NULL; + int8_t gpio_array_size = 0; + uint16_t *gpio_array = NULL; + + eb_info = e_ctrl->eboard_info; + if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) + of_node = e_ctrl->i2c_client. + spi_client->spi_master->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) + of_node = e_ctrl->pdev->dev.of_node; + else if (e_ctrl->eeprom_device_type == MSM_CAMERA_I2C_DEVICE) + of_node = e_ctrl->i2c_client.client->dev.of_node; + + if (!of_node) { + pr_err("%s: %d of_node is NULL\n", __func__, __LINE__); + return -ENOMEM; + } + rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, + &power_info->num_vreg); + if (rc < 0) + return rc; + + if (e_ctrl->userspace_probe == 0) { + rc = msm_camera_get_dt_power_setting_data(of_node, + power_info->cam_vreg, power_info->num_vreg, + power_info); + if (rc < 0) + goto ERROR1; + } + + power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), + GFP_KERNEL); + if (!power_info->gpio_conf) { + rc = -ENOMEM; + goto ERROR2; + } + gconf = power_info->gpio_conf; + gpio_array_size = of_gpio_count(of_node); + CDBG("%s gpio count %d\n", __func__, gpio_array_size); + + if (gpio_array_size > 0) { + gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), + GFP_KERNEL); + if (!gpio_array) + goto ERROR3; + for (i = 0; i < gpio_array_size; i++) { + gpio_array[i] = of_get_gpio(of_node, i); + CDBG("%s gpio_array[%d] = %d\n", __func__, i, + gpio_array[i]); + } + + rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + + rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, + gpio_array, gpio_array_size); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + goto ERROR4; + } + kfree(gpio_array); + } + + return rc; +ERROR4: + kfree(gpio_array); +ERROR3: + kfree(power_info->gpio_conf); +ERROR2: + kfree(power_info->cam_vreg); +ERROR1: + kfree(power_info->power_setting); + return rc; +} + static int msm_eeprom_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; + uint32_t temp = 0; struct msm_eeprom_ctrl_t *e_ctrl = NULL; + struct msm_eeprom_board_info *eb_info = NULL; + struct device_node *of_node = client->dev.of_node; + struct msm_camera_power_ctrl_t *power_info = NULL; CDBG("%s E\n", __func__); @@ -804,41 +894,122 @@ static int msm_eeprom_i2c_probe(struct i2c_client *client, e_ctrl = kzalloc(sizeof(*e_ctrl), GFP_KERNEL); if (!e_ctrl) return -ENOMEM; + e_ctrl->eeprom_v4l2_subdev_ops = &msm_eeprom_subdev_ops; e_ctrl->eeprom_mutex = &msm_eeprom_mutex; - CDBG("%s client = 0x%pK\n", __func__, client); - e_ctrl->eboard_info = (struct msm_eeprom_board_info *)(id->driver_data); - if (!e_ctrl->eboard_info) { - pr_err("%s:%d board info NULL\n", __func__, __LINE__); - rc = -EINVAL; - goto ectrl_free; - } - e_ctrl->i2c_client.client = client; + e_ctrl->cal_data.mapdata = NULL; e_ctrl->cal_data.map = NULL; e_ctrl->userspace_probe = 0; - e_ctrl->is_supported = 1; - + e_ctrl->is_supported = 0; + if (!of_node) { + pr_err("%s dev.of_node NULL\n", __func__); + rc = -EINVAL; + goto ectrl_free; + } /* Set device type as I2C */ e_ctrl->eeprom_device_type = MSM_CAMERA_I2C_DEVICE; e_ctrl->i2c_client.i2c_func_tbl = &msm_eeprom_qup_func_tbl; - if (e_ctrl->eboard_info->i2c_slaveaddr != 0) - e_ctrl->i2c_client.client->addr = - e_ctrl->eboard_info->i2c_slaveaddr; + e_ctrl->eboard_info = kzalloc(sizeof( + struct msm_eeprom_board_info), GFP_KERNEL); + if (!e_ctrl->eboard_info) { + rc = -ENOMEM; + goto ectrl_free; + } + eb_info = e_ctrl->eboard_info; + power_info = &eb_info->power_info; + e_ctrl->i2c_client.client = client; + power_info->dev = &client->dev; /*Get clocks information*/ rc = msm_camera_i2c_dev_get_clk_info( &e_ctrl->i2c_client.client->dev, - &e_ctrl->eboard_info->power_info.clk_info, - &e_ctrl->eboard_info->power_info.clk_ptr, - &e_ctrl->eboard_info->power_info.clk_info_size); + &power_info->clk_info, + &power_info->clk_ptr, + &power_info->clk_info_size); if (rc < 0) { pr_err("failed: msm_camera_get_clk_info rc %d", rc); - goto ectrl_free; + goto board_free; + } + + rc = of_property_read_u32(of_node, "cell-index", + &e_ctrl->subdev_id); + CDBG("cell-index %d, rc %d\n", e_ctrl->subdev_id, rc); + if (rc < 0) { + pr_err("failed rc %d\n", rc); + goto board_free; } - /*IMPLEMENT READING PART*/ + rc = of_property_read_string(of_node, "qcom,eeprom-name", + &eb_info->eeprom_name); + CDBG("%s qcom,eeprom-name %s, rc %d\n", __func__, + eb_info->eeprom_name, rc); + if (rc < 0) { + pr_err("%s failed %d\n", __func__, __LINE__); + e_ctrl->userspace_probe = 1; + } + + rc = msm_eeprom_get_dt_data(e_ctrl); + if (rc < 0) + goto board_free; + + if (e_ctrl->userspace_probe == 0) { + rc = of_property_read_u32(of_node, "qcom,slave-addr", + &temp); + if (rc < 0) { + pr_err("%s failed rc %d\n", __func__, rc); + goto board_free; + } + + rc = of_property_read_u32(of_node, "qcom,i2c-freq-mode", + &e_ctrl->i2c_freq_mode); + CDBG("qcom,i2c_freq_mode %d, rc %d\n", + e_ctrl->i2c_freq_mode, rc); + if (rc < 0) { + pr_err("%s qcom,i2c-freq-mode read fail. Setting to 0 %d\n", + __func__, rc); + e_ctrl->i2c_freq_mode = 0; + } + if (e_ctrl->i2c_freq_mode >= I2C_MAX_MODES) { + pr_err("%s:%d invalid i2c_freq_mode = %d\n", + __func__, __LINE__, e_ctrl->i2c_freq_mode); + e_ctrl->i2c_freq_mode = 0; + } + eb_info->i2c_slaveaddr = temp; + CDBG("qcom,slave-addr = 0x%X\n", eb_info->i2c_slaveaddr); + eb_info->i2c_freq_mode = e_ctrl->i2c_freq_mode; + + rc = msm_eeprom_parse_memory_map(of_node, &e_ctrl->cal_data); + if (rc < 0) + goto board_free; + + rc = msm_camera_power_up(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + + rc = read_eeprom_memory(e_ctrl, &e_ctrl->cal_data); + if (rc < 0) { + pr_err("%s read_eeprom_memory failed\n", __func__); + goto power_down; + } + CDBG("%s cal_data: %*ph\n", __func__, + e_ctrl->cal_data.num_data, e_ctrl->cal_data.mapdata); + + e_ctrl->is_supported |= msm_eeprom_match_crc(&e_ctrl->cal_data); + + rc = msm_camera_power_down(power_info, + e_ctrl->eeprom_device_type, &e_ctrl->i2c_client); + if (rc) { + pr_err("failed rc %d\n", rc); + goto memdata_free; + } + } else + e_ctrl->is_supported = 1; + /* Initialize sub device */ v4l2_i2c_subdev_init(&e_ctrl->msm_sd.sd, e_ctrl->i2c_client.client, @@ -846,12 +1017,23 @@ static int msm_eeprom_i2c_probe(struct i2c_client *client, v4l2_set_subdevdata(&e_ctrl->msm_sd.sd, e_ctrl); e_ctrl->msm_sd.sd.internal_ops = &msm_eeprom_internal_ops; e_ctrl->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(e_ctrl->msm_sd.sd.name, + ARRAY_SIZE(e_ctrl->msm_sd.sd.name), "msm_eeprom"); media_entity_pads_init(&e_ctrl->msm_sd.sd.entity, 0, NULL); e_ctrl->msm_sd.sd.entity.function = MSM_CAMERA_SUBDEV_EEPROM; msm_sd_register(&e_ctrl->msm_sd); - CDBG("%s success result=%d X\n", __func__, rc); + e_ctrl->is_supported = (e_ctrl->is_supported << 1) | 1; + pr_err("%s success result=%d X\n", __func__, rc); return rc; +power_down: + msm_camera_power_down(power_info, e_ctrl->eeprom_device_type, + &e_ctrl->i2c_client); +memdata_free: + kfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); +board_free: + kfree(e_ctrl->eboard_info); ectrl_free: kfree(e_ctrl); probe_failure: @@ -961,91 +1143,6 @@ static int msm_eeprom_match_id(struct msm_eeprom_ctrl_t *e_ctrl) return 0; } -static int msm_eeprom_get_dt_data(struct msm_eeprom_ctrl_t *e_ctrl) -{ - int rc = 0, i = 0; - struct msm_eeprom_board_info *eb_info; - struct msm_camera_power_ctrl_t *power_info = - &e_ctrl->eboard_info->power_info; - struct device_node *of_node = NULL; - struct msm_camera_gpio_conf *gconf = NULL; - int8_t gpio_array_size = 0; - uint16_t *gpio_array = NULL; - - eb_info = e_ctrl->eboard_info; - if (e_ctrl->eeprom_device_type == MSM_CAMERA_SPI_DEVICE) - of_node = e_ctrl->i2c_client. - spi_client->spi_master->dev.of_node; - else if (e_ctrl->eeprom_device_type == MSM_CAMERA_PLATFORM_DEVICE) - of_node = e_ctrl->pdev->dev.of_node; - - if (!of_node) { - pr_err("%s: %d of_node is NULL\n", __func__, __LINE__); - return -ENOMEM; - } - rc = msm_camera_get_dt_vreg_data(of_node, &power_info->cam_vreg, - &power_info->num_vreg); - if (rc < 0) - return rc; - - if (e_ctrl->userspace_probe == 0) { - rc = msm_camera_get_dt_power_setting_data(of_node, - power_info->cam_vreg, power_info->num_vreg, - power_info); - if (rc < 0) - goto ERROR1; - } - - power_info->gpio_conf = kzalloc(sizeof(struct msm_camera_gpio_conf), - GFP_KERNEL); - if (!power_info->gpio_conf) { - rc = -ENOMEM; - goto ERROR2; - } - gconf = power_info->gpio_conf; - gpio_array_size = of_gpio_count(of_node); - CDBG("%s gpio count %d\n", __func__, gpio_array_size); - - if (gpio_array_size > 0) { - gpio_array = kcalloc(gpio_array_size, sizeof(uint16_t), - GFP_KERNEL); - if (!gpio_array) - goto ERROR3; - for (i = 0; i < gpio_array_size; i++) { - gpio_array[i] = of_get_gpio(of_node, i); - CDBG("%s gpio_array[%d] = %d\n", __func__, i, - gpio_array[i]); - } - - rc = msm_camera_get_dt_gpio_req_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - - rc = msm_camera_init_gpio_pin_tbl(of_node, gconf, - gpio_array, gpio_array_size); - if (rc < 0) { - pr_err("%s failed %d\n", __func__, __LINE__); - goto ERROR4; - } - kfree(gpio_array); - } - - return rc; -ERROR4: - kfree(gpio_array); -ERROR3: - kfree(power_info->gpio_conf); -ERROR2: - kfree(power_info->cam_vreg); -ERROR1: - kfree(power_info->power_setting); - return rc; -} - - static int msm_eeprom_cmm_dts(struct msm_eeprom_board_info *eb_info, struct device_node *of_node) { diff --git a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c index 78321812dd993bdab827eee0c84db36cb8bfbaa9..4bc13d03d36d0cffbcc3794144841d0a3ab3a388 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c +++ b/drivers/media/platform/msm/camera_v2/sensor/msm_sensor_driver.c @@ -513,7 +513,7 @@ static int32_t msm_sensor_create_pd_settings(void *setting, int c, end; struct msm_sensor_power_setting pd_tmp; - pr_err("Generating power_down_setting"); + pr_err("Generating power_down_setting\n"); #ifdef CONFIG_COMPAT if (is_compat_task()) { @@ -603,7 +603,7 @@ static int32_t msm_sensor_get_power_down_settings(void *setting, /* Print power setting */ for (i = 0; i < size_down; i++) { - CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d", + CDBG("DOWN seq_type %d seq_val %d config_val %ld delay %d\n", pd[i].seq_type, pd[i].seq_val, pd[i].config_val, pd[i].delay); } @@ -657,7 +657,7 @@ static int32_t msm_sensor_get_power_up_settings(void *setting, /* Print power setting */ for (i = 0; i < size; i++) { - CDBG("UP seq_type %d seq_val %d config_val %ld delay %d", + CDBG("UP seq_type %d seq_val %d config_val %ld delay %d\n", pu[i].seq_type, pu[i].seq_val, pu[i].config_val, pu[i].delay); } diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index ce50dcda961d7cd216dfb876a3dff1f4b08a5668..ca3b010c95c61a0a5d68e14dba7c22c32bfacead 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -303,7 +303,7 @@ static int sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on) int ret = 0; if (mgr->regulator_enable == on) { - SDEROT_ERR("Regulators already in selected mode on=%d\n", on); + SDEROT_DBG("Regulators already in selected mode on=%d\n", on); return 0; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index a665978157aa7851b43ca3175b68b2b105438cd0..c15a2e9d12fccc4ecf69921297f7cc359138ba04 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -643,8 +643,8 @@ static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, vsp_factor_num = vsp_factor_num * 13 / 10; vsp_factor_den *= 2; } - vsp_cycles += ((u64)inst->clk_data.bitrate * vsp_factor_num) / - vsp_factor_den; + vsp_cycles += div_u64((u64)inst->clk_data.bitrate * + vsp_factor_num, vsp_factor_den); } else if (inst->session_type == MSM_VIDC_DECODER) { vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index d77ea216148182d94e2a9809d3ecf76e48fad441..b8789711d3eb34d85d2d42bdbe1576801130230a 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -6724,6 +6724,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, struct msm_vidc_buffer *temp; bool found = false; int i = 0; + u32 planes[VIDEO_MAX_PLANES] = {0}; mutex_lock(&inst->flush_lock); mutex_lock(&inst->registeredbufs.lock); @@ -6737,6 +6738,10 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, } } if (found) { + /* save device_addr */ + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) + planes[i] = mbuf->smem[i].device_addr; + /* send RBR event to client */ msm_vidc_queue_rbr_event(inst, mbuf->vvb.vb2_buf.planes[0].m.fd, @@ -6755,6 +6760,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, if (!mbuf->smem[0].refcount) { list_del(&mbuf->list); kref_put_mbuf(mbuf); + mbuf = NULL; } } else { print_vidc_buffer(VIDC_ERR, "mbuf not found", inst, mbuf); @@ -6772,8 +6778,8 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, */ found = false; list_for_each_entry(temp, &inst->registeredbufs.list, list) { - if (msm_comm_compare_vb2_plane(inst, mbuf, - &temp->vvb.vb2_buf, 0)) { + if (msm_comm_compare_device_plane(temp, planes, 0)) { + mbuf = temp; found = true; break; } @@ -6793,9 +6799,11 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, /* don't queue the buffer */ found = false; } - /* clear DEFERRED flag, if any, as the buffer is going to be queued */ - if (found) + /* clear required flags as the buffer is going to be queued */ + if (found) { mbuf->flags &= ~MSM_VIDC_FLAG_DEFERRED; + mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING; + } unlock: mutex_unlock(&inst->registeredbufs.lock); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 921cf1edb3b1bc64ebfa4634be93bbeb19a6387a..69156affd0aef0ca07a30636fedb95f3f87f6060 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -864,6 +864,9 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_CNXT_RDE_250}, {USB_DEVICE(0x0572, 0x58A0), .driver_info = CX231XX_BOARD_CNXT_RDU_250}, + /* AverMedia DVD EZMaker 7 */ + {USB_DEVICE(0x07ca, 0xc039), + .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER}, {USB_DEVICE(0x2040, 0xb110), .driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL}, {USB_DEVICE(0x2040, 0xb111), diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index d4e93f1501f1ebf8ab79421d111b70722ab17136..8618eba6474e8027e42d209192f960d20f477ad3 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -870,7 +870,7 @@ static int put_v4l2_ext_controls32(struct file *file, get_user(kcontrols, &kp->controls)) return -EFAULT; - if (!count) + if (!count || count > (U32_MAX/sizeof(*ucontrols))) return 0; if (get_user(p, &up->controls)) return -EFAULT; diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c index 70c646b0097d8c70ded6c4f62a92711aa89bfd22..19ac8bc8e7ea3caa71a81db528ebb5fd93e7cd6b 100644 --- a/drivers/mfd/intel-lpss.c +++ b/drivers/mfd/intel-lpss.c @@ -275,11 +275,11 @@ static void intel_lpss_init_dev(const struct intel_lpss *lpss) intel_lpss_deassert_reset(lpss); + intel_lpss_set_remap_addr(lpss); + if (!intel_lpss_has_idma(lpss)) return; - intel_lpss_set_remap_addr(lpss); - /* Make sure that SPI multiblock DMA transfers are re-enabled */ if (lpss->type == LPSS_DEV_SPI) writel(value, lpss->priv + LPSS_PRIV_SSP_REG); diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index bf87ed2f4918934bc92ad45b85f068dea8a1e8f9..d0b5a0e67304c78300766ff3c7c3ad927605981d 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -189,6 +189,7 @@ struct qseecom_registered_listener_list { wait_queue_head_t listener_block_app_wq; struct sglist_info sglistinfo_ptr[MAX_ION_FD]; uint32_t sglist_cnt; + int abort; }; struct qseecom_registered_app_list { @@ -198,6 +199,7 @@ struct qseecom_registered_app_list { char app_name[MAX_APP_NAME_SIZE]; u32 app_arch; bool app_blocked; + u32 check_block; u32 blocked_on_listener_id; }; @@ -1223,6 +1225,23 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, return ret; } +static void __qseecom_listener_abort_all(int abort) +{ + struct qseecom_registered_listener_list *entry = NULL; + unsigned long flags; + + spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags); + list_for_each_entry(entry, + &qseecom.registered_listener_list_head, list) { + pr_debug("set abort %d for listener %d\n", + abort, entry->svc.listener_id); + entry->abort = abort; + } + if (abort) + wake_up_interruptible_all(&qseecom.send_resp_wq); + spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags); +} + static int qseecom_unregister_listener(struct qseecom_dev_handle *data) { int ret = 0; @@ -1256,6 +1275,7 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data) list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == data->listener.id) { + ptr_svc->abort = 1; wake_up_all(&ptr_svc->rcv_req_wq); break; } @@ -1602,12 +1622,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data, return 0; } -static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data) +static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data, + struct qseecom_registered_listener_list *ptr_svc) { int ret; ret = (qseecom.send_resp_flag != 0); - return ret || data->abort; + return ret || data->abort || ptr_svc->abort; } static int __qseecom_reentrancy_listener_has_sent_rsp( @@ -1617,56 +1638,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp( int ret; ret = (ptr_svc->send_resp_flag != 0); - return ret || data->abort; -} - -static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data, - struct qseecom_command_scm_resp *resp, - struct qseecom_client_listener_data_irsp *send_data_rsp, - struct qseecom_registered_listener_list *ptr_svc, - uint32_t lstnr) { - int ret = 0; - - send_data_rsp->status = QSEOS_RESULT_FAILURE; - qseecom.send_resp_flag = 0; - send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND; - send_data_rsp->listener_id = lstnr; - if (ptr_svc) - pr_warn("listener_id:%x, lstnr: %x\n", - ptr_svc->svc.listener_id, lstnr); - 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, - ION_IOC_CLEAN_INV_CACHES); - if (ret) { - pr_err("cache operation failed %d\n", ret); - return ret; - } - } - - if (lstnr == RPMB_SERVICE) { - ret = __qseecom_enable_clk(CLK_QSEE); - if (ret) - return ret; - } - ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp, - sizeof(send_data_rsp), resp, sizeof(*resp)); - if (ret) { - pr_err("scm_call() failed with err: %d (app_id = %d)\n", - ret, data->client.app_id); - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; - } - if ((resp->result != QSEOS_RESULT_SUCCESS) && - (resp->result != QSEOS_RESULT_INCOMPLETE)) { - pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", - resp->result, data->client.app_id, lstnr); - ret = -EINVAL; - } - if (lstnr == RPMB_SERVICE) - __qseecom_disable_clk(CLK_QSEE); - return ret; + return ret || data->abort || ptr_svc->abort; } static void __qseecom_clean_listener_sglistinfo( @@ -1717,23 +1689,33 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, ptr_svc, lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - __qseecom_qseos_fail_return_resp_tz(data, resp, - &send_data_rsp, NULL, lstnr); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + + if (ptr_svc->abort == 1) { + pr_err("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); @@ -1750,7 +1732,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, */ if (!qseecom.qsee_reentrancy_support && !wait_event_freezable(qseecom.send_resp_wq, - __qseecom_listener_has_sent_rsp(data))) { + __qseecom_listener_has_sent_rsp( + data, ptr_svc))) { break; } @@ -1764,7 +1747,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -1772,7 +1755,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, } else { status = QSEOS_RESULT_SUCCESS; } - +err_resp: qseecom.send_resp_flag = 0; ptr_svc->send_resp_flag = 0; table = ptr_svc->sglistinfo_ptr; @@ -1832,6 +1815,8 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, __qseecom_disable_clk(CLK_QSEE); return ret; } + pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n", + status, resp->result, data->client.app_id, lstnr); if ((resp->result != QSEOS_RESULT_SUCCESS) && (resp->result != QSEOS_RESULT_INCOMPLETE)) { pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n", @@ -1985,7 +1970,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( size_t cmd_len; struct sglist_info *table = NULL; - while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { + while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; /* * Wake up blocking lsitener service with the lstnr id @@ -2006,17 +1991,33 @@ static int __qseecom_reentrancy_process_incomplete_cmd( if (ptr_svc == NULL) { pr_err("Listener Svc %d does not exist\n", lstnr); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (!ptr_svc->ihandle) { pr_err("Client handle is not initialized\n"); - return -EINVAL; + rc = -EINVAL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } if (ptr_svc->svc.listener_id != lstnr) { - pr_warn("Service requested does not exist\n"); - return -ERESTARTSYS; + pr_err("Service %d does not exist\n", + lstnr); + rc = -ERESTARTSYS; + ptr_svc = NULL; + status = QSEOS_RESULT_FAILURE; + goto err_resp; + } + + if (ptr_svc->abort == 1) { + pr_err("Service %d abort %d\n", + lstnr, ptr_svc->abort); + rc = -ENODEV; + status = QSEOS_RESULT_FAILURE; + goto err_resp; } pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n"); @@ -2042,7 +2043,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( /* restore signal mask */ sigprocmask(SIG_SETMASK, &old_sigset, NULL); - if (data->abort) { + if (data->abort || ptr_svc->abort) { pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; @@ -2050,6 +2051,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd( } else { status = QSEOS_RESULT_SUCCESS; } +err_resp: table = ptr_svc->sglistinfo_ptr; if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_rsp.listener_id = lstnr; @@ -2184,6 +2186,7 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( sigset_t new_sigset, old_sigset; if (qseecom.qsee_reentrancy_support) { + ptr_app->check_block++; while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) { /* thread sleep until this app unblocked */ sigfillset(&new_sigset); @@ -2198,6 +2201,7 @@ static void __qseecom_reentrancy_check_if_this_app_blocked( mutex_lock(&app_access_lock); sigprocmask(SIG_SETMASK, &old_sigset, NULL); } + ptr_app->check_block--; } } @@ -2466,6 +2470,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) @@ -2576,7 +2581,8 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, if (!strcmp((void *)ptr_app->app_name, (void *)data->client.app_name)) { found_app = true; - if (ptr_app->app_blocked) + if (ptr_app->app_blocked || + ptr_app->check_block) app_crash = false; if (app_crash || ptr_app->ref_cnt == 1) unload = true; @@ -3813,7 +3819,7 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data, int ret; ret = (svc->rcv_req_flag != 0); - return ret || data->abort; + return ret || data->abort || svc->abort; } static int qseecom_receive_req(struct qseecom_dev_handle *data) @@ -3837,9 +3843,9 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data) return -ERESTARTSYS; } - if (data->abort) { + if (data->abort || this_lstnr->abort) { pr_err("Aborting Listener Service = %d\n", - (uint32_t)data->listener.id); + (uint32_t)data->listener.id); return -ENODEV; } this_lstnr->rcv_req_flag = 0; @@ -4527,6 +4533,7 @@ int qseecom_start_app(struct qseecom_handle **handle, entry->app_arch = app_arch; entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, &qseecom.registered_app_list_head); spin_unlock_irqrestore(&qseecom.registered_app_list_lock, @@ -5441,6 +5448,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data, MAX_APP_NAME_SIZE); entry->app_blocked = false; entry->blocked_on_listener_id = 0; + entry->check_block = 0; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); list_add_tail(&entry->list, @@ -6154,7 +6162,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data, } static int qseecom_is_es_activated(void __user *argp) { - struct qseecom_is_es_activated_req req; + struct qseecom_is_es_activated_req req = {0}; struct qseecom_command_scm_resp resp; int ret; @@ -6999,12 +7007,14 @@ static inline long qseecom_ioctl(struct file *file, break; } pr_debug("ioctl unregister_listener_req()\n"); + __qseecom_listener_abort_all(1); mutex_lock(&app_access_lock); atomic_inc(&data->ioctl_count); ret = qseecom_unregister_listener(data); atomic_dec(&data->ioctl_count); wake_up_all(&data->abort_wq); mutex_unlock(&app_access_lock); + __qseecom_listener_abort_all(0); if (ret) pr_err("failed qseecom_unregister_listener: %d\n", ret); break; @@ -7671,9 +7681,11 @@ static int qseecom_release(struct inode *inode, struct file *file) data->type, data->mode, data); switch (data->type) { case QSEECOM_LISTENER_SERVICE: + __qseecom_listener_abort_all(1); mutex_lock(&app_access_lock); ret = qseecom_unregister_listener(data); mutex_unlock(&app_access_lock); + __qseecom_listener_abort_all(0); break; case QSEECOM_CLIENT_APP: mutex_lock(&app_access_lock); diff --git a/drivers/misc/vmw_balloon.c b/drivers/misc/vmw_balloon.c index 1e688bfec56728c3d00ebc353031c26fde29f187..fe90b7e044279c610ce58d413895d0b251626efa 100644 --- a/drivers/misc/vmw_balloon.c +++ b/drivers/misc/vmw_balloon.c @@ -576,15 +576,9 @@ static void vmballoon_pop(struct vmballoon *b) } } - if (b->batch_page) { - vunmap(b->batch_page); - b->batch_page = NULL; - } - - if (b->page) { - __free_page(b->page); - b->page = NULL; - } + /* Clearing the batch_page unconditionally has no adverse effect */ + free_page((unsigned long)b->batch_page); + b->batch_page = NULL; } /* @@ -991,16 +985,13 @@ static const struct vmballoon_ops vmballoon_batched_ops = { static bool vmballoon_init_batching(struct vmballoon *b) { - b->page = alloc_page(VMW_PAGE_ALLOC_NOSLEEP); - if (!b->page) - return false; + struct page *page; - b->batch_page = vmap(&b->page, 1, VM_MAP, PAGE_KERNEL); - if (!b->batch_page) { - __free_page(b->page); + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) return false; - } + b->batch_page = page_address(page); return true; } diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f78b659fbd4fcd7e0f16515ad195421874fede4a..a1488fe62e98cf7fb375de06b4fa608fe7970269 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -3994,6 +3994,7 @@ static inline int mmc_blk_cmdq_part_switch(struct mmc_card *card, pr_err("%s: %s: mmc_blk_cmdq_switch failed: %d\n", mmc_hostname(host), __func__, err); ret = err; + goto out; } cmdq_unhalt: err = mmc_cmdq_halt(host, false); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 7d242133528d0bfa1ff79c4284e806c4c0f6ba36..11192924097570320c77a02c0fa08435762b12a9 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -5239,19 +5239,50 @@ static int sdhci_msm_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct sdhci_msm_pltfm_data *pdata = msm_host->pdata; + int nr_groups = msm_host->pdata->pm_qos_data.cpu_group_map.nr_groups; + int i; int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - pr_debug("%s: %s\n", dev_name(&pdev->dev), __func__); + pr_debug("%s: %s Enter\n", dev_name(&pdev->dev), __func__); if (!gpio_is_valid(msm_host->pdata->status_gpio)) device_remove_file(&pdev->dev, &msm_host->polling); + + device_remove_file(&pdev->dev, &msm_host->auto_cmd21_attr); device_remove_file(&pdev->dev, &msm_host->msm_bus_vote.max_bus_bw); pm_runtime_disable(&pdev->dev); + if (msm_host->pm_qos_group_enable) { + struct sdhci_msm_pm_qos_group *group; + + for (i = 0; i < nr_groups; i++) + cancel_delayed_work_sync( + &msm_host->pm_qos[i].unvote_work); + + device_remove_file(&msm_host->pdev->dev, + &msm_host->pm_qos_group_enable_attr); + device_remove_file(&msm_host->pdev->dev, + &msm_host->pm_qos_group_status_attr); + + for (i = 0; i < nr_groups; i++) { + group = &msm_host->pm_qos[i]; + pm_qos_remove_request(&group->req); + } + } + + if (msm_host->pm_qos_irq.enabled) { + cancel_delayed_work_sync(&msm_host->pm_qos_irq.unvote_work); + device_remove_file(&pdev->dev, + &msm_host->pm_qos_irq.enable_attr); + device_remove_file(&pdev->dev, + &msm_host->pm_qos_irq.status_attr); + pm_qos_remove_request(&msm_host->pm_qos_irq.req); + } + if (msm_host->pm_qos_wq) destroy_workqueue(msm_host->pm_qos_wq); + sdhci_remove_host(host, dead); - sdhci_pltfm_free(pdev); sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false); @@ -5262,6 +5293,9 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); sdhci_msm_bus_unregister(msm_host); } + + sdhci_pltfm_free(pdev); + return 0; } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 107c05b3ddbb9da2c540098062f15a3acfcdaea1..de35a2a362f9e01751ad35218f98729beb80dc85 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -42,7 +42,7 @@ #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0 -#define MAX_WORD_RETRIES 3 +#define MAX_RETRIES 3 #define SST49LF004B 0x0060 #define SST49LF040B 0x0050 @@ -1643,7 +1643,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -1876,7 +1876,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, if (time_after(jiffies, timeo) && !chip_ready(map, adr)) break; - if (chip_ready(map, adr)) { + if (chip_good(map, adr, datum)) { xip_enable(map, chip, adr); goto op_done; } @@ -2102,7 +2102,7 @@ static int do_panic_write_oneword(struct map_info *map, struct flchip *chip, map_write(map, CMD(0xF0), chip->start); /* FIXME - should have reset delay before continuing */ - if (++retry_cnt <= MAX_WORD_RETRIES) + if (++retry_cnt <= MAX_RETRIES) goto retry; ret = -EIO; @@ -2237,6 +2237,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) unsigned long int adr; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr = cfi->addr_unlock1; @@ -2254,6 +2255,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2290,12 +2292,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; } - if (chip_ready(map, adr)) + if (chip_good(map, adr, map_word_ff(map))) break; if (time_after(jiffies, timeo)) { printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); + ret = -EIO; break; } @@ -2303,12 +2306,15 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - ret = -EIO; + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; + goto retry; + } } chip->state = FL_READY; @@ -2327,6 +2333,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long timeo = jiffies + HZ; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int retry_cnt = 0; adr += chip->start; @@ -2344,6 +2351,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ENABLE_VPP(map); xip_disable(map, chip, adr); + retry: cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -2380,7 +2388,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, chip->erase_suspended = 0; } - if (chip_ready(map, adr)) { + if (chip_good(map, adr, map_word_ff(map))) { xip_enable(map, chip, adr); break; } @@ -2389,6 +2397,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); + ret = -EIO; break; } @@ -2396,12 +2405,15 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ - if (!chip_good(map, adr, map_word_ff(map))) { + if (ret) { /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); /* FIXME - should have reset delay before continuing */ - ret = -EIO; + if (++retry_cnt <= MAX_RETRIES) { + ret = 0; + goto retry; + } } chip->state = FL_READY; @@ -2531,7 +2543,7 @@ static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct ppb_lock { struct flchip *chip; - loff_t offset; + unsigned long adr; int locked; }; @@ -2549,8 +2561,9 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, unsigned long timeo; int ret; + adr += chip->start; mutex_lock(&chip->mutex); - ret = get_chip(map, chip, adr + chip->start, FL_LOCKING); + ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { mutex_unlock(&chip->mutex); return ret; @@ -2568,8 +2581,8 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { chip->state = FL_LOCKING; - map_write(map, CMD(0xA0), chip->start + adr); - map_write(map, CMD(0x00), chip->start + adr); + map_write(map, CMD(0xA0), adr); + map_write(map, CMD(0x00), adr); } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { /* * Unlocking of one specific sector is not supported, so we @@ -2607,7 +2620,7 @@ static int __maybe_unused do_ppb_xxlock(struct map_info *map, map_write(map, CMD(0x00), chip->start); chip->state = FL_READY; - put_chip(map, chip, adr + chip->start); + put_chip(map, chip, adr); mutex_unlock(&chip->mutex); return ret; @@ -2664,9 +2677,9 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, * sectors shall be unlocked, so lets keep their locking * status at "unlocked" (locked=0) for the final re-locking. */ - if ((adr < ofs) || (adr >= (ofs + len))) { + if ((offset < ofs) || (offset >= (ofs + len))) { sect[sectors].chip = &cfi->chips[chipnum]; - sect[sectors].offset = offset; + sect[sectors].adr = adr; sect[sectors].locked = do_ppb_xxlock( map, &cfi->chips[chipnum], adr, 0, DO_XXLOCK_ONEBLOCK_GETLOCK); @@ -2680,6 +2693,8 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, i++; if (adr >> cfi->chipshift) { + if (offset >= (ofs + len)) + break; adr = 0; chipnum++; @@ -2710,7 +2725,7 @@ static int __maybe_unused cfi_ppb_unlock(struct mtd_info *mtd, loff_t ofs, */ for (i = 0; i < sectors; i++) { if (sect[i].locked) - do_ppb_xxlock(map, sect[i].chip, sect[i].offset, 0, + do_ppb_xxlock(map, sect[i].chip, sect[i].adr, 0, DO_XXLOCK_ONEBLOCK_LOCK); } diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 0c84ee80e5b6249bbcf94e37c09f92fae2dcf5a3..5c44eb57885b99094f1ba42106ee767f6df79be7 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -48,7 +48,7 @@ #define NFC_V1_V2_CONFIG (host->regs + 0x0a) #define NFC_V1_V2_ECC_STATUS_RESULT (host->regs + 0x0c) #define NFC_V1_V2_RSLTMAIN_AREA (host->regs + 0x0e) -#define NFC_V1_V2_RSLTSPARE_AREA (host->regs + 0x10) +#define NFC_V21_RSLTSPARE_AREA (host->regs + 0x10) #define NFC_V1_V2_WRPROT (host->regs + 0x12) #define NFC_V1_UNLOCKSTART_BLKADDR (host->regs + 0x14) #define NFC_V1_UNLOCKEND_BLKADDR (host->regs + 0x16) @@ -1121,6 +1121,9 @@ static void preset_v2(struct mtd_info *mtd) writew(config1, NFC_V1_V2_CONFIG1); /* preset operation */ + /* spare area size in 16-bit half-words */ + writew(mtd->oobsize / 2, NFC_V21_RSLTSPARE_AREA); + /* Unlock the internal RAM Buffer */ writew(0x2, NFC_V1_V2_CONFIG); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 68902b88415c01fa2eaefbd1468ae65ea882be69..541c17917a4dfc14fe39803d0ef25d19668553d5 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1137,6 +1137,9 @@ int ubi_detach_mtd_dev(int ubi_num, int anyway) */ get_device(&ubi->dev); +#ifdef CONFIG_MTD_UBI_FASTMAP + cancel_work_sync(&ubi->fm_work); +#endif ubi_debugfs_exit_dev(ubi); uif_close(ubi); diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 388e46be6ad92805f2a6633da6960d8c56b1b837..d0884bd9d9553ca2cd38e52d0c673f0f2a59b4b3 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -490,6 +490,82 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, return err; } +#ifdef CONFIG_MTD_UBI_FASTMAP +/** + * check_mapping - check and fixup a mapping + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @pnum: physical eraseblock number + * + * Checks whether a given mapping is valid. Fastmap cannot track LEB unmap + * operations, if such an operation is interrupted the mapping still looks + * good, but upon first read an ECC is reported to the upper layer. + * Normaly during the full-scan at attach time this is fixed, for Fastmap + * we have to deal with it while reading. + * If the PEB behind a LEB shows this symthom we change the mapping to + * %UBI_LEB_UNMAPPED and schedule the PEB for erasure. + * + * Returns 0 on success, negative error code in case of failure. + */ +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + int err; + struct ubi_vid_io_buf *vidb; + + if (!ubi->fast_attach) + return 0; + + vidb = ubi_alloc_vid_buf(ubi, GFP_NOFS); + if (!vidb) + return -ENOMEM; + + err = ubi_io_read_vid_hdr(ubi, *pnum, vidb, 0); + if (err > 0 && err != UBI_IO_BITFLIPS) { + int torture = 0; + + switch (err) { + case UBI_IO_FF: + case UBI_IO_FF_BITFLIPS: + case UBI_IO_BAD_HDR: + case UBI_IO_BAD_HDR_EBADMSG: + break; + default: + ubi_assert(0); + } + + if (err == UBI_IO_BAD_HDR_EBADMSG || err == UBI_IO_FF_BITFLIPS) + torture = 1; + + down_read(&ubi->fm_eba_sem); + vol->eba_tbl->entries[lnum].pnum = UBI_LEB_UNMAPPED; + up_read(&ubi->fm_eba_sem); + ubi_wl_put_peb(ubi, vol->vol_id, lnum, *pnum, torture); + + *pnum = UBI_LEB_UNMAPPED; + } else if (err < 0) { + ubi_err(ubi, "unable to read VID header back from PEB %i: %i", + *pnum, err); + + goto out_free; + } + + err = 0; + +out_free: + ubi_free_vid_buf(vidb); + + return err; +} +#else +static int check_mapping(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + int *pnum) +{ + return 0; +} +#endif + /** * ubi_eba_read_leb - read data. * @ubi: UBI device description object @@ -522,7 +598,13 @@ int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl->entries[lnum].pnum; - if (pnum < 0) { + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out_unlock; + } + + if (pnum == UBI_LEB_UNMAPPED) { /* * The logical eraseblock is not mapped, fill the whole buffer * with 0xFF bytes. The exception is static volumes for which @@ -930,6 +1012,12 @@ int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, return err; pnum = vol->eba_tbl->entries[lnum].pnum; + if (pnum >= 0) { + err = check_mapping(ubi, vol, lnum, &pnum); + if (err < 0) + goto out; + } + if (pnum >= 0) { dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", len, offset, vol_id, lnum, pnum); diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index 668b46202507ce7f0b59a998d2b34e7d92cc2bbc..23a6986d512b4c75ffd22f5ca51b58a8609e5f75 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1505,6 +1505,7 @@ int ubi_thread(void *u) } dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); + ubi->thread_enabled = 0; return 0; } @@ -1514,9 +1515,6 @@ int ubi_thread(void *u) */ static void shutdown_work(struct ubi_device *ubi) { -#ifdef CONFIG_MTD_UBI_FASTMAP - flush_work(&ubi->fm_work); -#endif while (!list_empty(&ubi->works)) { struct ubi_work *wrk; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 1a139d0f22328c709e33eb4f6af393fd435f52d7..f5fcc0850dacb4fa1c3646bc0a498fa3350ffe30 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -384,20 +384,15 @@ static int bond_update_speed_duplex(struct slave *slave) slave->duplex = DUPLEX_UNKNOWN; res = __ethtool_get_link_ksettings(slave_dev, &ecmd); - if (res < 0) { - slave->link = BOND_LINK_DOWN; + if (res < 0) return 1; - } - if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) { - slave->link = BOND_LINK_DOWN; + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) return 1; - } switch (ecmd.base.duplex) { case DUPLEX_FULL: case DUPLEX_HALF: break; default: - slave->link = BOND_LINK_DOWN; return 1; } @@ -1536,7 +1531,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->delay = 0; new_slave->link_failure_count = 0; - bond_update_speed_duplex(new_slave); + if (bond_update_speed_duplex(new_slave) && + bond_needs_speed_duplex(bond)) + new_slave->link = BOND_LINK_DOWN; new_slave->last_rx = jiffies - (msecs_to_jiffies(bond->params.arp_interval) + 1); @@ -2140,7 +2137,14 @@ static void bond_miimon_commit(struct bonding *bond) continue; case BOND_LINK_UP: - bond_update_speed_duplex(slave); + if (bond_update_speed_duplex(slave) && + bond_needs_speed_duplex(bond)) { + slave->link = BOND_LINK_DOWN; + netdev_warn(bond->dev, + "failed to get link speed/duplex for %s\n", + slave->dev->name); + continue; + } bond_set_slave_link_state(slave, BOND_LINK_UP, BOND_SLAVE_NOTIFY_NOW); slave->last_link_up = jiffies; diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 577e57cad1dc44194c17ffbeffff0ce16ef99600..473da3bf10c60a5da87187b9add04f9bcd19e0c5 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -1114,6 +1114,7 @@ static int bond_option_primary_set(struct bonding *bond, slave->dev->name); rcu_assign_pointer(bond->primary_slave, slave); strcpy(bond->params.primary, slave->dev->name); + bond->force_primary = true; bond_select_active_slave(bond); goto out; } diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index c26debc531eec3c11f47d6528f3885fc53a08604..71525950c641d6e4beaabc5172be9d114973444f 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -1515,6 +1515,18 @@ static const struct b53_chip_data b53_switch_chips[] = { .cpu_port = B53_CPU_PORT_25, .duplex_reg = B53_DUPLEX_STAT_FE, }, + { + .chip_id = BCM5389_DEVICE_ID, + .dev_name = "BCM5389", + .vlans = 4096, + .enabled_ports = 0x1f, + .arl_entries = 4, + .cpu_port = B53_CPU_PORT, + .vta_regs = B53_VTA_REGS, + .duplex_reg = B53_DUPLEX_STAT_GE, + .jumbo_pm_reg = B53_JUMBO_PORT_MASK, + .jumbo_size_reg = B53_JUMBO_MAX_SIZE, + }, { .chip_id = BCM5395_DEVICE_ID, .dev_name = "BCM5395", @@ -1825,6 +1837,7 @@ int b53_switch_detect(struct b53_device *dev) else dev->chip_id = BCM5365_DEVICE_ID; break; + case BCM5389_DEVICE_ID: case BCM5395_DEVICE_ID: case BCM5397_DEVICE_ID: case BCM5398_DEVICE_ID: diff --git a/drivers/net/dsa/b53/b53_mdio.c b/drivers/net/dsa/b53/b53_mdio.c index 477a16b5660ab61f7bda3dce2438d95b5806513c..6f47ff1a795232b0638e9bdcaf8b9db100e19c66 100644 --- a/drivers/net/dsa/b53/b53_mdio.c +++ b/drivers/net/dsa/b53/b53_mdio.c @@ -285,6 +285,7 @@ static const struct b53_io_ops b53_mdio_ops = { #define B53_BRCM_OUI_1 0x0143bc00 #define B53_BRCM_OUI_2 0x03625c00 #define B53_BRCM_OUI_3 0x00406000 +#define B53_BRCM_OUI_4 0x01410c00 static int b53_mdio_probe(struct mdio_device *mdiodev) { @@ -311,7 +312,8 @@ static int b53_mdio_probe(struct mdio_device *mdiodev) */ if ((phy_id & 0xfffffc00) != B53_BRCM_OUI_1 && (phy_id & 0xfffffc00) != B53_BRCM_OUI_2 && - (phy_id & 0xfffffc00) != B53_BRCM_OUI_3) { + (phy_id & 0xfffffc00) != B53_BRCM_OUI_3 && + (phy_id & 0xfffffc00) != B53_BRCM_OUI_4) { dev_err(&mdiodev->dev, "Unsupported device: 0x%08x\n", phy_id); return -ENODEV; } @@ -360,6 +362,7 @@ static const struct of_device_id b53_of_match[] = { { .compatible = "brcm,bcm53125" }, { .compatible = "brcm,bcm53128" }, { .compatible = "brcm,bcm5365" }, + { .compatible = "brcm,bcm5389" }, { .compatible = "brcm,bcm5395" }, { .compatible = "brcm,bcm5397" }, { .compatible = "brcm,bcm5398" }, diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h index f192a673caba4f0c687216934dbbb78190f5d0c8..68ab20baa631c676442cc4560c6b85039f3ad4e8 100644 --- a/drivers/net/dsa/b53/b53_priv.h +++ b/drivers/net/dsa/b53/b53_priv.h @@ -47,6 +47,7 @@ struct b53_io_ops { enum { BCM5325_DEVICE_ID = 0x25, BCM5365_DEVICE_ID = 0x65, + BCM5389_DEVICE_ID = 0x89, BCM5395_DEVICE_ID = 0x95, BCM5397_DEVICE_ID = 0x97, BCM5398_DEVICE_ID = 0x98, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 1fb80100e5e7d753b2ddd8ae741e0120ac161f42..912900db935fe9e2cb83787a715f11a96f54a1de 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -594,7 +594,7 @@ static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params, * slots for the highest priority. */ REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : - NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); /* Mapping between the CREDIT_WEIGHT registers and actual client * numbers */ diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index dda63b26e37073b0881c46953ac1da59ba0e9a8e..99f593be26e2ac670dd8375913bae09f759bdbd7 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -2541,11 +2541,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); /* Query PCI controller on system for DMA addressing - * limitation for the device. Try 64-bit first, and + * limitation for the device. Try 47-bit first, and * fail to 32-bit. */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); if (err) { @@ -2559,10 +2559,10 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_release_regions; } } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(47)); if (err) { dev_err(dev, "Unable to obtain %u-bit DMA " - "for consistent allocations, aborting\n", 64); + "for consistent allocations, aborting\n", 47); goto err_out_release_regions; } using_dac = 1; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index bcbb80ff86a76c777181844faf5802b298a791ef..1a92cd719e19d17a1600778675728c56b047f7de 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -142,16 +142,17 @@ static void mlx4_en_free_frag(struct mlx4_en_priv *priv, struct mlx4_en_rx_alloc *frags, int i) { - const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; - u32 next_frag_end = frags[i].page_offset + 2 * frag_info->frag_stride; - - - if (next_frag_end > frags[i].page_size) - dma_unmap_page(priv->ddev, frags[i].dma, frags[i].page_size, - frag_info->dma_dir); + if (frags[i].page) { + const struct mlx4_en_frag_info *frag_info = &priv->frag_info[i]; + u32 next_frag_end = frags[i].page_offset + + 2 * frag_info->frag_stride; - if (frags[i].page) + if (next_frag_end > frags[i].page_size) { + dma_unmap_page(priv->ddev, frags[i].dma, + frags[i].page_size, frag_info->dma_dir); + } put_page(frags[i].page); + } } static int mlx4_en_init_allocator(struct mlx4_en_priv *priv, @@ -586,21 +587,28 @@ static int mlx4_en_complete_rx_desc(struct mlx4_en_priv *priv, int length) { struct skb_frag_struct *skb_frags_rx = skb_shinfo(skb)->frags; - struct mlx4_en_frag_info *frag_info; int nr; dma_addr_t dma; /* Collect used fragments while replacing them in the HW descriptors */ for (nr = 0; nr < priv->num_frags; nr++) { - frag_info = &priv->frag_info[nr]; + struct mlx4_en_frag_info *frag_info = &priv->frag_info[nr]; + u32 next_frag_end = frags[nr].page_offset + + 2 * frag_info->frag_stride; + if (length <= frag_info->frag_prefix_size) break; if (unlikely(!frags[nr].page)) goto fail; dma = be64_to_cpu(rx_desc->data[nr].addr); - dma_sync_single_for_cpu(priv->ddev, dma, frag_info->frag_size, - DMA_FROM_DEVICE); + if (next_frag_end > frags[nr].page_size) + dma_unmap_page(priv->ddev, frags[nr].dma, + frags[nr].page_size, frag_info->dma_dir); + else + dma_sync_single_for_cpu(priv->ddev, dma, + frag_info->frag_size, + DMA_FROM_DEVICE); /* Save page reference in skb */ __skb_frag_set_page(&skb_frags_rx[nr], frags[nr].page); diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 474ff36b97558aebc749c0ce09b4c8fc89be2176..71578d48efbc3371f763676015f898ec83392794 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -392,11 +392,11 @@ struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; struct mlx4_qp *qp; - spin_lock(&qp_table->lock); + spin_lock_irq(&qp_table->lock); qp = __mlx4_qp_lookup(dev, qpn); - spin_unlock(&qp_table->lock); + spin_unlock_irq(&qp_table->lock); return qp; } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index d50350c7adc4b981924697b06c3568eada757076..22a5916e477e8baa798e283fe23854ffe0bb5300 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -4187,10 +4187,6 @@ static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, if (netif_is_lag_port(dev) && is_vlan_dev(upper_dev) && !netif_is_lag_master(vlan_dev_real_dev(upper_dev))) return -EINVAL; - if (!info->linking) - break; - if (netdev_has_any_upper_dev(upper_dev)) - return -EINVAL; break; case NETDEV_CHANGEUPPER: upper_dev = info->upper_dev; @@ -4566,6 +4562,8 @@ static int mlxsw_sp_netdevice_vport_event(struct net_device *dev, return -EINVAL; if (!info->linking) break; + if (netdev_has_any_upper_dev(upper_dev)) + return -EINVAL; /* We can't have multiple VLAN interfaces configured on * the same port and being members in the same bridge. */ diff --git a/drivers/net/ethernet/natsemi/sonic.c b/drivers/net/ethernet/natsemi/sonic.c index 612c7a44b26c6c58a16dbdd82017bfb3246bbb69..23821540ab078de3aafcb07c781e7f5ebc932299 100644 --- a/drivers/net/ethernet/natsemi/sonic.c +++ b/drivers/net/ethernet/natsemi/sonic.c @@ -71,7 +71,7 @@ static int sonic_open(struct net_device *dev) for (i = 0; i < SONIC_NUM_RRS; i++) { dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE), SONIC_RBSIZE, DMA_FROM_DEVICE); - if (!laddr) { + if (dma_mapping_error(lp->device, laddr)) { while(i > 0) { /* free any that were mapped successfully */ i--; dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index 457e304275357cb53a4904e4fa0f14c6ea9fd90b..f1956c4d02a0164ed41963db0c6237ec822ad707 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -54,7 +54,7 @@ #define ILT_CFG_REG(cli, reg) PSWRQ2_REG_ ## cli ## _ ## reg ## _RT_OFFSET /* ILT entry structure */ -#define ILT_ENTRY_PHY_ADDR_MASK 0x000FFFFFFFFFFFULL +#define ILT_ENTRY_PHY_ADDR_MASK (~0ULL >> 12) #define ILT_ENTRY_PHY_ADDR_SHIFT 0 #define ILT_ENTRY_VALID_MASK 0x1ULL #define ILT_ENTRY_VALID_SHIFT 52 diff --git a/drivers/net/phy/bcm-cygnus.c b/drivers/net/phy/bcm-cygnus.c index 49bbc682688356ae89b8ffcc629f017196f4c5ae..9a7dca2bb61885eb272d32e03cc84c38c7ca6531 100644 --- a/drivers/net/phy/bcm-cygnus.c +++ b/drivers/net/phy/bcm-cygnus.c @@ -61,17 +61,17 @@ static int bcm_cygnus_afe_config(struct phy_device *phydev) return rc; /* make rcal=100, since rdb default is 000 */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB1, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB1, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x10); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x10); if (rc < 0) return rc; /* CORE_EXPB0, Disable Reset R_CAL/RC_CAL Engine */ - rc = bcm_phy_write_exp(phydev, MII_BRCM_CORE_EXPB0, 0x00); + rc = bcm_phy_write_exp_sel(phydev, MII_BRCM_CORE_EXPB0, 0x00); return 0; } diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h index b2091c88b44dbbef9a4d1623a02b8b4add5f4f72..ce16b26d49ff319bcccca51b7389317d45ffa0db 100644 --- a/drivers/net/phy/bcm-phy-lib.h +++ b/drivers/net/phy/bcm-phy-lib.h @@ -14,11 +14,18 @@ #ifndef _LINUX_BCM_PHY_LIB_H #define _LINUX_BCM_PHY_LIB_H +#include #include int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val); int bcm_phy_read_exp(struct phy_device *phydev, u16 reg); +static inline int bcm_phy_write_exp_sel(struct phy_device *phydev, + u16 reg, u16 val) +{ + return bcm_phy_write_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER, val); +} + int bcm_phy_write_misc(struct phy_device *phydev, u16 reg, u16 chl, u16 value); int bcm_phy_read_misc(struct phy_device *phydev, diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c index 9636da0b6efc449907025b52e5e9cefaa51df198..caff474d2ee27b9fa0dc7fd3ccfe06a6096f9ea3 100644 --- a/drivers/net/phy/bcm7xxx.c +++ b/drivers/net/phy/bcm7xxx.c @@ -48,10 +48,10 @@ static void r_rc_cal_reset(struct phy_device *phydev) { /* Reset R_CAL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0010); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0010); /* Disable Reset R_AL/RC_CAL Engine */ - bcm_phy_write_exp(phydev, 0x00b0, 0x0000); + bcm_phy_write_exp_sel(phydev, 0x00b0, 0x0000); } static int bcm7xxx_28nm_b0_afe_config_init(struct phy_device *phydev) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2032a6de026bfd26c6ded8a20a83ca034473e640..707190d3ada0bca044d09e39c32f4611d01fa812 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -801,9 +801,6 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -948,9 +945,6 @@ static struct phy_driver ksphy_driver[] = { .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, .config_intr = kszphy_config_intr, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -960,6 +954,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, + .probe = kszphy_probe, .config_init = ksz9021_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, @@ -979,6 +974,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .driver_data = &ksz9021_type, + .probe = kszphy_probe, .config_init = ksz9031_config_init, .config_aneg = genphy_config_aneg, .read_status = ksz9031_read_status, @@ -998,9 +994,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1012,9 +1005,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, }, { @@ -1026,9 +1016,6 @@ static struct phy_driver ksphy_driver[] = { .config_init = kszphy_config_init, .config_aneg = ksz8873mll_config_aneg, .read_status = ksz8873mll_read_status, - .get_sset_count = kszphy_get_sset_count, - .get_strings = kszphy_get_strings, - .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, } }; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 36963685d42a835b383ecc862d333a6afa1ec5b2..f9ec00981b1e49c6dc577c2a52ade534d72ad03e 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1004,7 +1004,8 @@ static void team_port_disable(struct team *team, static void ___team_compute_features(struct team *team) { struct team_port *port; - u32 vlan_features = TEAM_VLAN_FEATURES & NETIF_F_ALL_FOR_ALL; + netdev_features_t vlan_features = TEAM_VLAN_FEATURES & + NETIF_F_ALL_FOR_ALL; netdev_features_t enc_features = TEAM_ENC_FEATURES; unsigned short max_hard_header_len = ETH_HLEN; unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE | diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 8a6675d92b98c763609ade909c0fdd77592f953f..f9f69d536dfeacc13040669b9da06425cb8ffeb5 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1435,7 +1435,8 @@ ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) headroom = skb_headroom(skb) - 8; - if ((skb_header_cloned(skb) || headroom < 0) && + if (((!(skb->fast_forwarded) && skb_header_cloned(skb)) || + headroom < 0) && pskb_expand_head(skb, headroom < 0 ? 8 : 0, 0, GFP_ATOMIC)) { dev_kfree_skb_any(skb); return NULL; diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c index 3a98f3762a4c81debc023d04b9c01876c6cbdc5f..4c8baba72933970069a184cd492e1c22e8a245fe 100644 --- a/drivers/net/usb/cdc_mbim.c +++ b/drivers/net/usb/cdc_mbim.c @@ -608,7 +608,7 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = { */ static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = { .description = "CDC MBIM", - .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN, + .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN | FLAG_SEND_ZLP, .bind = cdc_mbim_bind, .unbind = cdc_mbim_unbind, .manage_power = cdc_mbim_manage_power, diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index feb61eaffe3273821c9a6b1db23c349ef89a7c70..3086cae62fdcfb6c0cbc0b060451a46b8ddd18c3 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1124,7 +1124,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) * accordingly. Otherwise, we should check here. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) - delayed_ndp_size = ctx->max_ndp_size; + delayed_ndp_size = ALIGN(ctx->max_ndp_size, ctx->tx_ndp_modulus); else delayed_ndp_size = 0; @@ -1257,7 +1257,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) /* If requested, put NDP at end of frame. */ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) { nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; - cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max); + cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max - ctx->max_ndp_size); nth16->wNdpIndex = cpu_to_le16(skb_out->len); memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size); diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 1d56c73574e896b56ddad427553e2395c7fc7c2c..85bc0ca613897d7e65409a2d69f81026e14e9474 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -808,6 +808,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */ {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, + {QMI_FIXED_INTF(0x0846, 0x68d3, 8)}, /* Netgear Aircard 779S */ {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ {QMI_FIXED_INTF(0x1435, 0xd181, 3)}, /* Wistron NeWeb D18Q1 */ diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index bb2270bcbafa278ee42d34b1402b00f7f336a1cf..c915dedbb3b1da22305bee83b0821fab22d26a53 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -114,3 +114,5 @@ source "drivers/net/wireless/cnss_utils/Kconfig" source "drivers/net/wireless/cnss_genl/Kconfig" endif # WLAN + +source "drivers/net/wireless/qca402x/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 917a876062d9f7eb566172b4ae584d3ad5f64ee0..6cf62b66066119d3fe4b73ffbfe844661c248810 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_WCNSS_MEM_PRE_ALLOC) += cnss_prealloc/ obj-$(CONFIG_CNSS_UTILS) += cnss_utils/ obj-$(CONFIG_CNSS_GENL) += cnss_genl/ obj-$(CONFIG_CNSS_CRYPTO) += cnss_crypto/ +obj-$(CONFIG_QCA402X) += qca402x/ diff --git a/drivers/net/wireless/cnss/Kconfig b/drivers/net/wireless/cnss/Kconfig index 0b37af67415c0e6124b8d8441b5b5dba6a963ffa..c18cea7be4910542e5d3693d086fe5143095f21f 100644 --- a/drivers/net/wireless/cnss/Kconfig +++ b/drivers/net/wireless/cnss/Kconfig @@ -61,6 +61,19 @@ config CLD_DEBUG Say N, if you are building a release kernel for production use. Only say Y, if you are building a kernel with debug support. +config CLD_USB_CORE + tristate "Qualcomm Technologies Inc. Core wlan driver for QCA USB interface" + select WIRELESS_EXT + select WEXT_PRIV + select WEXT_CORE + select WEXT_SPY + select NL80211_TESTMODE + ---help--- + This section contains the necessary modules needed to enable the + core WLAN driver for Qualcomm Technologies Inc USB wlan chipset. + Select Y to compile the driver in order to have WLAN functionality + support. + config CLD_HL_SDIO_CORE tristate "Qualcomm Technologies Inc. Core wlan driver for QCA SDIO interface" select WIRELESS_EXT diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c index 8797e688241cd1510d659d47cc9df16e1cfa766d..b99a813ae8aad55168a2f0f5ef4c66c8f9403abc 100644 --- a/drivers/net/wireless/cnss/cnss_pci.c +++ b/drivers/net/wireless/cnss/cnss_pci.c @@ -234,8 +234,11 @@ static struct cnss_data { struct pci_dev *pdev; const struct pci_device_id *id; struct dma_iommu_mapping *smmu_mapping; + bool smmu_s1_bypass; dma_addr_t smmu_iova_start; size_t smmu_iova_len; + dma_addr_t smmu_iova_ipa_start; + size_t smmu_iova_ipa_len; struct cnss_wlan_vreg_info vreg_info; bool wlan_en_vreg_support; struct cnss_wlan_gpio_info gpio_info; @@ -1438,6 +1441,8 @@ static int cnss_smmu_init(struct device *dev) { struct dma_iommu_mapping *mapping; int atomic_ctx = 1; + int s1_bypass = 1; + int fast = 1; int ret; mapping = arm_iommu_create_mapping(&platform_bus_type, @@ -1449,13 +1454,33 @@ static int cnss_smmu_init(struct device *dev) goto map_fail; } - ret = iommu_domain_set_attr(mapping->domain, - DOMAIN_ATTR_ATOMIC, - &atomic_ctx); - if (ret) { - pr_err("%s: set atomic_ctx attribute failed, err = %d\n", - __func__, ret); - goto set_attr_fail; + if (penv->smmu_s1_bypass) { + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_S1_BYPASS, + &s1_bypass); + if (ret) { + pr_err("%s: set s1 bypass attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + } else { + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_ATOMIC, + &atomic_ctx); + if (ret) { + pr_err("%s: set atomic_ctx attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_FAST, + &fast); + if (ret) { + pr_err("%s: set fast map attr failed, err = %d\n", + __func__, ret); + goto set_attr_fail; + } } ret = arm_iommu_attach_device(dev, mapping); @@ -1618,7 +1643,6 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, if (ret) { pr_err("%s: SMMU init failed, err = %d\n", __func__, ret); - goto smmu_init_fail; } } @@ -1714,7 +1738,6 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev, dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle); err_unknown: err_pcie_suspend: -smmu_init_fail: cnss_pcie_reset_platform_ops(dev); return ret; } @@ -2717,10 +2740,14 @@ static int cnss_powerup(const struct subsys_desc *subsys) cnss_configure_wlan_en_gpio(WLAN_EN_LOW); cnss_wlan_vreg_set(vreg_info, VREG_OFF); if (penv->pdev) { - pr_err("%d: Unregistering pci device\n", __LINE__); - pci_unregister_driver(&cnss_wlan_pci_driver); - penv->pdev = NULL; - penv->pci_register_again = true; + if (wdrv && wdrv->update_status) + wdrv->update_status(penv->pdev, CNSS_SSR_FAIL); + if (!penv->recovery_in_progress) { + pr_err("%d: Unregistering pci device\n", __LINE__); + pci_unregister_driver(&cnss_wlan_pci_driver); + penv->pdev = NULL; + penv->pci_register_again = true; + } } err_wlan_vreg_on: @@ -2867,6 +2894,55 @@ static int cnss_init_dump_entry(void) return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry); } +struct dma_iommu_mapping *cnss_smmu_get_mapping(void) +{ + if (!penv) { + pr_err("Invalid penv: data %pK\n", penv); + return NULL; + } + + return penv->smmu_mapping; +} +EXPORT_SYMBOL(cnss_smmu_get_mapping); + +int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + unsigned long iova; + size_t len; + int ret = 0; + + if (!iova_addr) { + pr_err("iova_addr is NULL, paddr %pa, size %zu\n", + &paddr, size); + return -EINVAL; + } + + len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); + iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE); + + if (iova >= penv->smmu_iova_ipa_start + penv->smmu_iova_ipa_len) { + pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", + iova, + &penv->smmu_iova_ipa_start, + penv->smmu_iova_ipa_len); + return -ENOMEM; + } + + ret = iommu_map(penv->smmu_mapping->domain, iova, + rounddown(paddr, PAGE_SIZE), len, + IOMMU_READ | IOMMU_WRITE); + if (ret) { + pr_err("PA to IOVA mapping failed, ret %d\n", ret); + return ret; + } + + penv->smmu_iova_ipa_start = iova + len; + *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); + + return 0; +} +EXPORT_SYMBOL(cnss_smmu_map); + static int cnss_probe(struct platform_device *pdev) { int ret = 0; @@ -2877,6 +2953,7 @@ static int cnss_probe(struct platform_device *pdev) struct resource *res; u32 ramdump_size = 0; u32 smmu_iova_address[2]; + u32 smmu_iova_ipa[2]; if (penv) return -ENODEV; @@ -3028,6 +3105,17 @@ static int cnss_probe(struct platform_device *pdev) penv->smmu_iova_len = smmu_iova_address[1]; } + if (of_property_read_u32_array(dev->of_node, + "qcom,wlan-smmu-iova-ipa", + smmu_iova_ipa, 2) == 0) { + penv->smmu_iova_ipa_start = smmu_iova_ipa[0]; + penv->smmu_iova_ipa_len = smmu_iova_ipa[1]; + } + + if (of_property_read_bool(dev->of_node, + "qcom,smmu-s1-bypass")) + penv->smmu_s1_bypass = true; + ret = pci_register_driver(&cnss_wlan_pci_driver); if (ret) goto err_pci_reg; diff --git a/drivers/net/wireless/cnss2/debug.h b/drivers/net/wireless/cnss2/debug.h index f31fdfeaad0ed60296b87fdb4e970a56336d7370..bf2e755f8ee0ce7291db7d7e3d12ea7c42e9c737 100644 --- a/drivers/net/wireless/cnss2/debug.h +++ b/drivers/net/wireless/cnss2/debug.h @@ -26,23 +26,23 @@ extern void *cnss_ipc_log_context; } while (0) #define cnss_pr_err(_fmt, ...) do { \ - pr_err("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("ERR: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_ERR, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #define cnss_pr_warn(_fmt, ...) do { \ - pr_warn("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("WRN: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_WARNING, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #define cnss_pr_info(_fmt, ...) do { \ - pr_info("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("INF: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_INFO, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #define cnss_pr_dbg(_fmt, ...) do { \ - pr_debug("cnss: " _fmt, ##__VA_ARGS__); \ - cnss_ipc_log_string("DBG: " _fmt, ##__VA_ARGS__); \ + printk("%scnss: " _fmt, KERN_DEBUG, ##__VA_ARGS__); \ + cnss_ipc_log_string("%scnss: " _fmt, "", ##__VA_ARGS__);\ } while (0) #ifdef CONFIG_CNSS2_DEBUG diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 161e68eefa6530606404e0d88c91bd6e31974380..c1fc8ba3e4a2e159b9d0bbb05cd831cf555648d2 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1357,6 +1357,61 @@ void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv) CNSS_REASON_TIMEOUT); } +struct dma_iommu_mapping *cnss_smmu_get_mapping(struct device *dev) +{ + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); + + if (!pci_priv) + return NULL; + + return pci_priv->smmu_mapping; +} +EXPORT_SYMBOL(cnss_smmu_get_mapping); + +int cnss_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); + unsigned long iova; + size_t len; + int ret = 0; + + if (!pci_priv) + return -ENODEV; + + if (!iova_addr) { + cnss_pr_err("iova_addr is NULL, paddr %pa, size %zu\n", + &paddr, size); + return -EINVAL; + } + + len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE); + iova = roundup(pci_priv->smmu_iova_ipa_start, PAGE_SIZE); + + if (iova >= + (pci_priv->smmu_iova_ipa_start + pci_priv->smmu_iova_ipa_len)) { + cnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n", + iova, + &pci_priv->smmu_iova_ipa_start, + pci_priv->smmu_iova_ipa_len); + return -ENOMEM; + } + + ret = iommu_map(pci_priv->smmu_mapping->domain, iova, + rounddown(paddr, PAGE_SIZE), len, + IOMMU_READ | IOMMU_WRITE); + if (ret) { + cnss_pr_err("PA to IOVA mapping failed, ret %d\n", ret); + return ret; + } + + pci_priv->smmu_iova_ipa_start = iova + len; + *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE)); + + return 0; +} +EXPORT_SYMBOL(cnss_smmu_map); + int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info) { struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev)); @@ -2150,6 +2205,17 @@ static int cnss_pci_probe(struct pci_dev *pci_dev, &pci_priv->smmu_iova_start, pci_priv->smmu_iova_len); + res = platform_get_resource_byname(plat_priv->plat_dev, + IORESOURCE_MEM, + "smmu_iova_ipa"); + if (res) { + pci_priv->smmu_iova_ipa_start = res->start; + pci_priv->smmu_iova_ipa_len = resource_size(res); + cnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n", + &pci_priv->smmu_iova_ipa_start, + pci_priv->smmu_iova_ipa_len); + } + ret = cnss_pci_init_smmu(pci_priv); if (ret) { cnss_pr_err("Failed to init SMMU, err = %d\n", ret); diff --git a/drivers/net/wireless/cnss2/pci.h b/drivers/net/wireless/cnss2/pci.h index 79f66ac1bb99e07eff90844b2924484f9e39aef0..c8de4d74a1875646d2a4a227a5283e7c4fcee79b 100644 --- a/drivers/net/wireless/cnss2/pci.h +++ b/drivers/net/wireless/cnss2/pci.h @@ -63,6 +63,8 @@ struct cnss_pci_data { bool smmu_s1_enable; dma_addr_t smmu_iova_start; size_t smmu_iova_len; + dma_addr_t smmu_iova_ipa_start; + size_t smmu_iova_ipa_len; void __iomem *bar; struct cnss_msi_config *msi_config; u32 msi_ep_base_data; diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index 3fbad1f98457ffb3df464fa866034911ff21b604..2c375bb1bd387c1ca3ddc2845a743adb8afceb90 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -23,8 +23,17 @@ #define WLFW_SERVICE_INS_ID_V01 1 #define WLFW_CLIENT_ID 0x4b4e454c #define MAX_BDF_FILE_NAME 11 -#define DEFAULT_BDF_FILE_NAME "bdwlan.elf" -#define BDF_FILE_NAME_PREFIX "bdwlan.e" +#define ELF_BDF_FILE_NAME "bdwlan.elf" +#define ELF_BDF_FILE_NAME_PREFIX "bdwlan.e" +#define BIN_BDF_FILE_NAME "bdwlan.bin" +#define BIN_BDF_FILE_NAME_PREFIX "bdwlan.b" +#define DUMMY_BDF_FILE_NAME "bdwlan.dmy" + +enum cnss_bdf_type { + CNSS_BDF_BIN, + CNSS_BDF_ELF, + CNSS_BDF_DUMMY = 255, +}; #ifdef CONFIG_CNSS2_DEBUG static unsigned int qmi_timeout = 10000; @@ -40,17 +49,12 @@ static bool daemon_support; module_param(daemon_support, bool, 0600); MODULE_PARM_DESC(daemon_support, "User space has cnss-daemon support or not"); -static bool bdf_bypass; +static unsigned int bdf_type = CNSS_BDF_ELF; #ifdef CONFIG_CNSS2_DEBUG -module_param(bdf_bypass, bool, 0600); -MODULE_PARM_DESC(bdf_bypass, "If BDF is not found, send dummy BDF to FW"); +module_param(bdf_type, uint, 0600); +MODULE_PARM_DESC(bdf_type, "Type of board data file to be downloaded"); #endif -enum cnss_bdf_type { - CNSS_BDF_BIN, - CNSS_BDF_ELF, -}; - static char *cnss_qmi_mode_to_str(enum cnss_driver_mode mode) { switch (mode) { @@ -515,18 +519,33 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) goto out; } - if (plat_priv->board_info.board_id == 0xFF) - snprintf(filename, sizeof(filename), DEFAULT_BDF_FILE_NAME); - else - snprintf(filename, sizeof(filename), - BDF_FILE_NAME_PREFIX "%02x", - plat_priv->board_info.board_id); - - if (bdf_bypass) { - cnss_pr_info("bdf_bypass is enabled, sending dummy BDF\n"); - temp = filename; + switch (bdf_type) { + case CNSS_BDF_ELF: + if (plat_priv->board_info.board_id == 0xFF) + snprintf(filename, sizeof(filename), ELF_BDF_FILE_NAME); + else + snprintf(filename, sizeof(filename), + ELF_BDF_FILE_NAME_PREFIX "%02x", + plat_priv->board_info.board_id); + break; + case CNSS_BDF_BIN: + if (plat_priv->board_info.board_id == 0xFF) + snprintf(filename, sizeof(filename), BIN_BDF_FILE_NAME); + else + snprintf(filename, sizeof(filename), + BIN_BDF_FILE_NAME_PREFIX "%02x", + plat_priv->board_info.board_id); + break; + case CNSS_BDF_DUMMY: + cnss_pr_dbg("CNSS_BDF_DUMMY is set, sending dummy BDF\n"); + snprintf(filename, sizeof(filename), DUMMY_BDF_FILE_NAME); + temp = DUMMY_BDF_FILE_NAME; remaining = MAX_BDF_FILE_NAME; goto bypass_bdf; + default: + cnss_pr_err("Invalid BDF type: %d\n", bdf_type); + ret = -EINVAL; + goto err_req_fw; } ret = request_firmware(&fw_entry, filename, &plat_priv->plat_dev->dev); @@ -561,7 +580,7 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) req->data_valid = 1; req->end_valid = 1; req->bdf_type_valid = 1; - req->bdf_type = CNSS_BDF_ELF; + req->bdf_type = bdf_type; if (remaining > QMI_WLFW_MAX_DATA_SIZE_V01) { req->data_len = QMI_WLFW_MAX_DATA_SIZE_V01; @@ -594,7 +613,7 @@ int cnss_wlfw_bdf_dnld_send_sync(struct cnss_plat_data *plat_priv) } err_send: - if (!bdf_bypass) + if (bdf_type != CNSS_BDF_DUMMY) release_firmware(fw_entry); err_req_fw: kfree(req); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index fe32de252e6b2d4197a93facb2c796e3fc19a794..e7b873018dca61edb0e271324a3a5ba1e6bbb5e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -1509,14 +1509,13 @@ static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - int max_irqs, num_irqs, i, ret, nr_online_cpus; + int max_irqs, num_irqs, i, ret; u16 pci_cmd; if (!trans->cfg->mq_rx_supported) goto enable_msi; - nr_online_cpus = num_online_cpus(); - max_irqs = min_t(u32, nr_online_cpus + 2, IWL_MAX_RX_HW_QUEUES); + max_irqs = min_t(u32, num_online_cpus() + 2, IWL_MAX_RX_HW_QUEUES); for (i = 0; i < max_irqs; i++) trans_pcie->msix_entries[i].entry = i; @@ -1542,16 +1541,17 @@ static void iwl_pcie_set_interrupt_capa(struct pci_dev *pdev, * Two interrupts less: non rx causes shared with FBQ and RSS. * More than two interrupts: we will use fewer RSS queues. */ - if (num_irqs <= nr_online_cpus) { + if (num_irqs <= max_irqs - 2) { trans_pcie->trans->num_rx_queues = num_irqs + 1; trans_pcie->shared_vec_mask = IWL_SHARED_IRQ_NON_RX | IWL_SHARED_IRQ_FIRST_RSS; - } else if (num_irqs == nr_online_cpus + 1) { + } else if (num_irqs == max_irqs - 1) { trans_pcie->trans->num_rx_queues = num_irqs; trans_pcie->shared_vec_mask = IWL_SHARED_IRQ_NON_RX; } else { trans_pcie->trans->num_rx_queues = num_irqs - 1; } + WARN_ON(trans_pcie->trans->num_rx_queues > IWL_MAX_RX_HW_QUEUES); trans_pcie->alloc_vecs = num_irqs; trans_pcie->msix_enabled = true; diff --git a/drivers/net/wireless/qca402x/Kconfig b/drivers/net/wireless/qca402x/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..bae2a491d75af3f9278bd79608f174da2324ebdd --- /dev/null +++ b/drivers/net/wireless/qca402x/Kconfig @@ -0,0 +1,10 @@ +config QCA402X + tristate "Qualcomm QCA402X wireless support" + default n + ---help--- + Software for Qualcomm QCA402x including HIF and HTCA. + + Say Y here if support for Qualcomm's QCA402x wireless SoC + via host-target communication protocol is required. + Say N to disable completely if support for that device is + not needed or if not sure. diff --git a/drivers/net/wireless/qca402x/Makefile b/drivers/net/wireless/qca402x/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c052f7327b68ddbb86f615e668678caf23d208dc --- /dev/null +++ b/drivers/net/wireless/qca402x/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_compl.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_events.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_intr.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_recv.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_send.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_task.o +obj-$(CONFIG_QCA402X) += htca_mbox/htca_mbox_utils.o +obj-$(CONFIG_QCA402X) += hif_sdio/hif.o diff --git a/drivers/net/wireless/qca402x/README.txt b/drivers/net/wireless/qca402x/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..50873a81625812cebb5349209ad9110fc4569616 --- /dev/null +++ b/drivers/net/wireless/qca402x/README.txt @@ -0,0 +1,52 @@ +This directory contains support to communicate beteween an APQ8053 Host +and Qualcomm's QCA402x wireless SoC. + +QCA4020 SoC supports + 802.11 (i.e. WiFi/WLAN) + 802.15.4 (i.e. Zigbee, Thread) + BT LE + +Contents of this directory may eventually include: + cfg80211 support + SoftMAC wireless driver + Perhaps a mac80211 driver + Zigbee APIs + Thread APIs + BT APIs + +For now, all that is present are the bottommost layers of a communication stack: + + HTCA - Host/Target Communications protocol + htca_mbox + Quartz SDIO/SPI address space + Quartz mailboxes and associated SDIO/SPI registers + Quartz mbox credit-based flow control + htca_uart (TBD) + + HIF - a shim layer which abstracts the underlying Master/Host-side + interconnect controller (e.g. SDIO controller) to provide + an interconnect-independent API for use by HTCA. + hif_sdio + Host Interface layer for SDIO Master controllers + hif_spi (TBD) + Host Interface layer for SPI Master controllers + hif_uart (TBD) + Host Interface layer for UART-based controllers + + qrtzdev-a simple driver used for HTCA TESTING. + +Note: The initial implementation supports HTCA Protocol Version 1 over SDIO. +It is based on previous HTCA implementations for Atheros SoCs, but uses a +revised design which appropriately leverages kernel threads. + +This implementation is likely to evolve with increasing focus on performance, +especially for use cases of current interest such as streaming video from +Host over SDIO to WLAN; however this evolution may differ from the existing +implementation of HTCA Protocol Version 2 used by earlier Atheros SoC's. + +However there are several issues with this code: + it is based on HTCA v2 protocol which adds complexity + it is based on a non-threaded design, originally for a non-threaded RTOS +TBD: Ideally, these two implementations ought to be merged so that the resulting +implementation is based on a proper threaded design and supports both HTCA +protocol v1 and v2. diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif.c b/drivers/net/wireless/qca402x/hif_sdio/hif.c new file mode 100644 index 0000000000000000000000000000000000000000..56d3b95d8d331f95c9ba2c6ae829eba394eca3b1 --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif.c @@ -0,0 +1,1230 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hif_internal.h" +#include "hif.h" + +#if defined(DEBUG) +#define hifdebug(fmt, a...)\ + pr_err("hif %s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define hifdebug(args...) +#endif + +#define MAX_HIF_DEVICES 2 +#define ENABLE_SDIO_TIMEOUT 100 /* ms */ + +static unsigned int hif_mmcbuswidth; +EXPORT_SYMBOL(hif_mmcbuswidth); +module_param(hif_mmcbuswidth, uint, 0644); +MODULE_PARM_DESC(hif_mmcbuswidth, "Set MMC driver Bus Width: 1-1Bit, 4-4Bit, 8-8Bit"); + +static unsigned int hif_mmcclock; +EXPORT_SYMBOL(hif_mmcclock); +module_param(hif_mmcclock, uint, 0644); +MODULE_PARM_DESC(hif_mmcclock, "Set MMC driver Clock value"); + +static unsigned int hif_writecccr1; +module_param(hif_writecccr1, uint, 0644); +static unsigned int hif_writecccr1value; +module_param(hif_writecccr1value, uint, 0644); + +static unsigned int hif_writecccr2; +module_param(hif_writecccr2, uint, 0644); +static unsigned int hif_writecccr2value; +module_param(hif_writecccr2value, uint, 0644); + +static unsigned int hif_writecccr3; +module_param(hif_writecccr3, uint, 0644); +static unsigned int hif_writecccr3value; +module_param(hif_writecccr3value, uint, 0644); + +static unsigned int hif_writecccr4; +module_param(hif_writecccr4, uint, 0644); + +static unsigned int hif_writecccr4value; +module_param(hif_writecccr4value, uint, 0644); + +static int hif_device_inserted(struct sdio_func *func, + const struct sdio_device_id *id); +static void hif_device_removed(struct sdio_func *func); +static void *add_hif_device(struct sdio_func *func); +static struct hif_device *get_hif_device(struct sdio_func *func); +static void del_hif_device(struct hif_device *device); +static int func0_CMD52_write_byte(struct mmc_card *card, unsigned int address, + unsigned char byte); +static int func0_CMD52_read_byte(struct mmc_card *card, unsigned int address, + unsigned char *byte); +static void hif_stop_hif_task(struct hif_device *device); +static struct bus_request *hif_allocate_bus_request(void *device); +static void hif_free_bus_request(struct hif_device *device, + struct bus_request *busrequest); +static void hif_add_to_req_list(struct hif_device *device, + struct bus_request *busrequest); + +static int hif_reset_sdio_on_unload; +module_param(hif_reset_sdio_on_unload, int, 0644); + +static u32 hif_forcedriverstrength = 1; /* force driver strength to type D */ + +static const struct sdio_device_id hif_sdio_id_table[] = { + {SDIO_DEVICE(SDIO_ANY_ID, + SDIO_ANY_ID)}, /* QCA402x IDs are hardwired to 0 */ + {/* null */}, +}; + +MODULE_DEVICE_TABLE(sdio, hif_sdio_id_table); + +static struct sdio_driver hif_sdio_driver = { + .name = "hif_sdio", + .id_table = hif_sdio_id_table, + .probe = hif_device_inserted, + .remove = hif_device_removed, +}; + +/* make sure we unregister only when registered. */ +/* TBD: synchronization needed.... */ +/* device->completion_task, registered, ... */ +static int registered; + +static struct cbs_from_os hif_callbacks; + +static struct hif_device *hif_devices[MAX_HIF_DEVICES]; + +static int hif_disable_func(struct hif_device *device, struct sdio_func *func); +static int hif_enable_func(struct hif_device *device, struct sdio_func *func); + +static int hif_sdio_register_driver(struct cbs_from_os *callbacks) +{ + /* store the callback handlers */ + hif_callbacks = *callbacks; /* structure copy */ + + /* Register with bus driver core */ + registered++; + + return sdio_register_driver(&hif_sdio_driver); +} + +static void hif_sdio_unregister_driver(void) +{ + sdio_unregister_driver(&hif_sdio_driver); + registered--; +} + +int hif_init(struct cbs_from_os *callbacks) +{ + int status; + + hifdebug("Enter\n"); + if (!callbacks) + return HIF_ERROR; + + hifdebug("calling hif_sdio_register_driver\n"); + status = hif_sdio_register_driver(callbacks); + hifdebug("hif_sdio_register_driver returns %d\n", status); + if (status != 0) + return HIF_ERROR; + + return HIF_OK; +} + +static int __hif_read_write(struct hif_device *device, u32 address, + u8 *buffer, u32 length, + u32 request, void *context) +{ + u8 opcode; + int status = HIF_OK; + int ret = 0; + u8 temp[4]; + + if (!device || !device->func) + return HIF_ERROR; + + if (!buffer) + return HIF_EINVAL; + + if (length == 0) + return HIF_EINVAL; + + do { + if (!(request & HIF_EXTENDED_IO)) { + status = HIF_EINVAL; + break; + } + + if (request & HIF_BLOCK_BASIS) { + if (WARN_ON(length & (HIF_MBOX_BLOCK_SIZE - 1))) + return HIF_EINVAL; + } else if (request & HIF_BYTE_BASIS) { + } else { + status = HIF_EINVAL; + break; + } + + if (request & HIF_FIXED_ADDRESS) { + opcode = CMD53_FIXED_ADDRESS; + } else if (request & HIF_INCREMENTAL_ADDRESS) { + opcode = CMD53_INCR_ADDRESS; + } else { + status = HIF_EINVAL; + break; + } + + if (request & HIF_WRITE) { + if (opcode == CMD53_FIXED_ADDRESS) { + /* TBD: Why special handling? */ + if (length == 1) { + memset(temp, *buffer, 4); + ret = sdio_writesb(device->func, + address, temp, 4); + } else { + ret = + sdio_writesb(device->func, address, + buffer, length); + } + } else { + ret = sdio_memcpy_toio(device->func, address, + buffer, length); + } + } else if (request & HIF_READ) { + if (opcode == CMD53_FIXED_ADDRESS) { + if (length == + 1) { /* TBD: Why special handling? */ + memset(temp, 0, 4); + ret = sdio_readsb(device->func, temp, + address, 4); + buffer[0] = temp[0]; + } else { + ret = sdio_readsb(device->func, buffer, + address, length); + } + } else { + ret = sdio_memcpy_fromio(device->func, buffer, + address, length); + } + } else { + status = HIF_EINVAL; /* Neither read nor write */ + break; + } + + if (ret) { + hifdebug("SDIO op returns %d\n", ret); + status = HIF_ERROR; + } + } while (false); + + return status; +} + +/* Add busrequest to tail of sdio_request request list */ +static void hif_add_to_req_list(struct hif_device *device, + struct bus_request *busrequest) +{ + unsigned long flags; + + busrequest->next = NULL; + + spin_lock_irqsave(&device->req_qlock, flags); + if (device->req_qhead) + device->req_qtail->next = (void *)busrequest; + else + device->req_qhead = busrequest; + device->req_qtail = busrequest; + spin_unlock_irqrestore(&device->req_qlock, flags); +} + +int hif_sync_read(void *hif_device, u32 address, u8 *buffer, + u32 length, u32 request, void *context) +{ + int status; + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return HIF_ERROR; + + sdio_claim_host(device->func); + status = __hif_read_write(device, address, buffer, length, + request & ~HIF_SYNCHRONOUS, NULL); + sdio_release_host(device->func); + return status; +} + +/* Queue a read/write request and optionally wait for it to complete. */ +int hif_read_write(void *hif_device, u32 address, void *buffer, + u32 length, u32 req_type, void *context) +{ + struct bus_request *busrequest; + int status; + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return HIF_ERROR; + + if (!(req_type & HIF_ASYNCHRONOUS) && !(req_type & HIF_SYNCHRONOUS)) + return HIF_EINVAL; + + /* Serialize all requests through the reqlist and HIFtask */ + busrequest = hif_allocate_bus_request(device); + if (!busrequest) + return HIF_ERROR; + + /* TBD: caller may pass buffers ON THE STACK, especially 4 Byte buffers. + * If this is a problem on some platforms/drivers, this is one + * reasonable + * place to handle it. If poentially using DMA + * reject large buffers on stack + * copy 4B buffers allow register writes (no DMA) + */ + + busrequest->address = address; + busrequest->buffer = buffer; + busrequest->length = length; + busrequest->req_type = req_type; + busrequest->context = context; + + hif_add_to_req_list(device, busrequest); + device->hif_task_work = 1; + wake_up(&device->hif_wait); /* Notify HIF task */ + + if (req_type & HIF_ASYNCHRONOUS) + return HIF_PENDING; + + /* Synchronous request -- wait for completion. */ + wait_for_completion(&busrequest->comp_req); + status = busrequest->status; + hif_free_bus_request(device, busrequest); + return status; +} + +/* add_to_completion_list() - Queue a completed request + * @device: context to the hif device. + * @comple: SDIO bus access request. + * + * This function adds an sdio bus access request to the + * completion list. + * + * Return: No return. + */ +static void add_to_completion_list(struct hif_device *device, + struct bus_request *comple) +{ + unsigned long flags; + + comple->next = NULL; + + spin_lock_irqsave(&device->compl_qlock, flags); + if (device->compl_qhead) + device->compl_qtail->next = (void *)comple; + else + device->compl_qhead = comple; + + device->compl_qtail = comple; + spin_unlock_irqrestore(&device->compl_qlock, flags); +} + +/* process_completion_list() - Remove completed requests from + * the completion list, and invoke the corresponding callbacks. + * + * @device: HIF device handle. + * + * Function to clean the completion list. + * + * Return: No + */ +static void process_completion_list(struct hif_device *device) +{ + unsigned long flags; + struct bus_request *next_comple; + struct bus_request *request; + + /* Pull the entire chain of completions from the list */ + spin_lock_irqsave(&device->compl_qlock, flags); + request = device->compl_qhead; + device->compl_qhead = NULL; + device->compl_qtail = NULL; + spin_unlock_irqrestore(&device->compl_qlock, flags); + + while (request) { + int status; + void *context; + + hifdebug("HIF top of loop\n"); + next_comple = (struct bus_request *)request->next; + + status = request->status; + context = request->context; + hif_free_bus_request(device, request); + device->cbs_from_hif.rw_completion_hdl(context, status); + + request = next_comple; + } +} + +/* completion_task() - Thread to process request completions + * + * @param: context to the hif device. + * + * Completed asynchronous requests are added to a completion + * queue where they are processed by this task. This serves + * multiple purposes: + * -minimizes processing by the HIFTask, which allows + * that task to keep SDIO busy + * -allows request processing to be parallelized on + * multiprocessor systems + * -provides a suspendable context for use by the + * caller's callback function, though this should + * not be abused since it will cause requests to + * sit on the completion queue (which makes us + * more likely to exhaust free requests). + * + * Return: 0 thread exits + */ +static int completion_task(void *param) +{ + struct hif_device *device; + + device = (struct hif_device *)param; + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + hifdebug("HIF top of loop\n"); + wait_event_interruptible(device->completion_wait, + device->completion_work); + if (!device->completion_work) + break; + + if (device->completion_shutdown) + break; + + device->completion_work = 0; + process_completion_list(device); + } + + /* Process any remaining completions. + * This task should not be shut down + * until after all requests are stopped. + */ + process_completion_list(device); + + complete_and_exit(&device->completion_exit, 0); + return 0; +} + +/* hif_request_complete() - Completion processing after a request + * is processed. + * + * @device: device handle. + * @request: SIDO bus access request. + * + * All completed requests are queued onto a completion list + * which is processed by complete_task. + * + * Return: None. + */ +static inline void hif_request_complete(struct hif_device *device, + struct bus_request *request) +{ + add_to_completion_list(device, request); + device->completion_work = 1; + wake_up(&device->completion_wait); +} + +/* hif_stop_completion_thread() - Destroy the completion task + * @device: device handle. + * + * This function will destroy the completion thread. + * + * Return: None. + */ +static inline void hif_stop_completion_thread(struct hif_device *device) +{ + if (device->completion_task) { + init_completion(&device->completion_exit); + device->completion_shutdown = 1; + + device->completion_work = 1; + wake_up(&device->completion_wait); + wait_for_completion(&device->completion_exit); + device->completion_task = NULL; + } +} + +/* This task tries to keep the SDIO bus as busy as it + * can. It pulls both requests off the request queue and + * it uses the underlying sdio API to make them happen. + * + * Requests may be one of + * synchronous (a thread is suspended until it completes) + * asynchronous (a completion callback will be invoked) + * and one of + * reads (from Target SDIO space into Host RAM) + * writes (from Host RAM into Target SDIO space) + * and it is to one of + * Target's mailbox space + * Target's register space + * and lots of other choices. + */ +static int hif_task(void *param) +{ + struct hif_device *device; + struct bus_request *request; + int status; + unsigned long flags; + + set_user_nice(current, -3); + device = (struct hif_device *)param; + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + hifdebug("top of loop\n"); + /* wait for work */ + wait_event_interruptible(device->hif_wait, + device->hif_task_work); + if (!device->hif_task_work) + /* interrupted, exit */ + break; + + if (device->hif_shutdown) + break; + + device->hif_task_work = 0; + + /* We want to hold the host over multiple cmds if possible; + * but holding the host blocks card interrupts. + */ + sdio_claim_host(device->func); + + for (;;) { + hifdebug("pull next request\n"); + /* Pull the next request to work on */ + spin_lock_irqsave(&device->req_qlock, flags); + request = device->req_qhead; + if (!request) { + spin_unlock_irqrestore(&device->req_qlock, + flags); + break; + } + + /* Remove request from queue */ + device->req_qhead = (struct bus_request *)request->next; + /* Note: No need to clean up req_qtail */ + + spin_unlock_irqrestore(&device->req_qlock, flags); + + /* call __hif_read_write to do the work */ + hifdebug("before HIFRW: address=0x%08x buffer=0x%pK\n", + request->address, request->buffer); + hifdebug("before HIFRW: length=%d req_type=0x%08x\n", + request->length, request->req_type); + + if (request->req_type & HIF_WRITE) { + int i; + int dbgcount; + + if (request->length <= 16) + dbgcount = request->length; + else + dbgcount = 16; + + for (i = 0; i < dbgcount; i++) + hifdebug("|0x%02x", request->buffer[i]); + hifdebug("\n"); + } + status = __hif_read_write( + device, request->address, request->buffer, + request->length, + request->req_type & ~HIF_SYNCHRONOUS, NULL); + hifdebug("after HIFRW: address=0x%08x buffer=0x%pK\n", + request->address, request->buffer); + hifdebug("after HIFRW: length=%d req_type=0x%08x\n", + request->length, request->req_type); + + if (request->req_type & HIF_READ) { + int i; + int dbgcount; + + if (request->length <= 16) + dbgcount = request->length; + else + dbgcount = 16; + + for (i = 0; i < dbgcount; i++) + hifdebug("|0x%02x", request->buffer[i]); + hifdebug("\n"); + } + + /* When we return, the read/write is done */ + request->status = status; + + if (request->req_type & HIF_ASYNCHRONOUS) + hif_request_complete(device, request); + else + /* notify thread that's waiting on this request + */ + complete(&request->comp_req); + } + sdio_release_host(device->func); + } + + complete_and_exit(&device->hif_exit, 0); + return 0; +} + +int hif_configure_device(void *hif_device, + enum hif_device_config_opcode opcode, + void *config, u32 config_len) +{ + int status = HIF_OK; + struct hif_device *device = (struct hif_device *)hif_device; + + switch (opcode) { + case HIF_DEVICE_GET_MBOX_BLOCK_SIZE: + ((u32 *)config)[0] = HIF_MBOX0_BLOCK_SIZE; + ((u32 *)config)[1] = HIF_MBOX1_BLOCK_SIZE; + ((u32 *)config)[2] = HIF_MBOX2_BLOCK_SIZE; + ((u32 *)config)[3] = HIF_MBOX3_BLOCK_SIZE; + break; + + case HIF_DEVICE_SET_CONTEXT: + device->context = config; + break; + + case HIF_DEVICE_GET_CONTEXT: + if (!config) + return HIF_ERROR; + *(void **)config = device->context; + break; + + default: + status = HIF_ERROR; + } + + return status; +} + +void hif_shutdown_device(void *device) +{ + if (!device) { + int i; + /* since we are unloading the driver, reset all cards + * in case the SDIO card is externally powered and we + * are unloading the SDIO stack. This avoids the problem + * when the SDIO stack is reloaded and attempts are made + * to re-enumerate a card that is already enumerated. + */ + + /* Unregister with bus driver core */ + if (registered) { + registered = 0; + hif_sdio_unregister_driver(); + WARN_ON(1); + return; + } + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] && !hif_devices[i]->func) { + del_hif_device(hif_devices[i]); + hif_devices[i] = NULL; + } + } + } +} + +static void hif_irq_handler(struct sdio_func *func) +{ + int status; + struct hif_device *device; + + device = get_hif_device(func); + device->irq_handling = 1; + /* release the host during ints so we can pick it back up when we + * process cmds + */ + sdio_release_host(device->func); + status = device->cbs_from_hif.dsr_hdl(device->cbs_from_hif.context); + sdio_claim_host(device->func); + device->irq_handling = 0; +} + +static void hif_force_driver_strength(struct sdio_func *func) +{ + unsigned int addr = SDIO_CCCR_DRIVE_STRENGTH; + unsigned char value = 0; + + if (func0_CMD52_read_byte(func->card, addr, &value)) + goto cmd_fail; + + value = (value & (~(SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT))) | + SDIO_DTSx_SET_TYPE_D; + if (func0_CMD52_write_byte(func->card, addr, value)) + goto cmd_fail; + + addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR; + value = 0; + if (func0_CMD52_read_byte(func->card, addr, &value)) + goto cmd_fail; + + value = (value & (~CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK)) | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C | + CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D; + if (func0_CMD52_write_byte(func->card, addr, value)) + goto cmd_fail; + return; +cmd_fail: + hifdebug("set fail\n"); +} + +static int hif_set_mmc_buswidth(struct sdio_func *func, + struct hif_device *device) +{ + int ret = -1; + + if (hif_mmcbuswidth == 1) { + ret = func0_CMD52_write_byte(func->card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_1BIT); + if (ret) + return ret; + device->host->ios.bus_width = MMC_BUS_WIDTH_1; + device->host->ops->set_ios(device->host, &device->host->ios); + } else if (hif_mmcbuswidth == 4 && + (device->host->caps & MMC_CAP_4_BIT_DATA)) { + ret = func0_CMD52_write_byte(func->card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_4BIT); + if (ret) + return ret; + device->host->ios.bus_width = MMC_BUS_WIDTH_4; + device->host->ops->set_ios(device->host, &device->host->ios); + } +#ifdef SDIO_BUS_WIDTH_8BIT + else if (hif_mmcbuswidth == 8 && + (device->host->caps & MMC_CAP_8_BIT_DATA)) { + ret = func0_CMD52_write_byte(func->card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | + SDIO_BUS_WIDTH_8BIT); + if (ret) + return ret; + device->host->ios.bus_width = MMC_BUS_WIDTH_8; + device->host->ops->set_ios(device->host, &device->host->ios); + } +#endif /* SDIO_BUS_WIDTH_8BIT */ + return ret; +} + +static int hif_device_inserted(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int i; + int ret = -1; + struct hif_device *device = NULL; + int count; + + hifdebug("Enter\n"); + + /* dma_mask should be populated here. + * Use the parent device's setting. + */ + func->dev.dma_mask = mmc_dev(func->card->host)->dma_mask; + + if (!add_hif_device(func)) + return ret; + device = get_hif_device(func); + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (!hif_devices[i]) { + hif_devices[i] = device; + break; + } + } + if (WARN_ON(i >= MAX_HIF_DEVICES)) + return ret; + + device->id = id; + device->host = func->card->host; + device->is_enabled = false; + + { + u32 clock, clock_set = SDIO_CLOCK_FREQUENCY_DEFAULT; + + sdio_claim_host(func); + + /* force driver strength to type D */ + if (hif_forcedriverstrength == 1) + hif_force_driver_strength(func); + + if (hif_writecccr1) + (void)func0_CMD52_write_byte(func->card, hif_writecccr1, + hif_writecccr1value); + if (hif_writecccr2) + (void)func0_CMD52_write_byte(func->card, hif_writecccr2, + hif_writecccr2value); + if (hif_writecccr3) + (void)func0_CMD52_write_byte(func->card, hif_writecccr3, + hif_writecccr3value); + if (hif_writecccr4) + (void)func0_CMD52_write_byte(func->card, hif_writecccr4, + hif_writecccr4value); + /* Set MMC Clock */ + if (hif_mmcclock > 0) + clock_set = hif_mmcclock; + if (mmc_card_hs(func->card)) + clock = 50000000; + else + clock = func->card->cis.max_dtr; + if (clock > device->host->f_max) + clock = device->host->f_max; + hifdebug("clock is %d", clock); + + /* only when hif_mmcclock module parameter is specified, + * set the clock explicitly + */ + if (hif_mmcclock > 0) { + device->host->ios.clock = clock_set; + device->host->ops->set_ios(device->host, + &device->host->ios); + } + /* Set MMC Bus Width: 1-1Bit, 4-4Bit, 8-8Bit */ + if (hif_mmcbuswidth > 0) + ret = hif_set_mmc_buswidth(func, device); + + sdio_release_host(func); + } + + spin_lock_init(&device->req_free_qlock); + spin_lock_init(&device->req_qlock); + + /* Initialize the bus requests to be used later */ + memset(device->bus_request, 0, sizeof(device->bus_request)); + for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) { + init_completion(&device->bus_request[count].comp_req); + hif_free_bus_request(device, &device->bus_request[count]); + } + init_waitqueue_head(&device->hif_wait); + spin_lock_init(&device->compl_qlock); + init_waitqueue_head(&device->completion_wait); + + ret = hif_enable_func(device, func); + if ((ret == HIF_OK) || (ret == HIF_PENDING)) { + hifdebug("Function is ENABLED"); + return 0; + } + + for (i = 0; i < MAX_HIF_DEVICES; i++) { + if (hif_devices[i] == device) { + hif_devices[i] = NULL; + break; + } + } + sdio_set_drvdata(func, NULL); + del_hif_device(device); + return ret; +} + +void hif_un_mask_interrupt(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return; + + /* Unmask our function IRQ */ + sdio_claim_host(device->func); + device->func->card->host->ops->enable_sdio_irq(device->func->card->host, + 1); + device->is_intr_enb = true; + sdio_release_host(device->func); +} + +void hif_mask_interrupt(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + if (!device || !device->func) + return; + + /* Mask our function IRQ */ + sdio_claim_host(device->func); + device->func->card->host->ops->enable_sdio_irq(device->func->card->host, + 0); + device->is_intr_enb = false; + sdio_release_host(device->func); +} + +static struct bus_request *hif_allocate_bus_request(void *hif_device) +{ + struct bus_request *busrequest; + unsigned long flag; + struct hif_device *device = (struct hif_device *)hif_device; + + spin_lock_irqsave(&device->req_free_qlock, flag); + /* Remove first in list */ + busrequest = device->bus_req_free_qhead; + if (busrequest) + device->bus_req_free_qhead = + (struct bus_request *)busrequest->next; + spin_unlock_irqrestore(&device->req_free_qlock, flag); + + return busrequest; +} + +static void hif_free_bus_request(struct hif_device *device, + struct bus_request *busrequest) +{ + unsigned long flag; + + if (!busrequest) + return; + + busrequest->next = NULL; + + /* Insert first in list */ + spin_lock_irqsave(&device->req_free_qlock, flag); + busrequest->next = (struct bus_request *)device->bus_req_free_qhead; + device->bus_req_free_qhead = busrequest; + spin_unlock_irqrestore(&device->req_free_qlock, flag); +} + +static int hif_disable_func(struct hif_device *device, struct sdio_func *func) +{ + int ret; + int status = HIF_OK; + + device = get_hif_device(func); + + hif_stop_completion_thread(device); + hif_stop_hif_task(device); + + /* Disable the card */ + sdio_claim_host(device->func); + ret = sdio_disable_func(device->func); + if (ret) + status = HIF_ERROR; + + if (hif_reset_sdio_on_unload && (status == HIF_OK)) { + /* Reset the SDIO interface. This is useful in + * automated testing where the card does not need + * to be removed at the end of the test. It is + * expected that the user will also unload/reload + * the host controller driver to force the bus driver + * to re-enumerate the slot. + */ + + /* NOTE : sdio_f0_writeb() cannot be used here, that API only + * allows access to undefined registers in the range of: + * 0xF0-0xFF + */ + + ret = func0_CMD52_write_byte(device->func->card, + SDIO_CCCR_ABORT, (1 << 3)); + if (ret) + status = HIF_ERROR; + } + + sdio_release_host(device->func); + + if (status == HIF_OK) + device->is_enabled = false; + return status; +} + +static int hif_enable_func(struct hif_device *device, struct sdio_func *func) +{ + int ret = HIF_OK; + + device = get_hif_device(func); + + if (!device) + return HIF_EINVAL; + + if (!device->is_enabled) { + /* enable the SDIO function */ + sdio_claim_host(func); + + /* give us some time to enable, in ms */ + func->enable_timeout = ENABLE_SDIO_TIMEOUT; + ret = sdio_enable_func(func); + if (ret) { + sdio_release_host(func); + return HIF_ERROR; + } + ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); + + sdio_release_host(func); + if (ret) + return HIF_ERROR; + device->is_enabled = true; + + if (!device->completion_task) { + device->compl_qhead = NULL; + device->compl_qtail = NULL; + device->completion_shutdown = 0; + device->completion_task = kthread_create( + completion_task, (void *)device, "HIFCompl"); + if (IS_ERR(device->completion_task)) { + device->completion_shutdown = 1; + return HIF_ERROR; + } + wake_up_process(device->completion_task); + } + + /* create HIF I/O thread */ + if (!device->hif_task) { + device->hif_shutdown = 0; + device->hif_task = + kthread_create(hif_task, (void *)device, "HIF"); + if (IS_ERR(device->hif_task)) { + device->hif_shutdown = 1; + return HIF_ERROR; + } + wake_up_process(device->hif_task); + } + } + + if (!device->claimed_context) { + ret = hif_callbacks.dev_inserted_hdl(hif_callbacks.context, + device); + if (ret != HIF_OK) { + /* Disable the SDIO func & Reset the sdio + * for automated tests to move ahead, where + * the card does not need to be removed at + * the end of the test. + */ + hif_disable_func(device, func); + } + (void)sdio_claim_irq(func, hif_irq_handler); + } + + return ret; +} + +static void hif_device_removed(struct sdio_func *func) +{ + int i; + int status = HIF_OK; + struct hif_device *device; + + device = get_hif_device(func); + if (!device) + return; + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] == device) + hif_devices[i] = NULL; + } + + if (device->claimed_context) { + status = hif_callbacks.dev_removed_hdl( + device->claimed_context, device); + } + + /* TBD: Release IRQ (opposite of sdio_claim_irq) */ + hif_mask_interrupt(device); + + if (device->is_enabled) + status = hif_disable_func(device, func); + + del_hif_device(device); +} + +static void *add_hif_device(struct sdio_func *func) +{ + struct hif_device *hifdevice = NULL; + + if (!func) + return NULL; + + hifdevice = kmalloc(sizeof(*hifdevice), GFP_KERNEL); + if (!hifdevice) + return NULL; + + memset(hifdevice, 0, sizeof(*hifdevice)); + hifdevice->func = func; + sdio_set_drvdata(func, hifdevice); + + return (void *)hifdevice; +} + +static struct hif_device *get_hif_device(struct sdio_func *func) +{ + return (struct hif_device *)sdio_get_drvdata(func); +} + +static void del_hif_device(struct hif_device *device) +{ + if (!device) + return; + kfree(device); +} + +void hif_claim_device(void *hif_device, void *context) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + device->claimed_context = context; +} + +void hif_release_device(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + device->claimed_context = NULL; +} + +int hif_attach(void *hif_device, struct cbs_from_hif *callbacks) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + if (device->cbs_from_hif.context) { + /* already in use! */ + return HIF_ERROR; + } + device->cbs_from_hif = *callbacks; + return HIF_OK; +} + +static void hif_stop_hif_task(struct hif_device *device) +{ + if (device->hif_task) { + init_completion(&device->hif_exit); + device->hif_shutdown = 1; + device->hif_task_work = 1; + wake_up(&device->hif_wait); + wait_for_completion(&device->hif_exit); + device->hif_task = NULL; + } +} + +/* hif_reset_target() - Reset target device + * @struct hif_device: pointer to struct hif_device structure + * + * Reset the target by invoking power off and power on + * sequence to bring back target into active state. + * This API shall be called only when driver load/unload + * is in progress. + * + * Return: 0 on success, error for failure case. + */ +static int hif_reset_target(struct hif_device *hif_device) +{ + int ret; + + if (!hif_device || !hif_device->func || !hif_device->func->card) + return -ENODEV; + /* Disable sdio func->pull down WLAN_EN-->pull down DAT_2 line */ + ret = mmc_power_save_host(hif_device->func->card->host); + if (ret) + goto done; + + /* pull up DAT_2 line->pull up WLAN_EN-->Enable sdio func */ + ret = mmc_power_restore_host(hif_device->func->card->host); + +done: + return ret; +} + +void hif_detach(void *hif_device) +{ + struct hif_device *device = (struct hif_device *)hif_device; + + hif_stop_hif_task(device); + if (device->ctrl_response_timeout) { + /* Reset the target by invoking power off and power on sequence + * to the card to bring back into active state. + */ + if (hif_reset_target(device)) + panic("BUG"); + device->ctrl_response_timeout = false; + } + + memset(&device->cbs_from_hif, 0, sizeof(device->cbs_from_hif)); +} + +#define SDIO_SET_CMD52_ARG(arg, rw, func, raw, address, writedata) \ + ((arg) = ((((rw) & 1) << 31) | (((func) & 0x7) << 28) | \ + (((raw) & 1) << 27) | (1 << 26) | \ + (((address) & 0x1FFFF) << 9) | (1 << 8) | \ + ((writedata) & 0xFF))) + +#define SDIO_SET_CMD52_READ_ARG(arg, func, address) \ + SDIO_SET_CMD52_ARG(arg, 0, (func), 0, address, 0x00) +#define SDIO_SET_CMD52_WRITE_ARG(arg, func, address, value) \ + SDIO_SET_CMD52_ARG(arg, 1, (func), 0, address, value) + +static int func0_CMD52_write_byte(struct mmc_card *card, unsigned int address, + unsigned char byte) +{ + struct mmc_command ioCmd; + unsigned long arg; + int status; + + memset(&ioCmd, 0, sizeof(ioCmd)); + SDIO_SET_CMD52_WRITE_ARG(arg, 0, address, byte); + ioCmd.opcode = SD_IO_RW_DIRECT; + ioCmd.arg = arg; + ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + status = mmc_wait_for_cmd(card->host, &ioCmd, 0); + + return status; +} + +static int func0_CMD52_read_byte(struct mmc_card *card, unsigned int address, + unsigned char *byte) +{ + struct mmc_command ioCmd; + unsigned long arg; + s32 err; + + memset(&ioCmd, 0, sizeof(ioCmd)); + SDIO_SET_CMD52_READ_ARG(arg, 0, address); + ioCmd.opcode = SD_IO_RW_DIRECT; + ioCmd.arg = arg; + ioCmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &ioCmd, 0); + + if ((!err) && (byte)) + *byte = ioCmd.resp[0] & 0xFF; + + return err; +} + +void hif_set_handle(void *hif_handle, void *handle) +{ + struct hif_device *device = (struct hif_device *)hif_handle; + + device->caller_handle = handle; +} + +size_t hif_get_device_size(void) +{ + return sizeof(struct hif_device); +} diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif.h b/drivers/net/wireless/qca402x/hif_sdio/hif.h new file mode 100644 index 0000000000000000000000000000000000000000..924d2e4f020bc7424d0c1ca8efc5ce75a9444336 --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif.h @@ -0,0 +1,335 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#ifndef _HIF_H_ +#define _HIF_H_ + +#define DEBUG +#undef DEBUG + +#define HIF_OK 0 +#define HIF_PENDING 1 +#define HIF_ERROR 2 +#define HIF_EINVAL 3 + +/* direction - Direction of transfer (HIF_READ/HIF_WRITE). */ +#define HIF_READ 0x00000001 +#define HIF_WRITE 0x00000002 +#define HIF_DIR_MASK (HIF_READ | HIF_WRITE) + +/* type - An interface may support different kind of read/write commands. + * For example: SDIO supports CMD52/CMD53s. In case of MSIO it + * translates to using different kinds of TPCs. The command type + * is thus divided into a basic and an extended command and can + * be specified using HIF_BASIC_IO/HIF_EXTENDED_IO. + */ +#define HIF_BASIC_IO 0x00000004 +#define HIF_EXTENDED_IO 0x00000008 +#define HIF_TYPE_MASK (HIF_BASIC_IO | HIF_EXTENDED_IO) + +/* emode - This indicates the whether the command is to be executed in a + * blocking or non-blocking fashion (HIF_SYNCHRONOUS/ + * HIF_ASYNCHRONOUS). The read/write data paths in HTCA have been + * implemented using the asynchronous mode allowing the the bus + * driver to indicate the completion of operation through the + * registered callback routine. The requirement primarily comes + * from the contexts these operations get called from (a driver's + * transmit context or the ISR context in case of receive). + * Support for both of these modes is essential. + */ +#define HIF_SYNCHRONOUS 0x00000010 +#define HIF_ASYNCHRONOUS 0x00000020 +#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS) + +/* dmode - An interface may support different kinds of commands based on + * the tradeoff between the amount of data it can carry and the + * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/ + * HIF_BLOCK_BASIS). In case of latter, the data is rounded off + * to the nearest block size by padding. The size of the block is + * configurable at compile time using the HIF_BLOCK_SIZE and is + * negotiated with the target during initialization after the + * AR6000 interrupts are enabled. + */ +#define HIF_BYTE_BASIS 0x00000040 +#define HIF_BLOCK_BASIS 0x00000080 +#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS) + +/* amode - This indicates if the address has to be incremented on AR6000 + * after every read/write operation (HIF?FIXED_ADDRESS/ + * HIF_INCREMENTAL_ADDRESS). + */ +#define HIF_FIXED_ADDRESS 0x00000100 +#define HIF_INCREMENTAL_ADDRESS 0x00000200 +#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | HIF_INCREMENTAL_ADDRESS) + +#define HIF_WR_ASYNC_BYTE_FIX \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_WR_ASYNC_BYTE_INC \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_ASYNC_BLOCK_INC \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_SYNC_BYTE_FIX \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_WR_SYNC_BYTE_INC \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_SYNC_BLOCK_INC \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_ASYNC_BLOCK_FIX \ + (HIF_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_WR_SYNC_BLOCK_FIX \ + (HIF_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_SYNC_BYTE_INC \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BYTE_FIX \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BYTE_FIX \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BLOCK_FIX \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BYTE_INC \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BYTE_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_ASYNC_BLOCK_INC \ + (HIF_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BLOCK_INC \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BLOCK_FIX \ + (HIF_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | HIF_BLOCK_BASIS | \ + HIF_FIXED_ADDRESS) + +enum hif_device_config_opcode { + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, + HIF_DEVICE_SET_CONTEXT, + HIF_DEVICE_GET_CONTEXT, +}; + +/* HIF CONFIGURE definitions: + * + * HIF_DEVICE_GET_MBOX_BLOCK_SIZE + * input : none + * output : array of 4 u32s + * notes: block size is returned for each mailbox (4) + * + * HIF_DEVICE_SET_CONTEXT + * input : arbitrary pointer-sized value + * output: none + * notes: stores an arbitrary value which can be retrieved later + * + * HIF_DEVICE_GET_CONTEXT + * input: none + * output : arbitrary pointer-sized value + * notes: retrieves an arbitrary value which was set earlier + */ +struct cbs_from_hif { + void *context; /* context to pass to the dsrhandler + * note : rw_completion_hdl is provided the context + * passed to hif_read_write + */ + int (*rw_completion_hdl)(void *rw_context, int status); + int (*dsr_hdl)(void *context); +}; + +struct cbs_from_os { + void *context; /* context to pass for all callbacks except + * dev_removed_hdl the dev_removed_hdl is only called if + * the device is claimed + */ + int (*dev_inserted_hdl)(void *context, void *hif_handle); + int (*dev_removed_hdl)(void *claimed_context, void *hif_handle); + int (*dev_suspend_hdl)(void *context); + int (*dev_resume_hdl)(void *context); + int (*dev_wakeup_hdl)(void *context); +#if defined(DEVICE_POWER_CHANGE) + int (*dev_pwr_change_hdl)(void *context, + HIF_DEVICE_POWER_CHANGE_TYPE config); +#endif /* DEVICE_POWER_CHANGE */ +}; + +/* other interrupts (non-Recv) are pending, host + * needs to read the register table to figure out what + */ +#define HIF_OTHER_EVENTS BIT(0) + +#define HIF_RECV_MSG_AVAIL BIT(1) /* pending recv packet */ + +struct hif_pending_events_info { + u32 events; + u32 look_ahead; + u32 available_recv_bytes; +}; + +/* function to get pending events , some HIF modules use special mechanisms + * to detect packet available and other interrupts + */ +typedef int (*HIF_PENDING_EVENTS_FUNC)(void *device, + struct hif_pending_events_info *p_events, + void *async_context); + +#define HIF_MASK_RECV TRUE +#define HIF_UNMASK_RECV FALSE +/* function to mask recv events */ +typedef int (*HIF_MASK_UNMASK_RECV_EVENT)(void *device, bool mask, + void *async_context); + +#ifdef HIF_MBOX_SLEEP_WAR +/* This API is used to update the target sleep state */ +void hif_set_mbox_sleep(void *device, bool sleep, bool wait, + bool cache); +#endif +/* This API is used to perform any global initialization of the HIF layer + * and to set OS driver callbacks (i.e. insertion/removal) to the HIF layer + */ +int hif_init(struct cbs_from_os *callbacks); + +/* This API claims the HIF device and provides a context for handling removal. + * The device removal callback is only called when the OS claims + * a device. The claimed context must be non-NULL + */ +void hif_claim_device(void *device, void *claimed_context); + +/* release the claimed device */ +void hif_release_device(void *device); + +/* This API allows the calling layer to attach callbacks from HIF */ +int hif_attach(void *device, struct cbs_from_hif *callbacks); + +/* This API allows the calling layer to detach callbacks from HIF */ +void hif_detach(void *device); + +void hif_set_handle(void *hif_handle, void *handle); + +int hif_sync_read(void *device, u32 address, u8 *buffer, + u32 length, u32 request, void *context); + +size_t hif_get_device_size(void); + +/* This API is used to provide the read/write interface over the specific bus + * interface. + * address - Starting address in the AR6000's address space. For mailbox + * writes, it refers to the start of the mbox boundary. It should + * be ensured that the last byte falls on the mailbox's EOM. For + * mailbox reads, it refers to the end of the mbox boundary. + * buffer - Pointer to the buffer containg the data to be transmitted or + * received. + * length - Amount of data to be transmitted or received. + * request - Characterizes the attributes of the command. + */ +int hif_read_write(void *device, u32 address, void *buffer, + u32 length, u32 request, void *context); + +/* This can be initiated from the unload driver context when the OS has no more + * use for + * the device. + */ +void hif_shutdown_device(void *device); +void hif_surprise_removed(void *device); + +void hif_mask_interrupt(void *device); + +void hif_un_mask_interrupt(void *device); + +int hif_configure_device(void *device, + enum hif_device_config_opcode opcode, + void *config, u32 config_len); + +/* This API wait for the remaining MBOX messages to be drained + * This should be moved to HTCA AR6K layer + */ +int hif_wait_for_pending_recv(void *device); + +/* BMI and Diag window abstraction + */ + +#define HIF_BMI_EXCHANGE_NO_TIMEOUT ((u32)(0)) + +#define DIAG_TRANSFER_LIMIT 2048U /* maximum number of bytes that can be handled + * atomically by DiagRead/DiagWrite + */ + +#ifdef FEATURE_RUNTIME_PM +/* Runtime power management API of HIF to control + * runtime pm. During Runtime Suspend the get API + * return -EAGAIN. The caller can queue the cmd or return. + * The put API decrements the usage count. + * The get API increments the usage count. + * The API's are exposed to HTT and WMI Services only. + */ +int hif_pm_runtime_get(void *device); +int hif_pm_runtime_put(void *device); +void *hif_runtime_pm_prevent_suspend_init(const char *name); +void hif_runtime_pm_prevent_suspend_deinit(void *data); +int hif_pm_runtime_prevent_suspend(void *ol_sc, void *data); +int hif_pm_runtime_allow_suspend(void *ol_sc, void *data); +int hif_pm_runtime_prevent_suspend_timeout(void *ol_sc, void *data, + unsigned int delay); +void hif_request_runtime_pm_resume(void *ol_sc); +#else +static inline int hif_pm_runtime_get(void *device) +{ + return 0; +} + +static inline int hif_pm_runtime_put(void *device) +{ + return 0; +} + +static inline int hif_pm_runtime_prevent_suspend(void *ol_sc, void *context) +{ + return 0; +} + +static inline int hif_pm_runtime_allow_suspend(void *ol_sc, void *context) +{ + return 0; +} + +static inline int hif_pm_runtime_prevent_suspend_timeout(void *ol_sc, + void *context, + unsigned int msec) +{ + return 0; +} + +static inline void *hif_runtime_pm_prevent_suspend_init(const char *name) +{ + return NULL; +} + +static inline void hif_runtime_pm_prevent_suspend_deinit(void *context) +{ +} + +static inline void hif_request_runtime_pm_resume(void *ol_sc) +{ +} +#endif + +#endif /* _HIF_H_ */ diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif_internal.h b/drivers/net/wireless/qca402x/hif_sdio/hif_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..8b4c11e290249a3016da0b3c35d026c9e1c6d34c --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif_internal.h @@ -0,0 +1,117 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#ifndef _HIF_INTERNAL_H_ +#define _HIF_INTERNAL_H_ + +#include "hif.h" +#include "hif_sdio_common.h" + +/* Make this large enough to avoid ever failing due to lack of bus requests. + * A number that accounts for the total number of credits on the Target plus + * outstanding register requests is good. + * + * FUTURE: could dyanamically allocate busrequest structs as needed. + * FUTURE: would be nice for HIF to use HTCA's htca_request. Seems + * wasteful to use multiple structures -- one for HTCA and another + * for HIF -- and to copy info from one to the other. Maybe should + * semi-merge these layers? + */ +#define BUS_REQUEST_MAX_NUM 128 + +#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000 /* TBD: Can support 50000000 + * on real HW? + */ +#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20 +#define FLAGS_CARD_ENAB 0x02 +#define FLAGS_CARD_IRQ_UNMSK 0x04 + +/* The block size is an attribute of the SDIO function which is + * shared by all four mailboxes. We cannot support per-mailbox + * block sizes over SDIO. + */ +#define HIF_MBOX_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE +#define HIF_MBOX0_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE + +struct bus_request { + /*struct bus_request*/ void *next; /* link list of available requests */ + struct completion comp_req; + u32 address; /* request data */ + u8 *buffer; + u32 length; + u32 req_type; + void *context; + int status; +}; + +struct hif_device { + struct sdio_func *func; + + /* Main HIF task */ + struct task_struct *hif_task; /* task to handle SDIO requests */ + wait_queue_head_t hif_wait; + int hif_task_work; /* Signals HIFtask that there is work */ + int hif_shutdown; /* signals HIFtask to stop */ + struct completion hif_exit; /* HIFtask completion */ + + /* HIF Completion task */ + /* task to handle SDIO completions */ + struct task_struct *completion_task; + wait_queue_head_t completion_wait; + int completion_work; + int completion_shutdown; + struct completion completion_exit; + + /* pending request queue */ + spinlock_t req_qlock; + struct bus_request *req_qhead; /* head of request queue */ + struct bus_request *req_qtail; /* tail of request queue */ + + /* completed request queue */ + spinlock_t compl_qlock; + struct bus_request *compl_qhead; + struct bus_request *compl_qtail; + + /* request free list */ + spinlock_t req_free_qlock; + struct bus_request *bus_req_free_qhead; /* free queue */ + + /* Space for requests, initially queued to busRequestFreeQueue */ + struct bus_request bus_request[BUS_REQUEST_MAX_NUM]; + + void *claimed_context; + struct cbs_from_hif + cbs_from_hif; /* Callbacks made from HIF to caller */ + bool is_enabled; /* device is currently enabled? */ + bool is_intr_enb; /* interrupts are currently unmasked at + * Host - dbg only + */ + int irq_handling; /* currently processing interrupts */ + const struct sdio_device_id *id; + struct mmc_host *host; + void *context; + bool ctrl_response_timeout; + /* for debug; links hif device back to caller (e.g.HTCA target) */ + void *caller_handle; +}; + +#define CMD53_FIXED_ADDRESS 1 +#define CMD53_INCR_ADDRESS 2 + +#endif /* _HIF_INTERNAL_H_ */ diff --git a/drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h b/drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h new file mode 100644 index 0000000000000000000000000000000000000000..c325c068d11df5faf6bd6ff68a11031877f94382 --- /dev/null +++ b/drivers/net/wireless/qca402x/hif_sdio/hif_sdio_common.h @@ -0,0 +1,43 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* This file was originally distributed by Qualcomm Atheros, Inc. + * before Copyright ownership was assigned to the Linux Foundation. + */ + +#ifndef _HIF_SDIO_COMMON_H_ +#define _HIF_SDIO_COMMON_H_ + +/* The purpose of these blocks is to amortize SDIO command setup time + * across multiple bytes of data. In byte mode, we must issue a command + * for each byte. In block mode, we issue a command (8B?) for each + * BLOCK_SIZE bytes. + * + * Every mailbox read/write must be padded to this block size. If the + * value is too large, we spend more time sending padding bytes over + * SDIO. If the value is too small we see less benefit from amortizing + * the cost of a command across data bytes. + */ +#define HIF_DEFAULT_IO_BLOCK_SIZE 256 + +#define FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868 +#define FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF +#define FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000 + +/* Vendor Specific Driver Strength Settings */ +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xf2 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK 0x0e +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08 + +#endif /* _HIF_SDIO_COMMON_H_ */ diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca.h b/drivers/net/wireless/qca402x/htca_mbox/htca.h new file mode 100644 index 0000000000000000000000000000000000000000..ce2e0eb888985966ade693eb8adc738dc67011e1 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Host-Target Communication API */ + +#ifndef _HTCA_H_ +#define _HTCA_H_ + +#define DEBUG +#undef DEBUG + +/* The HTCA API is independent of the underlying interconnect and + * independent of the protocols used across that interconnect. + */ + +#define HTCA_OK 0 /* Success */ +#define HTCA_ERROR 1 /* generic error */ +#define HTCA_EINVAL 2 /* Invalid parameter */ +#define HTCA_ECANCELED 3 /* Operation canceled */ +#define HTCA_EPROTO 4 /* Protocol error */ +#define HTCA_ENOMEM 5 /* Memory exhausted */ + +/* Note: An Endpoint ID is always Interconnect-relative. So we + * are likely to see the same Endpoint ID with different Targets + * on a multi-Target system. + */ +#define HTCA_EP_UNUSED (0xff) + +#define HTCA_EVENT_UNUSED 0 + +/* Start global events */ +#define HTCA_EVENT_GLOBAL_START 1 +#define HTCA_EVENT_TARGET_AVAILABLE 1 +#define HTCA_EVENT_TARGET_UNAVAILABLE 2 +#define HTCA_EVENT_GLOBAL_END 2 +#define HTCA_EVENT_GLOBAL_COUNT \ + (HTCA_EVENT_GLOBAL_END - HTCA_EVENT_GLOBAL_START + 1) +/* End global events */ + +/* Start endpoint-specific events */ +#define HTCA_EVENT_EP_START 3 +#define HTCA_EVENT_BUFFER_RECEIVED 3 +#define HTCA_EVENT_BUFFER_SENT 4 +#define HTCA_EVENT_DATA_AVAILABLE 5 +#define HTCA_EVENT_EP_END 5 +#define HTCA_EVENT_EP_COUNT (HTCA_EVENT_EP_END - HTCA_EVENT_EP_START + 1) +/* End endpoint-specific events */ + +/* Maximum size of an HTC header across relevant implementations + * (e.g. across interconnect types and platforms and OSes of interest). + * + * Callers of HTC must leave HTCA_HEADER_LEN_MAX bytes + * reserved BEFORE the start of a buffer passed to HTCA htca_buffer_send + * AT the start of a buffer passed to HTCBufferReceive + * for use by HTC itself. + * + * FUTURE: Investigate ways to remove the need for callers to accommodate + * for HTC headers.* Doesn't seem that hard to do....just tack on the + * length in a separate buffer and send buffer pairs to HIF. When extracting, + * first pull header then pull payload into paired buffers. + */ + +#define HTCA_HEADER_LEN_MAX 2 + +struct htca_event_info { + u8 *buffer; + void *cookie; + u32 buffer_length; + u32 actual_length; + int status; +}; + +typedef void (*htca_event_handler)(void *target, + u8 ep, + u8 event_id, + struct htca_event_info *event_info, + void *context); + +int htca_init(void); + +void htca_shutdown(void); + +int htca_start(void *target); + +void htca_stop(void *target); + +int htca_event_reg(void *target, + u8 end_point_id, + u8 event_id, + htca_event_handler event_handler, void *context); + +/* Notes: + * buffer should be multiple of blocksize. + * buffer should be large enough for header+largest message, rounded up to + * blocksize. + * buffer passed in should be start of the buffer -- where header will go. + * length should be full length, including header. + * On completion, buffer points to start of payload (AFTER header). + * On completion, actual_length is the length of payload. Does not include + * header nor padding. On completion, buffer_length matches the length that + * was passed in here. + */ +int htca_buffer_receive(void *target, + u8 end_point_id, u8 *buffer, + u32 length, void *cookie); + +/* Notes: + * buffer should be multiple of blocksize. + * buffer passed in should be start of payload; header will be tacked on BEFORE + * this. + * extra bytes will be sent, padding the message to blocksize. + * length should be the number of payload bytes to be sent. + * The actual number of bytes that go over SDIO is length+header, rounded up to + * blocksize. + * On completion, buffer points to start of payload (AFTER header). + * On completion, actual_length is the length of payload. Does not include + * header nor padding. On completion buffer_length is irrelevant. + */ +int htca_buffer_send(void *target, + u8 end_point_id, + u8 *buffer, u32 length, void *cookie); + +#endif /* _HTCA_H_ */ diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c new file mode 100644 index 0000000000000000000000000000000000000000..fbf3549c06ebfe17435d0dd94288afc0bec07e37 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox.c @@ -0,0 +1,497 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Implementation of Host Target Communication + * API v1 and HTCA Protocol v1 + * over Qualcomm QCA mailbox-based SDIO/SPI interconnects. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +struct htca_target *htca_target_list[HTCA_NUM_DEVICES_MAX]; + +/* Single thread module initialization, module shutdown, + * target start and target stop. + */ +static DEFINE_MUTEX(htca_startup_mutex); +static bool htca_initialized; + +/* Initialize the HTCA software module. + * Typically invoked exactly once. + */ +int htca_init(void) +{ + struct cbs_from_os callbacks; + + if (mutex_lock_interruptible(&htca_startup_mutex)) + return HTCA_ERROR; /* interrupted */ + + if (htca_initialized) { + mutex_unlock(&htca_startup_mutex); + return HTCA_OK; /* Already initialized */ + } + + htca_initialized = true; + + htca_event_table_init(); + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.dev_inserted_hdl = htca_target_inserted_handler; + callbacks.dev_removed_hdl = htca_target_removed_handler; + hif_init(&callbacks); + + mutex_unlock(&htca_startup_mutex); + + return HTCA_OK; +} + +/* Shutdown the entire module and free all module data. + * Inverse of htca_init. + * + * May be invoked only after all Targets are stopped. + */ +void htca_shutdown(void) +{ + int i; + + if (mutex_lock_interruptible(&htca_startup_mutex)) + return; /* interrupted */ + + if (!htca_initialized) { + mutex_unlock(&htca_startup_mutex); + return; /* Not initialized, so nothing to shut down */ + } + + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + if (htca_target_instance(i)) { + /* One or more Targets are still active -- + * cannot shutdown software. + */ + mutex_unlock(&htca_startup_mutex); + WARN_ON(1); + return; + } + } + + hif_shutdown_device(NULL); /* Tell HIF that we're all done */ + htca_initialized = false; + + mutex_unlock(&htca_startup_mutex); +} + +/* Start a Target. This typically happens once per Target after + * the module has been initialized and a Target is powered on. + * + * When a Target starts, it posts a single credit to each mailbox + * and it enters "HTCA configuration". During configuration + * negotiation, block sizes for each HTCA endpoint are established + * that both Host and Target agree. Once this is complete, the + * Target starts normal operation so it can send/receive. + */ +int htca_start(void *tar) +{ + int status; + u32 address; + struct htca_target *target = (struct htca_target *)tar; + + mutex_lock(&htca_startup_mutex); + + if (!htca_initialized) { + mutex_unlock(&htca_startup_mutex); + return HTCA_ERROR; + } + + init_waitqueue_head(&target->target_init_wait); + + /* Unmask Host controller interrupts associated with this Target */ + hif_un_mask_interrupt(target->hif_handle); + + /* Enable all interrupts of interest on the Target. */ + + target->enb.int_status_enb = INT_STATUS_ENABLE_ERROR_SET(0x01) | + INT_STATUS_ENABLE_CPU_SET(0x01) | + INT_STATUS_ENABLE_COUNTER_SET(0x01) | + INT_STATUS_ENABLE_MBOX_DATA_SET(0x0F); + + target->enb.cpu_int_status_enb = CPU_INT_STATUS_ENABLE_BIT_SET(0x00); + + target->enb.err_status_enb = + ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) | + ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01); + + target->enb.counter_int_status_enb = + COUNTER_INT_STATUS_ENABLE_BIT_SET(0xFF); + + /* Commit interrupt register values to Target HW. */ + address = get_reg_addr(INTR_ENB_REG, ENDPOINT_UNUSED); + status = + hif_read_write(target->hif_handle, address, &target->enb, + sizeof(target->enb), HIF_WR_SYNC_BYTE_INC, NULL); + if (status != HIF_OK) { + _htca_stop(target); + mutex_unlock(&htca_startup_mutex); + return HTCA_ERROR; + } + + /* At this point, we're waiting for the Target to post + * 1 credit to each mailbox. This allows us to begin + * configuration negotiation. We should see an interrupt + * as soon as the first credit is posted. The remaining + * credits should be posted almost immediately after. + */ + + /* Wait indefinitely until configuration negotiation with + * the Target completes and the Target tells us it is ready to go. + */ + if (!target->ready) { + /* NB: Retain the htca_statup_mutex during this wait. + * This serializes startup but should be OK. + */ + + wait_event_interruptible(target->target_init_wait, + target->ready); + + if (target->ready) { + status = HTCA_OK; + } else { + status = HTCA_ERROR; + _htca_stop(target); + } + } + + mutex_unlock(&htca_startup_mutex); + return status; +} + +void _htca_stop(struct htca_target *target) +{ + uint ep; + struct htca_endpoint *end_point; + u32 address; + + /* Note: htca_startup_mutex must be held on entry */ + if (!htca_initialized) + return; + + htca_work_task_stop(target); + + /* Disable interrupts at source, on Target */ + target->enb.int_status_enb = 0; + target->enb.cpu_int_status_enb = 0; + target->enb.err_status_enb = 0; + target->enb.counter_int_status_enb = 0; + + address = get_reg_addr(INTR_ENB_REG, ENDPOINT_UNUSED); + + /* Try to disable all interrupts on the Target. */ + (void)hif_read_write(target->hif_handle, address, &target->enb, + sizeof(target->enb), HIF_WR_SYNC_BYTE_INC, NULL); + + /* Disable Host controller interrupts */ + hif_mask_interrupt(target->hif_handle); + + /* Flush all the queues and return the buffers to their owner */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + unsigned long flags; + + end_point = &target->end_point[ep]; + + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + end_point->tx_credits_available = 0; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + + end_point->enabled = false; + + /* Flush the Pending Receive Queue */ + htca_mbox_queue_flush(end_point, &end_point->recv_pending_queue, + &end_point->recv_free_queue, + HTCA_EVENT_BUFFER_RECEIVED); + + /* Flush the Pending Send Queue */ + htca_mbox_queue_flush(end_point, &end_point->send_pending_queue, + &end_point->send_free_queue, + HTCA_EVENT_BUFFER_SENT); + } + + target->ready = false; + + hif_detach(target->hif_handle); + + /* Remove this Target from the global list */ + htca_target_instance_remove(target); + + /* Free target memory */ + kfree(target); +} + +void htca_stop(void *tar) +{ + struct htca_target *target = (struct htca_target *)tar; + + htca_work_task_stop(target); + htca_compl_task_stop(target); + + mutex_lock(&htca_startup_mutex); + _htca_stop(target); + mutex_unlock(&htca_startup_mutex); +} + +/* Provides an interface for the caller to register for + * various events supported by the HTCA module. + */ +int htca_event_reg(void *tar, + u8 end_point_id, + u8 event_id, + htca_event_handler event_handler, void *param) +{ + int status; + struct htca_endpoint *end_point; + struct htca_event_info event_info; + struct htca_target *target = (struct htca_target *)tar; + + /* Register a new handler BEFORE dispatching events. + * UNregister a handler AFTER dispatching events. + */ + if (event_handler) { + /* Register a new event handler */ + + status = htca_add_to_event_table(target, end_point_id, event_id, + event_handler, param); + if (status != HTCA_OK) + return status; /* Fail to register handler */ + } + + /* Handle events associated with this handler */ + switch (event_id) { + case HTCA_EVENT_TARGET_AVAILABLE: + if (event_handler) { + struct htca_target *targ; + int i; + + /* Dispatch a Target Available event for all Targets + * that are already present. + */ + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + targ = htca_target_list[i]; + if (targ) { + size_t size = hif_get_device_size(); + + htca_frame_event(&event_info, + (u8 *)targ->hif_handle, + size, size, + HTCA_OK, NULL); + + htca_dispatch_event( + targ, ENDPOINT_UNUSED, + HTCA_EVENT_TARGET_AVAILABLE, + &event_info); + } + } + } + break; + + case HTCA_EVENT_TARGET_UNAVAILABLE: + break; + + case HTCA_EVENT_BUFFER_RECEIVED: + if (!event_handler) { + /* Flush the Pending Recv queue before unregistering + * the event handler. + */ + end_point = &target->end_point[end_point_id]; + htca_mbox_queue_flush(end_point, + &end_point->recv_pending_queue, + &end_point->recv_free_queue, + HTCA_EVENT_BUFFER_RECEIVED); + } + break; + + case HTCA_EVENT_BUFFER_SENT: + if (!event_handler) { + /* Flush the Pending Send queue before unregistering + * the event handler. + */ + end_point = &target->end_point[end_point_id]; + htca_mbox_queue_flush(end_point, + &end_point->send_pending_queue, + &end_point->send_free_queue, + HTCA_EVENT_BUFFER_SENT); + } + break; + + case HTCA_EVENT_DATA_AVAILABLE: + /* We could dispatch a data available event. Instead, + * we require users to register this event handler + * before posting receive buffers. + */ + break; + + default: + return HTCA_EINVAL; /* unknown event? */ + } + + if (!event_handler) { + /* Unregister an event handler */ + status = htca_remove_from_event_table(target, + end_point_id, event_id); + if (status != HTCA_OK) + return status; + } + + return HTCA_OK; +} + +/* Enqueue to the endpoint's recv_pending_queue an empty buffer + * which will receive data from the Target. + */ +int htca_buffer_receive(void *tar, + u8 end_point_id, u8 *buffer, + u32 length, void *cookie) +{ + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request; + struct htca_event_table_element *ev; + unsigned long flags; + struct htca_target *target = (struct htca_target *)tar; + + end_point = &target->end_point[end_point_id]; + + if (!end_point->enabled) + return HTCA_ERROR; + + /* Length must be a multiple of block_size. + * (Ideally, length should match the largest message that can be sent + * over this endpoint, including HTCA header, rounded up to blocksize.) + */ + if (length % end_point->block_size) + return HTCA_EINVAL; + + if (length > HTCA_MESSAGE_SIZE_MAX) + return HTCA_EINVAL; + + if (length < HTCA_HEADER_LEN_MAX) + return HTCA_EINVAL; + + ev = htca_event_id_to_event(target, end_point_id, + HTCA_EVENT_BUFFER_RECEIVED); + if (!ev->handler) { + /* In order to use this API, caller must + * register an event handler for HTCA_EVENT_BUFFER_RECEIVED. + */ + return HTCA_ERROR; + } + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = (struct htca_mbox_request *)htca_request_deq_head( + &end_point->recv_free_queue); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + if (!mbox_request) + return HTCA_ENOMEM; + + if (WARN_ON(mbox_request->req.target != target)) + return HTCA_ERROR; + + mbox_request->buffer = buffer; + /* includes space for HTCA header */ + mbox_request->buffer_length = length; + /* filled in after message is received */ + mbox_request->actual_length = 0; + mbox_request->end_point = end_point; + mbox_request->cookie = cookie; + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->recv_pending_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + /* Alert the work_task that there may be work to do */ + htca_work_task_poke(target); + + return HTCA_OK; +} + +/* Enqueue a buffer to be sent to the Target. + * + * Supplied buffer must be preceded by HTCA_HEADER_LEN_MAX bytes for the + * HTCA header (of which HTCA_HEADER_LEN bytes are actually used, and the + * remaining are padding). + * + * Must be followed with sufficient space for block-size padding. + * + * Example: + * To send a 10B message over an endpoint that uses 64B blocks, caller + * specifies length=10. HTCA adds HTCA_HEADER_LEN_MAX bytes just before + * buffer, consisting of HTCA_HEADER_LEN header bytes followed by + * HTCA_HEADER_LEN_MAX-HTCA_HEADER_LEN pad bytes. HTC sends blockSize + * bytes starting at buffer-HTCA_HEADER_LEN_MAX. + */ +int htca_buffer_send(void *tar, + u8 end_point_id, + u8 *buffer, u32 length, void *cookie) +{ + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request; + struct htca_event_table_element *ev; + unsigned long flags; + struct htca_target *target = (struct htca_target *)tar; + + end_point = &target->end_point[end_point_id]; + + if (!end_point->enabled) + return HTCA_ERROR; + + if (length + HTCA_HEADER_LEN_MAX > HTCA_MESSAGE_SIZE_MAX) + return HTCA_EINVAL; + + ev = htca_event_id_to_event(target, end_point_id, + HTCA_EVENT_BUFFER_SENT); + if (!ev->handler) { + /* In order to use this API, caller must + * register an event handler for HTCA_EVENT_BUFFER_SENT. + */ + return HTCA_ERROR; + } + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = (struct htca_mbox_request *)htca_request_deq_head( + &end_point->send_free_queue); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + if (!mbox_request) + return HTCA_ENOMEM; + + /* Buffer will be adjusted by HTCA_HEADER_LEN later, in + * htca_send_request_to_hif. + */ + mbox_request->buffer = buffer; + mbox_request->buffer_length = length; + mbox_request->actual_length = length; + mbox_request->end_point = end_point; + mbox_request->cookie = cookie; + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->send_pending_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + /* Alert the work_task that there may be work to do */ + htca_work_task_poke(target); + + return HTCA_OK; +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c new file mode 100644 index 0000000000000000000000000000000000000000..c7f8e953412ceb037aaa1188856795e709a13516 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_compl.c @@ -0,0 +1,503 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Host Target Communications Completion Management */ + +/* Top-level callback handler, registered with HIF to be invoked + * whenever a read/write HIF operation completes. Executed in the + * context of an HIF task, so we don't want to take much time + * here. Pass processing to HTCA's compl_task. + * + * Used for both reg_requests and mbox_requests. + */ +int htca_rw_completion_handler(void *context, int status) +{ + struct htca_request *req; + struct htca_target *target; + unsigned long flags; + + req = (struct htca_request *)context; + if (!context) { + /* No completion required for this request. + * (e.g. Fire-and-forget register write.) + */ + return HTCA_OK; + } + + target = req->target; + req->status = status; + + /* Enqueue this completed request on the + * Target completion queue. + */ + spin_lock_irqsave(&target->compl_queue_lock, flags); + htca_request_enq_tail(&target->compl_queue, (struct htca_request *)req); + spin_unlock_irqrestore(&target->compl_queue_lock, flags); + + /* Notify the completion task that it has work */ + htca_compl_task_poke(target); + + return HTCA_OK; +} + +/* Request-specific callback invoked by the HTCA Completion Task + * when a Mbox Send Request completes. Note: Used for Mbox Send + * requests; not used for Reg requests. + * + * Simply dispatch a BUFFER_SENT event to the originator of the request. + */ +void htca_send_compl(struct htca_request *req, int status) +{ + struct htca_target *target; + u8 end_point_id; + struct htca_event_info event_info; + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request = + (struct htca_mbox_request *)req; + unsigned long flags; + + end_point = mbox_request->end_point; + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + + /* Strip off the HTCA header that was added earlier */ + mbox_request->buffer += HTCA_HEADER_LEN_MAX; + + /* Prepare event frame to notify caller */ + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, + (status == HIF_OK) ? HTCA_OK : HTCA_ECANCELED, + mbox_request->cookie); + + /* Recycle the request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->send_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + /* Regardless of success/failure, notify caller that HTCA is done + * with his buffer. + */ + htca_dispatch_event(target, end_point_id, HTCA_EVENT_BUFFER_SENT, + &event_info); +} + +/* Request-specific callback invoked by the HTCA Completion Task + * when a Mbox Recv Request completes. Note: Used for Mbox Recv + * requests; not used for Reg requests. + * + * Simply dispatch a BUFFER_RECEIVED event to the originator + * of the request. + */ +void htca_recv_compl(struct htca_request *req, int status) +{ + struct htca_target *target; + struct htca_event_info event_info; + u8 end_point_id; + struct htca_endpoint *end_point; + struct htca_mbox_request *mbox_request = + (struct htca_mbox_request *)req; + unsigned long flags; + + end_point = mbox_request->end_point; + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + + /* Signaling: + * Now that we have consumed recv data, clar rx_frame_length so that + * htca_manage_pending_recvs will not try to re-read the same data. + * + * Set need_register_refresh so we can determine whether or not there + * is additional data waiting to be read. + * + * Clear our endpoint from the pending_recv_mask so + * htca_manage_pending_recvs + * is free to issue another read. + * + * Finally, poke the work_task. + */ + end_point->rx_frame_length = 0; + target->need_register_refresh = 1; + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_recv_mask &= ~(1 << end_point_id); + spin_unlock_irqrestore(&target->pending_op_lock, flags); + htca_work_task_poke(target); + + if (status == HIF_OK) { + u32 check_length; + /* Length coming from Target is always LittleEndian */ + check_length = ((mbox_request->buffer[0] << 0) | + (mbox_request->buffer[1] << 8)); + WARN_ON(mbox_request->actual_length != check_length); + } + + /* Strip off header */ + mbox_request->buffer += HTCA_HEADER_LEN_MAX; + + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, + (status == HIF_OK) ? HTCA_OK : HTCA_ECANCELED, + mbox_request->cookie); + + /* Recycle the request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->recv_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + htca_dispatch_event(target, end_point_id, HTCA_EVENT_BUFFER_RECEIVED, + &event_info); +} + +/* Request-specific callback invoked when a register read/write + * request completes. reg_request structures are not used for + * register WRITE requests so there's not much to do for writes. + * + * Note: For Mbox Request completions see htca_send_compl + * and htca_recv_compl. + */ + +/* Request-specific callback invoked by the HTCA Completion Task + * when a Reg Request completes. Note: Used for Reg requests; + * not used for Mbox requests. + */ +void htca_reg_compl(struct htca_request *req, int status) +{ + struct htca_target *target; + struct htca_reg_request *reg_request = (struct htca_reg_request *)req; + unsigned long flags; + + if (WARN_ON(!reg_request)) + return; + + htcadebug("purpose=0x%x\n", reg_request->purpose); + + /* Process async register read/write completion */ + + target = reg_request->req.target; + if (status != HIF_OK) { + /* Recycle the request */ + reg_request->purpose = UNUSED_PURPOSE; + spin_lock_irqsave(&target->reg_queue_lock, flags); + htca_request_enq_tail(&target->reg_free_queue, + (struct htca_request *)reg_request); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + + /* A register read/write accepted by HIF + * should never fail. + */ + WARN_ON(1); + return; + } + + switch (reg_request->purpose) { + case INTR_REFRESH: + /* Target register state, including interrupt + * registers, has been fetched. + */ + htca_register_refresh_compl(target, reg_request); + break; + + case CREDIT_REFRESH: + htca_credit_refresh_compl(target, reg_request); + break; + + case UPDATE_TARG_INTRS: + case UPDATE_TARG_AND_ENABLE_HOST_INTRS: + htca_update_intr_enbs_compl(target, reg_request); + break; + + default: + WARN_ON(1); /* unhandled request type */ + break; + } + + /* Recycle this register read/write request */ + reg_request->purpose = UNUSED_PURPOSE; + spin_lock_irqsave(&target->reg_queue_lock, flags); + htca_request_enq_tail(&target->reg_free_queue, + (struct htca_request *)reg_request); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); +} + +/* After a Register Refresh, uppdate tx_credits_to_reap for each end_point. */ +static void htca_update_tx_credits_to_reap(struct htca_target *target, + struct htca_reg_request *reg_request) +{ + struct htca_endpoint *end_point; + int ep; + + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + + if (reg_request->u.reg_table.status.counter_int_status & + (0x10 << ep)) { + end_point->tx_credits_to_reap = true; + } else { + end_point->tx_credits_to_reap = false; + } + } +} + +/* After a Register Refresh, uppdate rx_frame_length for each end_point. */ +static void htca_update_rx_frame_lengths(struct htca_target *target, + struct htca_reg_request *reg_request) +{ + struct htca_endpoint *end_point; + u32 rx_lookahead; + u32 frame_length; + int ep; + + htcadebug("Enter\n"); + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + + if (end_point->rx_frame_length != 0) { + /* NB: Will be cleared in htca_recv_compl after + * frame is read + */ + continue; + } + + if (!(reg_request->u.reg_table.rx_lookahead_valid & + (1 << ep))) { + continue; + } + + /* The length of the incoming message is contained + * in the first two (HTCA_HEADER_LEN) bytes in + * LittleEndian order. + * + * This length does NOT include the HTCA header nor block + * padding. + */ + rx_lookahead = reg_request->u.reg_table.rx_lookahead[ep]; + frame_length = rx_lookahead & 0x0000ffff; + + end_point->rx_frame_length = frame_length; + htcadebug("ep#%d : %d\n", ep, + frame_length); + } +} + +static unsigned int htca_debug_no_pending; /* debug only */ + +/* Completion for a register refresh. + * + * Update rxFrameLengths and tx_credits_to_reap info for + * each endpoint. Then handle all pending interrupts (o + * if interrupts are currently masked at the Host, handle + * all interrupts that would be pending if interrupts + * were enabled). + * + * Called in the context of HIF's completion task whenever + * results from a register refresh are received. + */ +void htca_register_refresh_compl(struct htca_target *target, + struct htca_reg_request *req) +{ + u8 host_int_status; + u8 pnd_enb_intrs; /* pending and enabled interrupts */ + u8 pending_int; + u8 enabled_int; + unsigned long flags; + + htcadebug("Enter\n"); + + if (WARN_ON(target->pending_register_refresh == 0)) + return; + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_register_refresh--; + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + htcadebug( + "REGDUMP: hostis=0x%02x cpuis=0x%02x erris=0x%02x cntris=0x%02x\n", + req->u.reg_table.status.host_int_status, + req->u.reg_table.status.cpu_int_status, + req->u.reg_table.status.err_int_status, + req->u.reg_table.status.counter_int_status); + htcadebug( + "mbox_frame=0x%02x lav=0x%02x la0=0x%08x la1=0x%08x la2=0x%08x la3=0x%08x\n", + req->u.reg_table.mbox_frame, req->u.reg_table.rx_lookahead_valid, + req->u.reg_table.rx_lookahead[0], req->u.reg_table.rx_lookahead[1], + req->u.reg_table.rx_lookahead[2], req->u.reg_table.rx_lookahead[3]); + + /* Update rxFrameLengths */ + htca_update_rx_frame_lengths(target, req); + + /* Update tx_credits_to_reap */ + htca_update_tx_credits_to_reap(target, req); + + /* Process pending Target interrupts. */ + + /* Restrict attention to pending interrupts of interest */ + host_int_status = req->u.reg_table.status.host_int_status; + + /* Unexpected and unhandled */ + if (WARN_ON(host_int_status & HOST_INT_STATUS_DRAGON_INT_MASK)) + return; + + /* Form software's idea of pending and enabled interrupts. + * Start with ERRORs and CPU interrupts. + */ + pnd_enb_intrs = host_int_status & + (HOST_INT_STATUS_ERROR_MASK | HOST_INT_STATUS_CPU_MASK); + + /* Software may have intended to enable/disable credit + * counter interrupts; but we commit these updates to + * Target hardware lazily, just before re-enabling + * interrupts. So registers that we have now may not + * reflect the intended state of interrupt enables. + */ + + /* Based on software credit enable bits, update pnd_enb_intrs + * (which is like a software copy of host_int_status) as if + * all desired interrupt enables had been committed to HW. + */ + pending_int = req->u.reg_table.status.counter_int_status; + enabled_int = target->enb.counter_int_status_enb; + if (pending_int & enabled_int) + pnd_enb_intrs |= HOST_INT_STATUS_COUNTER_MASK; + + /* Based on software recv data enable bits, update + * pnd_enb_intrs AS IF all the interrupt enables had + * been committed to HW. + */ + pending_int = host_int_status; + enabled_int = target->enb.int_status_enb; + pnd_enb_intrs |= (pending_int & enabled_int); + + if (!pnd_enb_intrs) { + /* No enabled interrupts are pending. */ + htca_debug_no_pending++; + } + + /* Invoke specific handlers for each enabled and pending interrupt. + * The goal of each service routine is to clear interrupts at the + * source (on the Target). + * + * We deal with four types of interrupts in the HOST_INT_STATUS + * summary register: + * errors + * This remains set until bits in ERROR_INT_STATUS are cleared + * + * CPU + * This remains set until bits in CPU_INT_STATUS are cleared + * + * rx data available + * These remain set as long as rx data is available. HW clears + * the rx data available enable bits when receive buffers + * are exhausted. If we exhaust Host-side received buffers, we + * mask the rx data available interrupt. + * + * tx credits available + * This remains set until all bits in COUNTER_INT_STATUS are + * cleared by HW after Host SW reaps all credits on a mailbox. + * If credits on an endpoint are sufficient, we mask the + * corresponding COUNTER_INT_STATUS bit. We avoid "dribbling" + * one credit at a time and instead reap them en masse. + * + * The HOST_INT_STATUS register is read-only these bits are cleared + * by HW when the underlying condition is cleared. + */ + + if (HOST_INT_STATUS_ERROR_GET(pnd_enb_intrs)) + htca_service_error_interrupt(target, req); + + if (HOST_INT_STATUS_CPU_GET(pnd_enb_intrs)) + htca_service_cpu_interrupt(target, req); + + if (HOST_INT_STATUS_COUNTER_GET(pnd_enb_intrs)) + htca_service_credit_counter_interrupt(target, req); + + /* Always needed in order to at least unmask Host interrupts */ + htca_work_task_poke(target); +} + +/* Complete an update of interrupt enables. */ +void htca_update_intr_enbs_compl(struct htca_target *target, + struct htca_reg_request *req) +{ + htcadebug("Enter\n"); + if (req->purpose == UPDATE_TARG_AND_ENABLE_HOST_INTRS) { + /* NB: non-intuitive, but correct */ + + /* While waiting for rxdata and txcred + * interrupts to be disabled at the Target, + * we temporarily masked interrupts at + * the Host. It is now safe to allow + * interrupts (esp. ERROR and CPU) at + * the Host. + */ + htcadebug("Unmasking\n"); + hif_un_mask_interrupt(target->hif_handle); + } +} + +/* Called to complete htca_credit_refresh_start. + * + * Ends a credit refresh cycle. Called after decrementing a + * credit counter register (many times in a row). HW atomically + * decrements the counter and returns the OLD value but HW will + * never reduce it below 0. + * + * Called in the context of the work_task when the credit counter + * decrement operation completes synchronously. Called in the + * context of the compl_task when the credit counter decrement + * operation completes asynchronously. + */ +void htca_credit_refresh_compl(struct htca_target *target, + struct htca_reg_request *reg_request) +{ + struct htca_endpoint *end_point; + unsigned long flags; + int reaped; + int i; + + /* A non-zero value indicates 1 credit reaped. + * Typically, we will find monotonically descending + * values that reach 0 with the remaining values + * all zero. But we must scan the entire results + * to handle the case where the Target just happened + * to increment credits simultaneously with our + * series of credit decrement operations. + */ + htcadebug("ep=%d\n", reg_request->epid); + end_point = &target->end_point[reg_request->epid]; + reaped = 0; + for (i = 0; i < HTCA_TX_CREDITS_REAP_MAX; i++) { + htcadebug("|R0x%02x", reg_request->u.credit_dec_results[i]); + if (reg_request->u.credit_dec_results[i]) + reaped++; + } + + htcadebug("\nreaped %d credits on ep=%d\n", reaped, reg_request->epid); + + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + end_point->tx_credits_available += reaped; + end_point->tx_credit_refresh_in_progress = false; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + + htca_work_task_poke(target); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c new file mode 100644 index 0000000000000000000000000000000000000000..d034277f2e9f975a9988352863eee492f58b0528 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_events.c @@ -0,0 +1,130 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Host Target Communications Event Management */ + +/* Protect all event tables -- global as well as per-endpoint. */ +static spinlock_t event_lock; /* protects all event tables */ + +/* Mapping table for global events -- avail/unavail */ +static struct htca_event_table_element + global_event_table[HTCA_EVENT_GLOBAL_COUNT]; + +struct htca_event_table_element * +htca_event_id_to_event(struct htca_target *target, + u8 end_point_id, + u8 event_id) +{ + struct htca_event_table_element *ev = NULL; + + /* is ep event */ + if ((event_id >= HTCA_EVENT_EP_START) && + (event_id <= HTCA_EVENT_EP_END)) { + struct htca_endpoint *end_point; + int ep_evid; + + ep_evid = event_id - HTCA_EVENT_EP_START; + end_point = &target->end_point[end_point_id]; + ev = &end_point->endpoint_event_tbl[ep_evid]; + /* is global event */ + } else if ((event_id >= HTCA_EVENT_GLOBAL_START) && + (event_id <= HTCA_EVENT_GLOBAL_END)) { + int global_evid; + + global_evid = event_id - HTCA_EVENT_GLOBAL_START; + ev = &global_event_table[global_evid]; + } else { + WARN_ON(1); /* unknown event */ + } + + return ev; +} + +void htca_dispatch_event(struct htca_target *target, + u8 end_point_id, + u8 event_id, + struct htca_event_info *event_info) +{ + struct htca_event_table_element *ev; + + ev = htca_event_id_to_event(target, end_point_id, event_id); + if (!ev) { + panic("BUG"); + return; + } + if (ev->handler) { + htca_event_handler handler; + void *param; + unsigned long flags; + + spin_lock_irqsave(&event_lock, flags); + handler = ev->handler; + param = ev->param; + spin_unlock_irqrestore(&event_lock, flags); + + handler((void *)target, end_point_id, event_id, + event_info, param); + } +} + +int htca_add_to_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id, + htca_event_handler handler, void *param) { + struct htca_event_table_element *ev; + unsigned long flags; + + ev = htca_event_id_to_event(target, end_point_id, event_id); + if (!ev) + return HTCA_ERROR; + + spin_lock_irqsave(&event_lock, flags); + ev->handler = handler; + ev->param = param; + spin_unlock_irqrestore(&event_lock, flags); + + return HTCA_OK; +} + +int htca_remove_from_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id) { + struct htca_event_table_element *ev; + unsigned long flags; + + ev = htca_event_id_to_event(target, end_point_id, event_id); + if (!ev) + return HTCA_ERROR; + + spin_lock_irqsave(&event_lock, flags); + /* Clear event handler info */ + memset(ev, 0, sizeof(*ev)); + spin_unlock_irqrestore(&event_lock, flags); + + return HTCA_OK; +} + +/* Called once during module initialization */ +void htca_event_table_init(void) +{ + spin_lock_init(&event_lock); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..b1c7c6bbc6a8c126a5980b30312b4604b95a4592 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_internal.h @@ -0,0 +1,581 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _HTCA_INTERNAL_H_ +#define _HTCA_INTERNAL_H_ + +#include "mbox_host_reg.h" + +#if defined(DEBUG) +#define htcadebug(fmt, a...) \ + pr_err("htca %s:%d: " fmt, __func__, __LINE__, ##a) +#else +#define htcadebug(args...) +#endif + +/* HTCA internal specific declarations and prototypes */ + +/* Target-side SDIO/SPI (mbox) controller supplies 4 mailboxes */ +#define HTCA_NUM_MBOX 4 + +/* Software supports at most this many Target devices */ +#define HTCA_NUM_DEVICES_MAX 2 + +/* Maximum supported mailbox message size. + * + * Quartz' SDIO/SPI mailbox alias spaces are 2KB each; so changes + * would be required to exceed that. WLAN restricts packets to + * under 1500B. + */ +#define HTCA_MESSAGE_SIZE_MAX 2048 + +#define HTCA_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ + +/* The maximum number of credits that we will reap + * from the Target at one time. + */ +#define HTCA_TX_CREDITS_REAP_MAX 8 + +/* Mailbox address in SDIO address space */ +#define MBOX_BASE_ADDR 0x800 /* Start of MBOX alias spaces */ +#define MBOX_WIDTH 0x800 /* Width of each mailbox alias space */ + +#define MBOX_START_ADDR(mbox) (MBOX_BASE_ADDR + ((mbox) * (MBOX_WIDTH))) + +/* The byte just before this causes an EndOfMessage interrupt to be generated */ +#define MBOX_END_ADDR(mbox) (MBOX_START_ADDR(mbox) + MBOX_WIDTH) + +/* extended MBOX address for larger MBOX writes to MBOX 0 (not used) */ +#define MBOX0_EXTENDED_BASE_ADDR 0x2800 +#define MBOX0_EXTENDED_WIDTH (6 * 1024) + +/* HTCA message header */ +struct HTCA_header { + u16 total_msg_length; +} __packed; + +#define HTCA_HEADER_LEN sizeof(struct HTCA_header) + +/* Populate an htca_event_info structure to be passed to + * a user's event handler. + */ +static inline void htca_frame_event(struct htca_event_info *event_info, + u8 *buffer, size_t buffer_length, + size_t actual_length, u32 status, + void *cookie) +{ + if (event_info) { + event_info->buffer = buffer; + event_info->buffer_length = buffer_length; + event_info->actual_length = actual_length; + event_info->status = status; + event_info->cookie = cookie; + } +} + +/* Global and endpoint-specific event tables use these to + * map an event ID --> handler + param. + */ +struct htca_event_table_element { + htca_event_handler handler; + void *param; +}; + +/* This layout MUST MATCH Target hardware layout! */ +struct htca_intr_status { + u8 host_int_status; + u8 cpu_int_status; + u8 err_int_status; + u8 counter_int_status; +} __packed; + +/* This layout MUST MATCH Target hardware layout! */ +struct htca_intr_enables { + u8 int_status_enb; + u8 cpu_int_status_enb; + u8 err_status_enb; + u8 counter_int_status_enb; +} __packed; + +/* The Register table contains Target SDIO/SPI interrupt/rxstatus + * registers used by HTCA. Rather than read particular registers, + * we use a bulk "register refresh" to read all at once. + * + * This layout MUST MATCH Target hardware layout! + */ +struct htca_register_table { + struct htca_intr_status status; + + u8 mbox_frame; + u8 rx_lookahead_valid; + u8 hole[2]; + + /* Four lookahead bytes for each mailbox */ + u32 rx_lookahead[HTCA_NUM_MBOX]; +} __packed; + +/* Two types of requests/responses are supported: + * "mbox requests" are messages or data which + * are sent to a Target mailbox + * "register requests" are to read/write Target registers + * + * Mbox requests are managed with a per-endpoint + * pending list and free list. + * + * Register requests are managed with a per-Target + * pending list and free list. + * + * A generic HTCA request -- one which is either an + * htca_mbox_request or an htca_reg_request is represented + * by an htca_request. + */ + +/* Number of mbox_requests and reg_requests allocated initially. */ +#define HTCA_MBOX_REQUEST_COUNT 16 /* per mailbox */ +#define HTCA_REG_REQUEST_COUNT (4 * HTCA_NUM_MBOX) /* per target */ + +/* An htca_request is at the start of a mbox_request structure + * and at the start of a reg_request structure. + * + * Specific request types may be cast to a generic htca_request + * (e.g. in order to invoke the completion callback function) + */ +struct htca_request { + /*struct htca_request*/ void *next; /* linkage */ + struct htca_target *target; + void (*completion_cb)(struct htca_request *req, int status); + int status; /* completion status from HIF */ +}; + +struct htca_endpoint; /* forward reference */ + +/* Mailbox request -- a message or bulk data */ +struct htca_mbox_request { + struct htca_request req; /* Must be first -- (cast to htca_request) */ + + /* Caller-supplied cookie associated with this request */ + void *cookie; + + /* Pointer to the start of the buffer. In the transmit + * direction this points to the start of the payload. In the + * receive direction, however, the buffer when queued up + * points to the start of the HTCA header but when returned + * to the caller points to the start of the payload + * + * Note: buffer is set to NULL whenever this request is free. + */ + u8 *buffer; + + /* length, in bytes, of the buffer */ + u32 buffer_length; + + /* length, in bytes, of the payload within the buffer */ + u32 actual_length; + + struct htca_endpoint *end_point; +}; + +/* Round up a value (e.g. length) to a power of 2 (e.g. block size). */ +static inline u32 htca_round_up(u32 value, u32 pwrof2) +{ + return (((value) + (pwrof2) - 1) & ~((pwrof2) - 1)); +} + +/* Indicates reasons that we might access Target register space */ +enum htca_req_purpose { + UNUSED_PURPOSE, + INTR_REFRESH, /* Fetch latest interrupt/status registers */ + CREDIT_REFRESH, /* Reap credits */ + UPDATE_TARG_INTRS, + UPDATE_TARG_AND_ENABLE_HOST_INTRS, +}; + +/* Register read request -- used to read registers from SDIO/SPI space. + * Register writes are fire and forget; no completion is needed. + * + */ +struct htca_reg_request { + struct htca_request req; /* Must be first -- (cast to htca_request) */ + u8 *buffer; /* register value(s) */ + u32 length; + + /* Indicates the purpose this request was made */ + enum htca_req_purpose purpose; + + /* Which endpoint this read is for. + * Used when processing a completed credit refresh request. + */ + u8 epid; /* which endpoint ID [0..3] */ + + /* A read to Target register space returns + * one specific Target register value OR + * all values in the register_table OR + * a special repeated read-and-dec from a credit register + * + * FUTURE: We could separate these into separate request + * types in order to perhaps save a bit of space.... + * eliminate the union. + */ + union { + struct htca_intr_enables enb; + struct htca_register_table reg_table; + u8 credit_dec_results[HTCA_TX_CREDITS_REAP_MAX]; + } u; +}; + +struct htca_request_queue { + struct htca_request *head; + struct htca_request *tail; +}; + +#define HTCA_IS_QUEUE_EMPTY(q) (!((q)->head)) + +/* List of Target registers in SDIO/SPI space which can be accessed by Host */ +enum target_registers { + UNUSED_REG = 0, + INTR_ENB_REG = INT_STATUS_ENABLE_ADDRESS, + ALL_STATUS_REG = HOST_INT_STATUS_ADDRESS, + ERROR_INT_STATUS_REG = ERROR_INT_STATUS_ADDRESS, + CPU_INT_STATUS_REG = CPU_INT_STATUS_ADDRESS, + TX_CREDIT_COUNTER_DECREMENT_REG = COUNT_DEC_ADDRESS, + INT_TARGET_REG = INT_TARGET_ADDRESS, +}; + +static inline u32 get_reg_addr(enum target_registers which, + u8 epid) +{ + return (((which) == TX_CREDIT_COUNTER_DECREMENT_REG) + ? (COUNT_DEC_ADDRESS + (HTCA_NUM_MBOX + (epid)) * 4) + : (which)); +} + +/* FUTURE: See if we can use lock-free operations + * to manage credits and linked lists. + * FUTURE: Use standard Linux queue ops; ESPECIALLY + * if they support lock-free operation. + */ + +/* One of these per endpoint */ +struct htca_endpoint { + /* Enabled or Disabled */ + bool enabled; + + /* If data is available, rxLengthPending + * indicates the length of the incoming message. + */ + u32 rx_frame_length; /* incoming frame length on this endpoint */ + /* includes HTCA header */ + /* Modified only by compl_task */ + + bool rx_data_alerted; /* Caller was sent a BUFFER_AVAILABLE event */ + /* and has not supplied a new recv buffer */ + /* since that warning was sent. */ + /* Modified only by work_task */ + + bool tx_credits_to_reap; /* At least one credit available at the */ + /* Target waiting to be reaped. */ + /* Modified only by compl_task */ + + /* Guards tx_credits_available and tx_credit_refresh_in_progress */ + spinlock_t tx_credit_lock; + + /* The number of credits that we have already reaped + * from the Target. (i.e. we have decremented the Target's + * count register so that we have ability to send future + * messages). We have the ability to send tx_credits_available + * messages without blocking. + * + * The size of a message is endpoint-dependent and always + * a multiple of the device's block_size. + */ + u32 tx_credits_available; + + /* Maximum message size */ + u32 max_msg_sz; + + /* Indicates that we are in the midst of a credit refresh cycle */ + bool tx_credit_refresh_in_progress; + + /* Free/Pending Send/Recv queues are used for mbox requests. + * An mbox Send request cannot be given to HIF until we have + * a tx credit. An mbox Recv request cannot be given to HIF + * until we have a pending rx msg. + * + * The HIF layer maintains its own queue of requests, which + * it uses to serialize access to SDIO. Its queue contains + * a mixture of sends/recvs and mbox/reg requests. HIF is + * "beyond" flow control so once a requets is given to HIF + * it is guaranteed to complete (after all previous requests + * complete). + */ + + /* Guards Free/Pending send/recv queues */ + spinlock_t mbox_queue_lock; + struct htca_request_queue send_free_queue; + struct htca_request_queue send_pending_queue; + struct htca_request_queue recv_free_queue; + struct htca_request_queue recv_pending_queue; + + /* Inverse reference to the target */ + struct htca_target *target; + + /* Block size configured for the endpoint -- common across all endpoints + */ + u32 block_size; + + /* Mapping table for per-endpoint events */ + struct htca_event_table_element endpoint_event_tbl[HTCA_EVENT_EP_COUNT]; + + /* Location of the endpoint's mailbox space */ + u32 mbox_start_addr; + u32 mbox_end_addr; +}; + +#define ENDPOINT_UNUSED 0 + +/* Target interrupt states. */ +enum intr_state_e { + /* rxdata and txcred interrupts enabled. + * Only the DSR context can switch us to + * polled state. + */ + HTCA_INTERRUPT, + + /* rxdata and txcred interrupts are disabled. + * We are polling (via RegisterRefresh). + * Only the work_task can switch us to + * interrupt state. + */ + HTCA_POLL, +}; + +/* One of these per connected QCA402X device. */ +struct htca_target { + /* Target device is initialized and ready to go? + * This has little o do with Host state; + * it reflects readiness of the Target. + */ + bool ready; + + /* Handle passed to HIF layer for SDIO/SPI Host controller access */ + void *hif_handle; /* hif_device */ + + /* Per-endpoint info */ + struct htca_endpoint end_point[HTCA_NUM_MBOX]; + + /* Used during startup while the Host waits for the + * Target to initialize. + */ + wait_queue_head_t target_init_wait; + + /* Free queue for htca_reg_requests. + * + * We don't need a regPendingQueue because reads/writes to + * Target register space are not flow controlled by the Target. + * There is no need to wait for credits in order to hand off a + * register read/write to HIF. + * + * The register read/write may end up queued in a HIF queue + * behind both register and mbox reads/writes that were + * handed to HIF earlier. But they will never be queued + * by HTCA. + */ + spinlock_t reg_queue_lock; + struct htca_request_queue reg_free_queue; + + /* comp task synchronization */ + struct mutex task_mutex; + + struct task_struct *work_task; + struct task_struct *compl_task; + + /* work_task synchronization */ + wait_queue_head_t work_task_wait; /* wait for work to do */ + bool work_task_has_work; /* work available? */ + bool work_task_shutdown; /* requested stop? */ + struct completion work_task_completion; + + /* compl_task synchronization */ + wait_queue_head_t compl_task_wait; /* wait for work to do */ + bool compl_task_has_work; /* work available? */ + bool compl_task_shutdown; /* requested stop? */ + struct completion compl_cask_completion; + + /* Queue of completed mailbox and register requests */ + spinlock_t compl_queue_lock; + struct htca_request_queue compl_queue; + + /* Software's shadow copy of interrupt enables. + * Only the work_task changes intr_enable bits, + * so no locking necessary. + * + * Committed to Target HW when + * we convert from polling to interrupts or + * we are using interrupts and enables have changed + */ + struct htca_intr_enables enb; + struct htca_intr_enables last_committed_enb; + + enum intr_state_e intr_state; + int need_start_polling; + + /* Set after we read data from a mailbox (to + * update lookahead and mailbox status bits). + * used only by work_task even though refreshes + * may be started in other contexts. + */ + int need_register_refresh; + + /* Guards pending_register_refresh and pending_recv_mask */ + spinlock_t pending_op_lock; + + /* Incremented when a RegisterRefresh is started; + * Decremented when it completes. + */ + int pending_register_refresh; + + /* Non-zero if a recv operation has been started + * but not yet completed. 1 bit for each ep. + */ + int pending_recv_mask; +}; + +/* Convert an endpoint POINTER into an endpoint ID [0..3] */ +static inline u32 get_endpoint_id(struct htca_endpoint *ep) +{ + return (u32)(ep - ep->target->end_point); +} + +void htca_receive_frame(struct htca_endpoint *end_point); + +u32 htca_get_frame_length(struct htca_endpoint *end_point); + +void htca_send_frame(struct htca_endpoint *end_point); + +void htca_send_blk_size(struct htca_endpoint *end_point); + +int htca_rw_completion_handler(void *req, int status); + +void htca_send_compl(struct htca_request *req, int status); + +void htca_recv_compl(struct htca_request *req, int status); + +void htca_reg_compl(struct htca_request *req, int status); + +int htca_target_inserted_handler(void *context, + void *hif_handle); + +int htca_target_removed_handler(void *context, void *hif_handle); + +int htca_dsr_handler(void *target_ctxt); + +void htca_service_cpu_interrupt(struct htca_target *target, + struct htca_reg_request *req); + +void htca_service_error_interrupt(struct htca_target *target, + struct htca_reg_request *req); + +void htca_service_credit_counter_interrupt(struct htca_target *target, + struct htca_reg_request *req); + +void htca_enable_credit_counter_interrupt(struct htca_target *target, + u8 end_point_id); + +void htca_disable_credit_counter_interrupt(struct htca_target *target, + u8 end_point_id); + +int htca_add_to_mbox_queue(struct htca_mbox_request *queue, + u8 *buffer, + u32 buffer_length, + u32 actual_length, void *cookie); + +struct htca_mbox_request * +htca_remove_from_mbox_queue(struct htca_mbox_request *queue); + +void htca_mbox_queue_flush(struct htca_endpoint *end_point, + struct htca_request_queue *pending_queue, + struct htca_request_queue *free_queue, + u8 event_id); + +int htca_add_to_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id, + htca_event_handler handler, + void *param); + +int htca_remove_from_event_table(struct htca_target *target, + u8 end_point_id, + u8 event_id); + +void htca_dispatch_event(struct htca_target *target, + u8 end_point_id, + u8 event_id, + struct htca_event_info *event_info); + +struct htca_target *htca_target_instance(int i); + +void htca_target_instance_add(struct htca_target *target); + +void htca_target_instance_remove(struct htca_target *target); + +u8 htca_get_bit_num_set(u32 data); + +void htca_register_refresh(struct htca_target *target); + +void free_request(struct htca_request *req, + struct htca_request_queue *queue); + +extern struct htca_target *htca_target_list[HTCA_NUM_DEVICES_MAX]; + +int htca_work_task_start(struct htca_target *target); +int htca_compl_task_start(struct htca_target *target); +void htca_work_task_stop(struct htca_target *target); +void htca_compl_task_stop(struct htca_target *target); +void htca_work_task_poke(struct htca_target *target); +void htca_compl_task_poke(struct htca_target *target); + +void htca_event_table_init(void); +struct htca_event_table_element * +htca_event_id_to_event(struct htca_target *target, + u8 end_point_id, + u8 event_id); + +void htca_request_enq_tail(struct htca_request_queue *queue, + struct htca_request *req); +struct htca_request *htca_request_deq_head(struct htca_request_queue *queue); + +void htca_register_refresh_start(struct htca_target *target); +void htca_register_refresh_compl(struct htca_target *target, + struct htca_reg_request *req); + +int htca_credit_refresh_start(struct htca_endpoint *end_point); +void htca_credit_refresh_compl(struct htca_target *target, + struct htca_reg_request *req); + +void htca_update_intr_enbs(struct htca_target *target, + int enable_host_intrs); +void htca_update_intr_enbs_compl(struct htca_target *target, + struct htca_reg_request *req); + +bool htca_negotiate_config(struct htca_target *target); + +int htca_recv_request_to_hif(struct htca_endpoint *end_point, + struct htca_mbox_request *mbox_request); +int htca_send_request_to_hif(struct htca_endpoint *endpoint, + struct htca_mbox_request *mbox_request); + +int htca_manage_pending_sends(struct htca_target *target, int epid); +int htca_manage_pending_recvs(struct htca_target *target, int epid); + +void _htca_stop(struct htca_target *target); + +#endif /* _HTCA_INTERNAL_H_ */ diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c new file mode 100644 index 0000000000000000000000000000000000000000..0486f5974a4ef20121fef80311a1b1ae99609a07 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_intr.c @@ -0,0 +1,627 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Host Target Communications Interrupt Management */ + +/* Interrupt Management + * When an interrupt occurs at the Host, it is to tell us about + * a high-priority error interrupt + * a CPU interrupt (TBD) + * rx data available + * tx credits available + * + * From an interrupt management perspective, rxdata and txcred + * interrupts are grouped together. When either of these occurs, + * we enter a mode where we repeatedly refresh register state + * and act on all interrupt information in the refreshed registers. + * We are basically polling with rxdata and txcred interrupts + * masked. Eventually, we refresh registers and find no rxdata + * and no txcred interrupts pending. At this point, we unmask + * those types of interrupts. + * + * Unmasking is selective: We unmask only the interrupts that + * we want to receive which include + * -rxdata interrupts for endpoints that have received + * buffers on the recv pending queue + * -txcred interrupts for endpoints with a very low + * count of creditsAvailable + * Other rxdata and txcred interrupts are masked. These include: + * -rxdata interrupts for endpoint that lack recv buffers + * -txcred interrupts for endpoint with lots of credits + * + * Very little activity takes place in the context of the + * interrupt function (Delayed Service Routine). We mask + * interrupts at the Host, send a command to disable all + * rxdata/txcred interrupts and finally start a register + * refresh. When the register refresh completes, we unmask + * interrupts on the Host and poke the work_task which now + * has valid register state to examine. + * + * The work_task repeatedly + * handles outstanding rx and tx service + * starts another register refresh + * Every time a register refresh completes, it pokes the + * work_task. This cycle continues until the work_task finds + * nothing to do after a register refresh. At this point, + * it unmasks rxdata/txcred interrupts at the Target (again, + * selectively). + * + * While in the work_task polling cycle, we maintain a notion + * of interrupt enables in software rather than commit these + * to Target HW. + * + * + * Credit State Machine: + * Credits are + * -Added by the Target whenever a Target-side receive + * buffer is added to a mailbox + * -Never rescinded by the Target + * -Reaped by this software after a credit refresh cycle + * which is initiated + * -as a result of a credit counter interrupt + * -after a send completes and the number of credits + * are below an acceptable threshold + * -used by this software when it sends a message HIF to + * be sent to the Target + * + * The process of "reaping" credits involves first issuing + * a sequence of reads to the COUNTER_DEC register. (This is + * known as the start of a credit refresh.) We issue a large + * number of reads in order to reap as many credits at once + * as we can. When these reads complete, we determine how + * many credits were available and increase software's notion + * of tx_credits_available accordingly. + * + * Note: All Target reads/writes issued from the interrupt path + * should be asynchronous. HIF adds such a request to a queue + * and immediately returns. + * + * TBD: It might be helpful for HIF to support a "priority + * queue" -- requests that should be issued prior to anything + * in its normal queue. Even with this, a request might have + * to wait for a while as the current, read/write request + * completes on SDIO and then wait for all prior priority + * requests to finish. So probably not worth the additional + * complexity. + */ + +/* Maximum message sizes for each endpoint. + * Must be a multiple of the block size. + * Must be no greater than HTCA_MESSAGE_SIZE_MAX. + * + * TBD: These should be tunable. Example anticipated usage: + * ep0: Host-side networking control messages + * ep1: Host-side networking data messages + * ep2: OEM control messages + * ep3: OEM data messages + */ +static u32 htca_msg_size[HTCA_NUM_MBOX] = {256, 3 * 512, 512, 2048}; + +/* Commit the shadow interrupt enables in software to + * Target Hardware. This is where the "lazy commit" + * occurs. Always called in the context of work_task. + * + * When the host's intr_state is POLL: + * -All credit count interrupts and all rx data interrupts + * are disabled at the Target. + * + * When the host's intr_state is INTERRUPT: + * -We commit the shadow copy of interrupt enables. + * -A mailbox with low credit count will have the credit + * interrupt enabled. A mailbox with high credit count + * will have the credit interrupt disabled. + * -A mailbox with no available receive buffers will have + * the mailbox data interrupt disabled. A mailbox with + * at least one receive buffer will have the mailbox + * data interrupt enabled. + */ +void htca_update_intr_enbs(struct htca_target *target, + int enable_host_intrs) +{ + int status; + struct htca_reg_request *reg_request; + struct htca_intr_enables *enbregs; + unsigned long flags; + u32 address; + + htcadebug("Enter: enable_host_intrs=%d\n", + enable_host_intrs); + htcadebug("ints: 0x%02x --> 0x%02x\n", + target->last_committed_enb.int_status_enb, + target->enb.int_status_enb); + htcadebug("cpu: 0x%02x --> 0x%02x\n", + target->last_committed_enb.cpu_int_status_enb, + target->enb.cpu_int_status_enb); + htcadebug("error: 0x%02x --> 0x%02x\n", + target->last_committed_enb.err_status_enb, + target->enb.err_status_enb); + htcadebug("counters: 0x%02x --> 0x%02x\n", + target->last_committed_enb.counter_int_status_enb, + target->enb.counter_int_status_enb); + if ((target->enb.int_status_enb == + target->last_committed_enb.int_status_enb) && + (target->enb.counter_int_status_enb == + target->last_committed_enb.counter_int_status_enb) && + (target->enb.cpu_int_status_enb == + target->last_committed_enb.cpu_int_status_enb) && + (target->enb.err_status_enb == + target->last_committed_enb.err_status_enb)) { + /* No changes to Target-side interrupt enables are required. + * But we must still need to enable Host-side interrupts. + */ + if (enable_host_intrs) { + htcadebug("Unmasking - no change to Target enables\n"); + hif_un_mask_interrupt(target->hif_handle); + } + return; + } + + spin_lock_irqsave(&target->reg_queue_lock, flags); + reg_request = (struct htca_reg_request *)htca_request_deq_head( + &target->reg_free_queue); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + if (!reg_request) { + WARN_ON(1); + return; + } + if (WARN_ON(reg_request->purpose != UNUSED_PURPOSE)) + return; + + reg_request->buffer = NULL; + reg_request->length = 0; + reg_request->epid = 0; /* unused */ + enbregs = ®_request->u.enb; + + if (target->intr_state == HTCA_INTERRUPT) { + enbregs->int_status_enb = target->enb.int_status_enb; + enbregs->counter_int_status_enb = + target->enb.counter_int_status_enb; + } else { + enbregs->int_status_enb = (target->enb.int_status_enb & + ~HOST_INT_STATUS_MBOX_DATA_MASK); + enbregs->counter_int_status_enb = 0; + } + + enbregs->cpu_int_status_enb = target->enb.cpu_int_status_enb; + enbregs->err_status_enb = target->enb.err_status_enb; + + target->last_committed_enb = *enbregs; /* structure copy */ + + if (enable_host_intrs) + reg_request->purpose = UPDATE_TARG_AND_ENABLE_HOST_INTRS; + else + reg_request->purpose = UPDATE_TARG_INTRS; + + address = get_reg_addr(INTR_ENB_REG, ENDPOINT_UNUSED); + + status = hif_read_write(target->hif_handle, address, enbregs, + sizeof(*enbregs), HIF_WR_ASYNC_BYTE_INC, + reg_request); + if (status == HIF_OK && reg_request->req.completion_cb) { + reg_request->req.completion_cb( + (struct htca_request *)reg_request, HIF_OK); + /* htca_update_intr_enbs_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + WARN_ON(1); + } +} + +/* Delayed Service Routine, invoked from HIF in thread context + * (from sdio's irqhandler) in order to handle interrupts + * caused by the Target. + * + * This serves as a top-level interrupt dispatcher for HTCA. + */ +int htca_dsr_handler(void *htca_handle) +{ + struct htca_target *target = (struct htca_target *)htca_handle; + + htcadebug("Enter\n"); + if (target->ready) { + /* Transition state to polling mode. + * Temporarily disable intrs at Host + * until interrupts are stopped in + * Target HW. + */ + htcadebug("Masking interrupts\n"); + hif_mask_interrupt(target->hif_handle); + target->need_start_polling = 1; + + /* Kick off a register refresh so we + * use updated registers in order to + * figure out what needs to be serviced. + * + * RegisterRefresh completion wakes the + * work_task which re-enables Host-side + * interrupts. + */ + htca_register_refresh_start(target); + } else { /* startup time */ + /* Assumption is that we are receiving an interrupt + * because the Target made a TX Credit available + * on each endpoint (for configuration negotiation). + */ + + hif_mask_interrupt(target->hif_handle); + if (htca_negotiate_config(target)) { + /* All endpoints are configured. + * Target is now ready for normal operation. + */ + /* TBDXXX - Fix Quartz-side and remove this */ + { + /* HACK: Signal Target to read mbox Cfg info. + * TBD: Target should use EOM rather than an + * an explicit Target Interrupt for this. + */ + u8 my_targ_int; + u32 address; + int status; + + /* Set HTCA_INT_TARGET_INIT_HOST_REQ */ + my_targ_int = 1; + + address = + get_reg_addr( + INT_TARGET_REG, ENDPOINT_UNUSED); + status = hif_read_write( + target->hif_handle, address, &my_targ_int, + sizeof(my_targ_int), HIF_WR_SYNC_BYTE_INC, + NULL); + if (WARN_ON(status != HIF_OK)) + return status; + } + target->ready = true; + htcadebug("HTCA TARGET IS READY\n"); + wake_up(&target->target_init_wait); + } + hif_un_mask_interrupt(target->hif_handle); + } + return HTCA_OK; +} + +/* Handler for CPU interrupts that are explicitly + * initiated by Target firmware. Not used by system firmware today. + */ +void htca_service_cpu_interrupt(struct htca_target *target, + struct htca_reg_request *req) +{ + int status; + u32 address; + u8 cpu_int_status; + + htcadebug("Enter\n"); + cpu_int_status = req->u.reg_table.status.cpu_int_status & + target->enb.cpu_int_status_enb; + + /* Clear pending interrupts on Target -- Write 1 to Clear */ + address = get_reg_addr(CPU_INT_STATUS_REG, ENDPOINT_UNUSED); + + status = + hif_read_write(target->hif_handle, address, &cpu_int_status, + sizeof(cpu_int_status), HIF_WR_SYNC_BYTE_INC, NULL); + + WARN_ON(status != HIF_OK); + + /* Handle cpu_int_status actions here. None are currently used */ +} + +/* Handler for error interrupts on Target. + * If everything is working properly we hope never to see these. + */ +void htca_service_error_interrupt(struct htca_target *target, + struct htca_reg_request *req) +{ + int status = HIF_ERROR; + u32 address; + u8 err_int_status; + struct htca_endpoint *end_point; + + htcadebug("Enter\n"); + err_int_status = + req->u.reg_table.status.err_int_status & target->enb.err_status_enb; + + end_point = &target->end_point[req->epid]; + htcadebug("epid=%d txCreditsAvailable=%d\n", + (int)req->epid, end_point->tx_credits_available); + htcadebug("statusregs host=0x%02x cpu=0x%02x err=0x%02x cnt=0x%02x\n", + req->u.reg_table.status.host_int_status, + req->u.reg_table.status.cpu_int_status, + req->u.reg_table.status.err_int_status, + req->u.reg_table.status.counter_int_status); + + /* Clear pending interrupts on Target -- Write 1 to Clear */ + address = get_reg_addr(ERROR_INT_STATUS_REG, ENDPOINT_UNUSED); + status = + hif_read_write(target->hif_handle, address, &err_int_status, + sizeof(err_int_status), HIF_WR_SYNC_BYTE_INC, NULL); + + if (WARN_ON(status != HIF_OK)) + return; + + if (ERROR_INT_STATUS_WAKEUP_GET(err_int_status)) { + /* Wakeup */ + htcadebug("statusregs host=0x%x\n", + ERROR_INT_STATUS_WAKEUP_GET(err_int_status)); + /* Nothing needed here */ + } + + if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(err_int_status)) { + /* TBD: Rx Underflow */ + /* Host posted a read to an empty mailbox? */ + /* Target DMA was not able to keep pace with Host reads? */ + if (WARN_ON(2)) /* TBD */ + return; + } + + if (ERROR_INT_STATUS_TX_OVERFLOW_GET(err_int_status)) { + /* TBD: Tx Overflow */ + /* Host posted a write to a mailbox with no credits? */ + /* Target DMA was not able to keep pace with Host writes? */ + if (WARN_ON(1)) /* TBD */ + return; + } +} + +/* Handler for Credit Counter interrupts from Target. + * + * This occurs when the number of credits available on a mailbox + * increases from 0 to non-zero. (i.e. when Target firmware queues a + * DMA Receive buffer to an endpoint that previously had no buffers.) + * + * This interrupt is masked when we have a sufficient number of + * credits available. It is unmasked only when we have reaped all + * available credits and are still below a desired threshold. + */ +void htca_service_credit_counter_interrupt(struct htca_target *target, + struct htca_reg_request *req) +{ + struct htca_endpoint *end_point; + u8 counter_int_status; + u8 eps_with_credits; + int ep; + + htcadebug("Enter\n"); + counter_int_status = req->u.reg_table.status.counter_int_status; + + /* Service the credit counter interrupt. + * COUNTER bits [4..7] are used for credits on endpoints [0..3]. + */ + eps_with_credits = + counter_int_status & target->enb.counter_int_status_enb; + htcadebug("eps_with_credits=0x%02x\n", eps_with_credits); + htcadebug("counter_int_status=0x%02x\n", counter_int_status); + htcadebug("counter_int_status_enb=0x%02x\n", + target->enb.counter_int_status_enb); + + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + if (!(eps_with_credits & (0x10 << ep))) + continue; + + end_point = &target->end_point[ep]; + + /* We need credits on this endpoint AND + * the target tells us that there are some. + * Start a credit refresh cycle on this + * endpoint. + */ + (void)htca_credit_refresh_start(end_point); + } +} + +/* Callback registered with HIF to be invoked when Target + * presence is first detected. + * + * Allocate memory for Target, endpoints, requests, etc. + */ +int htca_target_inserted_handler(void *unused_context, + void *hif_handle) +{ + struct htca_target *target; + struct htca_endpoint *end_point; + int ep; + struct htca_event_info event_info; + struct htca_request_queue *send_free_queue, *recv_free_queue; + struct htca_request_queue *reg_queue; + u32 block_size[HTCA_NUM_MBOX]; + struct cbs_from_hif htca_callbacks; /* Callbacks from HIF to HTCA */ + int status = HTCA_OK; + int i; + + htcadebug("Enter\n"); + + target = kzalloc(sizeof(*target), GFP_KERNEL); + /* target->ready = false; */ + + /* Give a handle to HIF for this target */ + target->hif_handle = hif_handle; + hif_set_handle(hif_handle, (void *)target); + + /* Register htca_callbacks from HIF */ + memset(&htca_callbacks, 0, sizeof(htca_callbacks)); + htca_callbacks.rw_completion_hdl = htca_rw_completion_handler; + htca_callbacks.dsr_hdl = htca_dsr_handler; + htca_callbacks.context = target; + (void)hif_attach(hif_handle, &htca_callbacks); + + /* Get block sizes and start addresses for each mailbox */ + hif_configure_device(hif_handle, + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, &block_size, + sizeof(block_size)); + + /* Initial software copies of interrupt enables */ + target->enb.int_status_enb = + INT_STATUS_ENABLE_ERROR_MASK | INT_STATUS_ENABLE_CPU_MASK | + INT_STATUS_ENABLE_COUNTER_MASK | INT_STATUS_ENABLE_MBOX_DATA_MASK; + + /* All 8 CPU interrupts enabled */ + target->enb.cpu_int_status_enb = CPU_INT_STATUS_ENABLE_BIT_MASK; + + target->enb.err_status_enb = ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK | + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK; + + /* credit counters in upper bits */ + target->enb.counter_int_status_enb = COUNTER_INT_STATUS_ENABLE_BIT_MASK; + + spin_lock_init(&target->reg_queue_lock); + spin_lock_init(&target->compl_queue_lock); + spin_lock_init(&target->pending_op_lock); + mutex_init(&target->task_mutex); + + status = htca_work_task_start(target); + if (status != HTCA_OK) + goto done; + + status = htca_compl_task_start(target); + if (status != HTCA_OK) + goto done; + + /* Initialize the register request free list */ + reg_queue = &target->reg_free_queue; + for (i = 0; i < HTCA_REG_REQUEST_COUNT; i++) { + struct htca_reg_request *reg_request; + + /* Add a reg_request to the Reg Free Queue */ + reg_request = kzalloc(sizeof(*reg_request), GFP_DMA); + reg_request->req.target = target; + reg_request->req.completion_cb = htca_reg_compl; + + /* no lock required -- startup */ + htca_request_enq_tail(reg_queue, + (struct htca_request *)reg_request); + } + + /* Initialize endpoints, mbox queues and event tables */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + + spin_lock_init(&end_point->tx_credit_lock); + spin_lock_init(&end_point->mbox_queue_lock); + + end_point->tx_credits_available = 0; + end_point->max_msg_sz = htca_msg_size[ep]; + end_point->rx_frame_length = 0; + end_point->tx_credits_to_reap = false; + end_point->target = target; + end_point->enabled = false; + end_point->block_size = block_size[ep]; + end_point->mbox_start_addr = MBOX_START_ADDR(ep); + end_point->mbox_end_addr = MBOX_END_ADDR(ep); + + /* Initialize per-endpoint queues */ + end_point->send_pending_queue.head = NULL; + end_point->send_pending_queue.tail = NULL; + end_point->recv_pending_queue.head = NULL; + end_point->recv_pending_queue.tail = NULL; + + send_free_queue = &end_point->send_free_queue; + recv_free_queue = &end_point->recv_free_queue; + for (i = 0; i < HTCA_MBOX_REQUEST_COUNT; i++) { + struct htca_mbox_request *mbox_request; + + /* Add an mbox_request to the mbox SEND Free Queue */ + mbox_request = kzalloc(sizeof(*mbox_request), + GFP_KERNEL); + mbox_request->req.target = target; + mbox_request->req.completion_cb = htca_send_compl; + mbox_request->end_point = end_point; + htca_request_enq_tail( + send_free_queue, + (struct htca_request *)mbox_request); + + /* Add an mbox_request to the mbox RECV Free Queue */ + mbox_request = kzalloc(sizeof(*mbox_request), + GFP_KERNEL); + mbox_request->req.target = target; + mbox_request->req.completion_cb = htca_recv_compl; + mbox_request->end_point = end_point; + htca_request_enq_tail( + recv_free_queue, + (struct htca_request *)mbox_request); + } + } + + /* Target and endpoint structures are now completely initialized. + * Add the target instance to the global list of targets. + */ + htca_target_instance_add(target); + + /* Frame a TARGET_AVAILABLE event and send it to + * the caller. Return the hif_device handle as a + * parameter with the event. + */ + htca_frame_event(&event_info, (u8 *)hif_handle, + hif_get_device_size(), + hif_get_device_size(), HTCA_OK, NULL); + htca_dispatch_event(target, ENDPOINT_UNUSED, + HTCA_EVENT_TARGET_AVAILABLE, &event_info); + +done: + return status; +} + +/* Callback registered with HIF to be invoked when Target + * is removed + * + * Also see htca_stop + * Stop tasks + * Free memory for Target, endpoints, requests, etc. + * + * TBD: Not yet supported + */ +int htca_target_removed_handler(void *unused_context, + void *htca_handle) +{ + struct htca_target *target = (struct htca_target *)htca_handle; + struct htca_event_info event_info; + struct htca_endpoint *end_point; + int ep; + + htcadebug("Enter\n"); + /* Disable each of the endpoints to stop accepting requests. */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + end_point->enabled = false; + } + + if (target) { + /* Frame a TARGET_UNAVAILABLE event and send it to the host */ + htca_frame_event(&event_info, NULL, 0, 0, HTCA_OK, NULL); + htca_dispatch_event(target, ENDPOINT_UNUSED, + HTCA_EVENT_TARGET_UNAVAILABLE, &event_info); + } + + /* TBD: call htca_stop? */ + /* TBD: Must be sure that nothing is going on before we free. */ + if (WARN_ON(1)) /* TBD */ + return HTCA_ERROR; + + /* Free everything allocated earlier, including target + * structure and all request structures. + */ + /* TBD: kfree .... */ + + return HTCA_OK; +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c new file mode 100644 index 0000000000000000000000000000000000000000..0d4eae81025273223cb62654b607468b4f088fec --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_recv.c @@ -0,0 +1,205 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* If there is data available to read on the specified mailbox, + * pull a Mailbox Recv Request off of the PendingRecv queue + * and request HIF to pull data from the mailbox into the + * request's recv buffer. + * + * If we are not aware of data waiting on the endpoint, simply + * return. Note that our awareness is based on slightly stale + * data from Quartz registers. Upper layers insure that we are + * called shortly after data becomes available on an endpoint. + * + * If we exhaust receive buffers, disable the mailbox's interrupt + * until additional buffers are available. + * + * Returns 0 if no request was sent to HIF + * returns 1 if at least one request was sent to HIF + */ +int htca_manage_pending_recvs(struct htca_target *target, int epid) +{ + struct htca_endpoint *end_point; + struct htca_request_queue *recv_queue; + struct htca_mbox_request *mbox_request; + u32 rx_frame_length; + unsigned long flags; + int work_done = 0; + + if (target->pending_recv_mask & (1 << epid)) { + /* Receive operation is already in progress on this endpoint */ + return 0; + } + + end_point = &target->end_point[epid]; + + /* Hand off requests as long as we have both + * something to recv into + * data waiting to be read on the mailbox + */ + + /* rx_frame_length of 0 --> nothing waiting; otherwise, it's + * the length of data waiting to be read, NOT including + * HTCA header nor block padding. + */ + rx_frame_length = end_point->rx_frame_length; + + recv_queue = &end_point->recv_pending_queue; + if (HTCA_IS_QUEUE_EMPTY(recv_queue)) { + htcadebug("no recv buff for ep#%d\n", epid); + /* Not interested in rxdata interrupts + * since we have no recv buffers. + */ + target->enb.int_status_enb &= ~(1 << epid); + + if (rx_frame_length) { + struct htca_event_info event_info; + + htcadebug("frame waiting (%d): %d\n", + epid, rx_frame_length); + /* No buffer ready to receive but data + * is ready. Alert the caller with a + * DATA_AVAILABLE event. + */ + if (!end_point->rx_data_alerted) { + end_point->rx_data_alerted = true; + + htca_frame_event(&event_info, NULL, + rx_frame_length, + 0, HTCA_OK, NULL); + + htca_dispatch_event(target, epid, + HTCA_EVENT_DATA_AVAILABLE, + &event_info); + } + } + return 0; + } + + /* We have recv buffers available, so we are + * interested in rxdata interrupts. + */ + target->enb.int_status_enb |= (1 << epid); + end_point->rx_data_alerted = false; + + if (rx_frame_length == 0) { + htcadebug( + "htca_manage_pending_recvs: buffer available (%d), but no data to recv\n", + epid); + /* We have a buffer but there's nothing + * available on the Target to read. + */ + return 0; + } + + /* There is rxdata waiting and a buffer to read it into */ + + /* Pull the request buffer off the Pending Recv Queue */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = + (struct htca_mbox_request *)htca_request_deq_head(recv_queue); + + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + if (!mbox_request) + goto done; + + htcadebug("ep#%d receiving frame: %d bytes\n", epid, rx_frame_length); + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_recv_mask |= (1 << epid); + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + /* Hand off this Mbox Recv request to HIF */ + mbox_request->actual_length = rx_frame_length; + if (htca_recv_request_to_hif(end_point, mbox_request) == HTCA_ERROR) { + struct htca_event_info event_info; + + /* TBD: Could requeue this at the HEAD of the + * pending recv queue. Try again later? + */ + + /* Frame an event to send to caller */ + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, HTCA_ECANCELED, + mbox_request->cookie); + + /* Free the Mailbox request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(&end_point->recv_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_recv_mask &= ~(1 << epid); + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + htca_dispatch_event(target, epid, HTCA_EVENT_BUFFER_RECEIVED, + &event_info); + goto done; + } else { + work_done = 1; + } + +done: + return work_done; +} + +int htca_recv_request_to_hif(struct htca_endpoint *end_point, + struct htca_mbox_request *mbox_request) +{ + int status; + struct htca_target *target; + u32 padded_length; + u32 mbox_address; + u32 req_type; + + target = end_point->target; + + /* Adjust length for power-of-2 block size */ + padded_length = + htca_round_up(mbox_request->actual_length + HTCA_HEADER_LEN_MAX, + end_point->block_size); + + req_type = (end_point->block_size > 1) ? HIF_RD_ASYNC_BLOCK_INC + : HIF_RD_ASYNC_BYTE_INC; + + mbox_address = end_point->mbox_start_addr; + + status = hif_read_write(target->hif_handle, mbox_address, + &mbox_request->buffer + [HTCA_HEADER_LEN_MAX - HTCA_HEADER_LEN], + padded_length, req_type, mbox_request); + + if (status == HIF_OK && mbox_request->req.completion_cb) { + mbox_request->req.completion_cb( + (struct htca_request *)mbox_request, HTCA_OK); + /* htca_recv_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + return HTCA_ERROR; + } + + return HTCA_OK; +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c new file mode 100644 index 0000000000000000000000000000000000000000..ebccf72b21445f0c3d082766c9af4216bc78af7f --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_send.c @@ -0,0 +1,392 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Decide when an endpoint is low on tx credits and we should + * initiate a credit refresh. If this is set very low, we may + * exhaust credits entirely and pause while we wait for credits + * to be reaped from the Target. If set very high we may end + * up spending excessive time trying to reap when nothing is + * available. + * + * TBD: We could make this something like a percentage of the + * most credits we've ever seen on this endpoint. Or make it + * a value that automatically adjusts -- increase by one whenever + * we exhaust credits; decrease by one whenever a CREDIT_REFRESH + * fails to reap any credits. + * For now, wait until credits are completely exhausted; then + * initiate a credit refresh cycle. + */ +#define HTCA_EP_CREDITS_ARE_LOW(_endp) ((_endp)->tx_credits_available == 0) + +/* Pull as many Mailbox Send Requests off of the PendingSend queue + * as we can (must have a credit for each send) and hand off the + * request to HIF. + * + * This function returns when we exhaust Send Requests OR when we + * exhaust credits. + * + * If we are low on credits, it starts a credit refresh cycle. + * + * Returns 0 if nothing was send to HIF + * returns 1 if at least one request was sent to HIF + */ +int htca_manage_pending_sends(struct htca_target *target, int epid) +{ + struct htca_endpoint *end_point; + struct htca_request_queue *send_queue; + struct htca_mbox_request *mbox_request; + unsigned long flags; + u8 tx_credits_available; + int work_done = 0; + + end_point = &target->end_point[epid]; + send_queue = &end_point->send_pending_queue; + + /* Transmit messages as long as we have both something to send + * tx credits that permit us to send + */ + while (!HTCA_IS_QUEUE_EMPTY(send_queue)) { + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + tx_credits_available = end_point->tx_credits_available; + if (tx_credits_available) + end_point->tx_credits_available--; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + htcadebug("(ep=%d) tx_credits_available=%d\n", + epid, tx_credits_available); + if (!tx_credits_available) { + /* We exhausted tx credits */ + break; + } + + /* Get the request buffer from the Pending Send Queue */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + mbox_request = + (struct htca_mbox_request *)htca_request_deq_head( + send_queue); + + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + if (!mbox_request) + break; + + /* Hand off this Mbox Send request to HIF */ + if (htca_send_request_to_hif(end_point, mbox_request) == + HTCA_ERROR) { + struct htca_event_info event_info; + + /* TBD: Could requeue this at the HEAD of the + * pending send queue. Try again later? + */ + + /* Restore tx credit, since it was not used */ + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + end_point->tx_credits_available++; + spin_unlock_irqrestore(&end_point->tx_credit_lock, + flags); + + /* Frame an event to send to caller */ + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, + mbox_request->actual_length, + HTCA_ECANCELED, + mbox_request->cookie); + + /* Free the Mailbox request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail( + &end_point->send_free_queue, + (struct htca_request *)mbox_request); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, + flags); + + htca_dispatch_event( + target, epid, HTCA_EVENT_BUFFER_SENT, &event_info); + goto done; + } + work_done = 1; + } + + htcadebug("ep=%d credsAvail=%d toReap=%d\n", + epid, end_point->tx_credits_available, + end_point->tx_credits_to_reap); + if (HTCA_EP_CREDITS_ARE_LOW(end_point)) { + target->enb.counter_int_status_enb |= (0x10 << epid); + if (end_point->tx_credits_to_reap) + htca_credit_refresh_start(end_point); + } else { + target->enb.counter_int_status_enb &= ~(0x10 << epid); + } + +done: + return work_done; +} + +/* Send one send request to HIF. + * + * Called from the HTCA task while processing requests from + * an endpoint's pendingSendQueue. + * + * Note: May consider calling this in the context of a process + * submitting a new Send Request (i.e. when nothing else is + * pending and credits are available). This would save the + * cost of context switching to the HTCA Work Task; but it would + * require additional synchronization and would add some + * complexity. For the high throughput case this optimization + * would not help since we are likely to have requests + * pending which must be submitted to HIF in the order received. + */ +int htca_send_request_to_hif(struct htca_endpoint *end_point, + struct htca_mbox_request *mbox_request) +{ + int status; + struct htca_target *target; + u32 padded_length; + u32 mbox_address; + u32 req_type; + + target = end_point->target; + + /* Adjust length for power-of-2 block size */ + padded_length = + htca_round_up(mbox_request->actual_length + HTCA_HEADER_LEN_MAX, + end_point->block_size); + + /* Prepend the message's actual length to the outgoing message. + * Caller is REQUIRED to leave HTCA_HEADER_LEN_MAX bytes before + * the message for this purpose (of which the first HTCA_HEADER_LEN + * bytes are actually used). + * + * TBD: We may enhance HIF so that a single write request + * may have TWO consecutive components: one for the HTCA header + * and another for the payload. This would remove the burden + * on callers to reserve space in their buffer for HTCA. + * + * TBD: Since the messaging layer sitting on top of HTCA may + * have this same issue it may make sense to allow a Send + * to pass in a "header buffer" along with a "payload buffer". + * So two buffers (or more generally, a list of buffers) + * rather than one on each call. These buffers would be + * guaranteed to be sent to HIF as a group and they would + * be sent over SDIO back to back. + */ + mbox_request->buffer -= HTCA_HEADER_LEN_MAX; + + if (HTCA_HEADER_LEN_MAX > HTCA_HEADER_LEN) { + /* Sanity: clear padding bytes, if used */ + memset(&mbox_request->buffer[HTCA_HEADER_LEN], 0, + HTCA_HEADER_LEN_MAX - HTCA_HEADER_LEN); + } + /* Target receives length in LittleEndian byte order + * regardeless of Host endianness. + */ + mbox_request->buffer[0] = mbox_request->actual_length & 0xff; + mbox_request->buffer[1] = (mbox_request->actual_length >> 8) & 0xff; + + req_type = (end_point->block_size > 1) ? HIF_WR_ASYNC_BLOCK_INC + : HIF_WR_ASYNC_BYTE_INC; + + /* Arrange for last byte of the message to generate an + * EndOfMessage interrupt to the Target. + */ + mbox_address = end_point->mbox_end_addr - padded_length; + + /* Send the request to HIF */ + status = hif_read_write(target->hif_handle, mbox_address, + mbox_request->buffer, padded_length, req_type, + mbox_request); + + if (status == HIF_OK && mbox_request->req.completion_cb) { + mbox_request->req.completion_cb( + (struct htca_request *)mbox_request, HTCA_OK); + /* htcaSendCompletionCB */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + /* Restore mbox_request buffer */ + mbox_request->buffer += HTCA_HEADER_LEN_MAX; + return HTCA_ERROR; + } + + return HTCA_OK; +} + +/* Start a credit refresh cycle. Credits will appear in + * end_point->tx_credits_available when this refresh completes. + * + * Called in the context of the work_task when we are unable + * to send any more requests because credits are exhausted. + * Also called from HIF completion's context when a credit + * interrupt occurs. + * + * TBD: Consider HTCA v2 features: Quartz FW can send + * in-band TX Credit hint + * RX Length hint + * interrupt status registers + * as opportunistic trailer(s) on an RX message. + * This increases code complexity but may reduce overhead + * since we may reduce the number of explicit SDIO register + * read operations which are relatively expensive "byte basis" + * operations. + */ +int htca_credit_refresh_start(struct htca_endpoint *end_point) +{ + u8 end_point_id; + int status; + struct htca_target *target; + struct htca_reg_request *reg_request; + unsigned long flags; + bool already_in_progress; + u32 address; + + htcadebug("Enter\n"); + + spin_lock_irqsave(&end_point->tx_credit_lock, flags); + already_in_progress = end_point->tx_credit_refresh_in_progress; + end_point->tx_credit_refresh_in_progress = true; + spin_unlock_irqrestore(&end_point->tx_credit_lock, flags); + + if (already_in_progress) + return 0; + + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + htcadebug("on endpoint %d\n", end_point_id); + + spin_lock_irqsave(&target->reg_queue_lock, flags); + reg_request = (struct htca_reg_request *)htca_request_deq_head( + &target->reg_free_queue); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + + if (!reg_request) { + WARN_ON(1); + return 1; + } + + if (WARN_ON(reg_request->purpose != UNUSED_PURPOSE)) + return 1; + + reg_request->buffer = NULL; + reg_request->length = 0; + reg_request->purpose = CREDIT_REFRESH; + reg_request->epid = end_point_id; + + address = get_reg_addr(TX_CREDIT_COUNTER_DECREMENT_REG, end_point_id); + + /* Note: reading many times FROM a FIXed register address, the + * "atomic decrement address". The function htca_credit_refresh_compl + * examines the results upon completion. + */ + status = hif_read_write( + target->hif_handle, address, reg_request->u.credit_dec_results, + HTCA_TX_CREDITS_REAP_MAX, HIF_RD_ASYNC_BYTE_FIX, reg_request); + if (status == HIF_OK && reg_request->req.completion_cb) { + reg_request->req.completion_cb( + (struct htca_request *)reg_request, HIF_OK); + /* htca_credit_refresh_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + WARN_ON(1); + } + return 1; +} + +/* Used during Configuration Negotiation at startup + * to configure max message sizes for each endpoint. + * + * Returns true if all endpoints have been configured, + * by this pass and/or all earlier calls. (Typically + * there should be only a single call which enables + * all endpoints at once.) + * + * Returns false if at least one endpoint has not + * yet been configured. + */ +bool htca_negotiate_config(struct htca_target *target) +{ + int status; + struct htca_endpoint *end_point; + u32 address; + int enb_count = 0; + int ep; + + htcadebug("Enter\n"); + + /* The Target should have posted 1 credit to + * each endpoint by the time we reach here. + */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + end_point = &target->end_point[ep]; + if (end_point->enabled) { + /* This endpoint was already enabled */ + enb_count++; + continue; + } + htcadebug("try epid=%d\n", ep); + + address = get_reg_addr(TX_CREDIT_COUNTER_DECREMENT_REG, ep); + end_point->tx_credits_available = 0; + status = + hif_read_write(target->hif_handle, address, + (u8 *)&end_point->tx_credits_available, + 1, HIF_RD_SYNC_BYTE_FIX, NULL); + if (status != HIF_OK) { + htcadebug("DBG: address=0x%08x status=%d\n", address, + status); + } + if (WARN_ON(status != HIF_OK)) + return false; + + if (!end_point->tx_credits_available) { + /* not yet ready -- no credit posted. Odd case. */ + continue; + } + if (WARN_ON(end_point->tx_credits_available != 1)) + return false; + + end_point->tx_credits_available--; + + /* TBD: Tacitly assumes LittleEndian Host. + * This -- rather than an explicit Host interrupt -- is + * what should trigger Target to fetch blocksize. + */ + htcadebug("good to go epid=%d\n", ep); + + /* "Negotiate" the message size for this endpoint by writing + * the maximum message size (and trigger EOM). + */ + address = + end_point->mbox_end_addr - sizeof(end_point->max_msg_sz); + status = hif_read_write(target->hif_handle, address, + (u8 *)&end_point->max_msg_sz, + sizeof(end_point->max_msg_sz), + HIF_WR_SYNC_BYTE_INC, NULL); + if (WARN_ON(status != HIF_OK)) + return false; + + end_point->enabled = true; + enb_count++; + } + + htcadebug("enb_count=%d\n", enb_count); + return (enb_count == HTCA_NUM_MBOX); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c new file mode 100644 index 0000000000000000000000000000000000000000..6598cbae4ed448dd8111763fb6e086cc76d54592 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_task.c @@ -0,0 +1,340 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* Implementation of Host Target Communication tasks, + * WorkTask and compl_task, which are used to manage + * the Mbox Pending Queues. + * + * A mailbox Send request is queued in arrival order on + * a per-mailbox Send queue until a credit is available + * from the Target. Requests in this queue are + * waiting for the Target to provide tx credits (i.e. recv + * buffers on the Target-side). + * + * A mailbox Recv request is queued in arrival order on + * a per-mailbox Recv queue until a message is available + * to be read. So requests in this queue are waiting for + * the Target to provide rx data. + * + * htca_work_task dequeues requests from the SendPendingQueue + * (once credits are available) and dequeues requests from + * the RecvPendingQueue (once rx data is available) and + * hands them to HIF for processing. + * + * htca_compl_task handles completion processing after + * HIF completes a request. + * + * The main purpose of these tasks is to provide a + * suitable suspendable context for processing requests + * and completions. + */ + +#include +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* Wakeup the htca_work_task. + * + * Invoked whenever send/recv state changes: + * new Send buffer added to the send_pending_queue + * new Recv buffer added to the recv_pending_queue + * tx credits are reaped + * rx data available recognized + */ +void htca_work_task_poke(struct htca_target *target) +{ + target->work_task_has_work = true; + wake_up_interruptible_sync(&target->work_task_wait); +} + +/* Body of the htca_work_task, which hands Send and + * Receive requests to HIF. + */ +static int htca_work_task_core(struct htca_target *target) +{ + int ep; + int work_done = 0; + + /* TBD: We might consider alternative ordering policies, here, + * between Sends and Recvs and among mailboxes. The current + * algorithm is simple. + */ + + /* Process sends/recvs */ + for (ep = 0; ep < HTCA_NUM_MBOX; ep++) { + htcadebug("Call (%d)\n", ep); + work_done += htca_manage_pending_sends(target, ep); + htcadebug("Call (%d)\n", ep); + work_done += htca_manage_pending_recvs(target, ep); + } + + return work_done; +} + +/* Only this work_task is permitted to update + * interrupt enables. That restriction eliminates + * complex race conditions. + */ +static int htca_work_task(void *param) +{ + struct htca_target *target = (struct htca_target *)param; + + /* set_user_nice(current, -3); */ + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + htcadebug("top of loop. intr_state=%d\n", target->intr_state); + /* Wait for htca_work_task_poke */ + wait_event_interruptible(target->work_task_wait, + target->work_task_has_work); + + if (target->work_task_shutdown) + break; /* htcaTaskStop invoked */ + + if (!target->work_task_has_work) + break; /* exit, if this task was interrupted */ + + /* reset before we start work */ + target->work_task_has_work = false; + barrier(); + + if (target->need_start_polling) { + /* reset for next time */ + target->need_start_polling = 0; + target->intr_state = HTCA_POLL; + htca_update_intr_enbs(target, 1); + } + + while (htca_work_task_core(target)) + ; + + if (target->pending_recv_mask || + target->pending_register_refresh) { + continue; + } + + /* When a Recv completes, it sets need_register_refresh=1 + * and pokes the work_task. + * + * We won't actually initiate a register refresh until + * pending recvs on ALL eps have completed. This may + * increase latency slightly but it increases efficiency + * and reduces chatter which should improve throughput. + * Note that even though we don't initiate the register + * refresh immediately, SDIO is still 100% busy doing + * useful work. The refresh is issued shortly after. + */ + if (target->need_register_refresh) { + /* Continue to poll. When the RegsiterRefresh + * completes, the WorkTask will be poked. + */ + target->need_register_refresh = 0; + htca_register_refresh_start(target); + continue; + } + + /* If more work has arrived since we last checked, + * make another pass. + */ + if (target->work_task_has_work) + continue; + + /* As long as we are constantly refreshing register + * state and reprocessing, there is no need to + * enable interrupts. We are essentially POLLING for + * interrupts anyway. But if + * -we were in POLL mode and + * -we have processed all outstanding sends/recvs and + * -there are no PENDING recv operations and + * -there is no pending register refresh (so + * no recv operations have completed since the + * last time we refreshed register state) + * then we switch to INTERRUPT mode and re-enable + * Target-side interrupts. + * + * We'll sleep until poked: + * -DSR handler receives an interrupt + * -application enqueues a new send/recv buffer + * We must also UPDATE interrupt enables even if we + * were already in INTERRUPT mode, since some bits + * may have changed. + */ + if (target->intr_state == HTCA_POLL) { + target->intr_state = HTCA_INTERRUPT; + htca_update_intr_enbs(target, 0); + } + } + complete_and_exit(&target->work_task_completion, 0); + + return 0; +} + +int htca_work_task_start(struct htca_target *target) +{ + int status = HTCA_ERROR; + + if (mutex_lock_interruptible(&target->task_mutex)) + return HTCA_ERROR; /* interrupted */ + + if (target->work_task) + goto done; /* already started */ + + target->work_task = kthread_create(htca_work_task, target, "htcaWork"); + if (!target->work_task) + goto done; /* Failed to create task */ + + target->work_task_shutdown = false; + init_waitqueue_head(&target->work_task_wait); + init_completion(&target->work_task_completion); + wake_up_process(target->work_task); + status = HTCA_OK; + +done: + mutex_unlock(&target->task_mutex); + return status; +} + +void htca_work_task_stop(struct htca_target *target) +{ + if (mutex_lock_interruptible(&target->task_mutex)) + return; /* interrupted */ + + if (!target->work_task) + goto done; + + target->work_task_shutdown = true; + htca_work_task_poke(target); + wait_for_completion(&target->work_task_completion); + target->work_task = NULL; + +done: + mutex_unlock(&target->task_mutex); +} + +/* Wakeup the compl_task. + * Invoked after adding a new completion to the compl_queue. + */ +void htca_compl_task_poke(struct htca_target *target) +{ + target->compl_task_has_work = true; + wake_up_interruptible_sync(&target->compl_task_wait); +} + +static int htca_manage_compl(struct htca_target *target) +{ + struct htca_request *req; + unsigned long flags; + + /* Pop a request from the completion queue */ + spin_lock_irqsave(&target->compl_queue_lock, flags); + req = htca_request_deq_head(&target->compl_queue); + spin_unlock_irqrestore(&target->compl_queue_lock, flags); + + if (!req) + return 0; /* nothing to do */ + + /* Invoke request's corresponding completion function */ + if (req->completion_cb) + req->completion_cb(req, req->status); + + return 1; +} + +static int htca_compl_task(void *param) +{ + struct htca_target *target = (struct htca_target *)param; + + /* set_user_nice(current, -3); */ + set_current_state(TASK_INTERRUPTIBLE); + + for (;;) { + /* Wait for htca_compl_task_poke */ + wait_event_interruptible(target->compl_task_wait, + target->compl_task_has_work); + if (target->compl_task_shutdown) + break; /* htcaTaskStop invoked */ + + if (!target->compl_task_has_work) + break; /* exit, if this task was interrupted */ + + /* reset before we start work */ + target->compl_task_has_work = false; + barrier(); + + /* TBD: We could try to prioritize completions rather than + * handle them strictly in order. Could use separate queues for + * register completions and mailbox completion on each endpoint. + * In general, completion processing is expected to be short + * so this probably isn't worth the additional complexity. + */ + { + int did_work; + + do { + did_work = htca_manage_compl(target); + } while (did_work); + } + } + complete_and_exit(&target->compl_cask_completion, 0); + + return 0; +} + +int htca_compl_task_start(struct htca_target *target) +{ + int status = HTCA_ERROR; + + if (mutex_lock_interruptible(&target->task_mutex)) + return HTCA_ERROR; /* interrupted */ + + if (target->compl_task) + goto done; /* already started */ + + target->compl_task = + kthread_create(htca_compl_task, target, "htcaCompl"); + if (!target->compl_task) + goto done; /* Failed to create task */ + + target->compl_task_shutdown = false; + init_waitqueue_head(&target->compl_task_wait); + init_completion(&target->compl_cask_completion); + wake_up_process(target->compl_task); + status = HTCA_OK; + +done: + mutex_unlock(&target->task_mutex); + return status; +} + +void htca_compl_task_stop(struct htca_target *target) +{ + if (mutex_lock_interruptible(&target->task_mutex)) + return; /* interrupted */ + + if (!target->compl_task) + goto done; + + target->compl_task_shutdown = true; + htca_compl_task_poke(target); + wait_for_completion(&target->compl_cask_completion); + target->compl_task = NULL; + +done: + mutex_unlock(&target->task_mutex); +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..4cf137c89d7557e13cce8ede752727cf1695d022 --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/htca_mbox_utils.c @@ -0,0 +1,182 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "../hif_sdio/hif.h" +#include "htca.h" +#include "htca_mbox_internal.h" + +/* HTCA utility routines */ + +/* Invoked when shutting down */ +void htca_mbox_queue_flush(struct htca_endpoint *end_point, + struct htca_request_queue *pending_queue, + struct htca_request_queue *free_queue, + u8 event_id) +{ + struct htca_event_info event_info; + u8 end_point_id; + struct htca_target *target; + struct htca_mbox_request *mbox_request; + unsigned long flags; + + target = end_point->target; + end_point_id = get_endpoint_id(end_point); + + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + for (;;) { + mbox_request = + (struct htca_mbox_request *)htca_request_deq_head( + pending_queue); + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); + + if (!mbox_request) + break; + + htca_frame_event(&event_info, mbox_request->buffer, + mbox_request->buffer_length, 0, HTCA_ECANCELED, + mbox_request->cookie); + + htca_dispatch_event(target, end_point_id, event_id, + &event_info); + + /* Recycle the request */ + spin_lock_irqsave(&end_point->mbox_queue_lock, flags); + htca_request_enq_tail(free_queue, + (struct htca_request *)mbox_request); + } + spin_unlock_irqrestore(&end_point->mbox_queue_lock, flags); +} + +struct htca_target *htca_target_instance(int i) +{ + return htca_target_list[i]; +} + +void htca_target_instance_add(struct htca_target *target) +{ + int i; + + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + if (!htca_target_list[i]) { + htca_target_list[i] = target; + break; + } + } + WARN_ON(i >= HTCA_NUM_DEVICES_MAX); +} + +void htca_target_instance_remove(struct htca_target *target) +{ + int i; + + for (i = 0; i < HTCA_NUM_DEVICES_MAX; i++) { + if (htca_target_list[i] == target) { + htca_target_list[i] = NULL; + break; + } + } + WARN_ON(i >= HTCA_NUM_DEVICES_MAX); +} + +/* Add a request to the tail of a queue. + * Caller must handle any locking required. + * TBD: Use Linux queue support + */ +void htca_request_enq_tail(struct htca_request_queue *queue, + struct htca_request *req) +{ + req->next = NULL; + + if (queue->tail) + queue->tail->next = (void *)req; + else + queue->head = req; + + queue->tail = req; +} + +/* Remove a request from the start of a queue. + * Caller must handle any locking required. + * TBD: Use Linux queue support + * TBD: If cannot allocate from FREE queue, caller may add more elements. + */ +struct htca_request *htca_request_deq_head(struct htca_request_queue *queue) +{ + struct htca_request *req; + + req = queue->head; + if (!req) + return NULL; + + queue->head = req->next; + if (!queue->head) + queue->tail = NULL; + req->next = NULL; + + return req; +} + +/* Start a Register Refresh cycle. + * + * Submits a request to fetch ALL relevant registers from Target. + * When this completes, we'll take actions based on the new + * register values. + */ +void htca_register_refresh_start(struct htca_target *target) +{ + int status; + struct htca_reg_request *reg_request; + u32 address; + unsigned long flags; + + htcadebug("Enter\n"); + spin_lock_irqsave(&target->reg_queue_lock, flags); + reg_request = (struct htca_reg_request *)htca_request_deq_head( + &target->reg_free_queue); + spin_unlock_irqrestore(&target->reg_queue_lock, flags); + if (!reg_request) { + WARN_ON(1); + return; + } + if (WARN_ON(reg_request->purpose != UNUSED_PURPOSE)) + return; + + spin_lock_irqsave(&target->pending_op_lock, flags); + target->pending_register_refresh++; + spin_unlock_irqrestore(&target->pending_op_lock, flags); + + reg_request->buffer = (u8 *)®_request->u.reg_table; + reg_request->length = sizeof(reg_request->u.reg_table); + reg_request->purpose = INTR_REFRESH; + reg_request->epid = 0; /* not used */ + + address = get_reg_addr(ALL_STATUS_REG, ENDPOINT_UNUSED); + status = hif_read_write(target->hif_handle, address, + ®_request->u.reg_table, + sizeof(reg_request->u.reg_table), + HIF_RD_ASYNC_BYTE_INC, reg_request); + if (status == HIF_OK && reg_request->req.completion_cb) { + reg_request->req.completion_cb( + (struct htca_request *)reg_request, HIF_OK); + /* htca_register_refresh_compl */ + } else if (status == HIF_PENDING) { + /* Will complete later */ + } else { /* HIF error */ + WARN_ON(1); + } +} diff --git a/drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h b/drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..81ce6325eeb8e10ce68711e28553e2da7121bf5b --- /dev/null +++ b/drivers/net/wireless/qca402x/htca_mbox/mbox_host_reg.h @@ -0,0 +1,412 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _MBOX_HOST_REG_REG_H_ +#define _MBOX_HOST_REG_REG_H_ + +/* TBD: REMOVE things that are not needed, especially Diag Window */ + +#define HOST_INT_STATUS_ADDRESS 0x00000400 +#define HOST_INT_STATUS_OFFSET 0x00000400 +#define HOST_INT_STATUS_ERROR_MSB 7 +#define HOST_INT_STATUS_ERROR_LSB 7 +#define HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define HOST_INT_STATUS_ERROR_GET(x) \ + (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_ERROR_SET(x) \ + (((x) << HOST_INT_STATUS_ERROR_LSB) & HOST_INT_STATUS_ERROR_MASK) +#define HOST_INT_STATUS_CPU_MSB 6 +#define HOST_INT_STATUS_CPU_LSB 6 +#define HOST_INT_STATUS_CPU_MASK 0x00000040 +#define HOST_INT_STATUS_CPU_GET(x) \ + (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_CPU_SET(x) \ + (((x) << HOST_INT_STATUS_CPU_LSB) & HOST_INT_STATUS_CPU_MASK) +#define HOST_INT_STATUS_DRAGON_INT_MSB 5 +#define HOST_INT_STATUS_DRAGON_INT_LSB 5 +#define HOST_INT_STATUS_DRAGON_INT_MASK 0x00000020 +#define HOST_INT_STATUS_DRAGON_INT_GET(x) \ + (((x) & HOST_INT_STATUS_DRAGON_INT_MASK) >> \ + HOST_INT_STATUS_DRAGON_INT_LSB) +#define HOST_INT_STATUS_DRAGON_INT_SET(x) \ + (((x) << HOST_INT_STATUS_DRAGON_INT_LSB) & \ + HOST_INT_STATUS_DRAGON_INT_MASK) +#define HOST_INT_STATUS_COUNTER_MSB 4 +#define HOST_INT_STATUS_COUNTER_LSB 4 +#define HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define HOST_INT_STATUS_COUNTER_GET(x) \ + (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB) +#define HOST_INT_STATUS_COUNTER_SET(x) \ + (((x) << HOST_INT_STATUS_COUNTER_LSB) & HOST_INT_STATUS_COUNTER_MASK) +#define HOST_INT_STATUS_MBOX_DATA_MSB 3 +#define HOST_INT_STATUS_MBOX_DATA_LSB 0 +#define HOST_INT_STATUS_MBOX_DATA_MASK 0x0000000f +#define HOST_INT_STATUS_MBOX_DATA_GET(x) \ + (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> \ + HOST_INT_STATUS_MBOX_DATA_LSB) +#define HOST_INT_STATUS_MBOX_DATA_SET(x) \ + (((x) << HOST_INT_STATUS_MBOX_DATA_LSB) & \ + HOST_INT_STATUS_MBOX_DATA_MASK) + +#define CPU_INT_STATUS_ADDRESS 0x00000401 +#define CPU_INT_STATUS_OFFSET 0x00000401 +#define CPU_INT_STATUS_BIT_MSB 7 +#define CPU_INT_STATUS_BIT_LSB 0 +#define CPU_INT_STATUS_BIT_MASK 0x000000ff +#define CPU_INT_STATUS_BIT_GET(x) \ + (((x) & CPU_INT_STATUS_BIT_MASK) >> CPU_INT_STATUS_BIT_LSB) +#define CPU_INT_STATUS_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_BIT_LSB) & CPU_INT_STATUS_BIT_MASK) + +#define ERROR_INT_STATUS_ADDRESS 0x00000402 +#define ERROR_INT_STATUS_OFFSET 0x00000402 +#define ERROR_INT_STATUS_SPI_MSB 3 +#define ERROR_INT_STATUS_SPI_LSB 3 +#define ERROR_INT_STATUS_SPI_MASK 0x00000008 +#define ERROR_INT_STATUS_SPI_GET(x) \ + (((x) & ERROR_INT_STATUS_SPI_MASK) >> ERROR_INT_STATUS_SPI_LSB) +#define ERROR_INT_STATUS_SPI_SET(x) \ + (((x) << ERROR_INT_STATUS_SPI_LSB) & ERROR_INT_STATUS_SPI_MASK) +#define ERROR_INT_STATUS_WAKEUP_MSB 2 +#define ERROR_INT_STATUS_WAKEUP_LSB 2 +#define ERROR_INT_STATUS_WAKEUP_MASK 0x00000004 +#define ERROR_INT_STATUS_WAKEUP_GET(x) \ + (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_WAKEUP_SET(x) \ + (((x) << ERROR_INT_STATUS_WAKEUP_LSB) & ERROR_INT_STATUS_WAKEUP_MASK) +#define ERROR_INT_STATUS_RX_UNDERFLOW_MSB 1 +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB 1 +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00000002 +#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> \ + ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_INT_STATUS_RX_UNDERFLOW_LSB) & \ + ERROR_INT_STATUS_RX_UNDERFLOW_MASK) +#define ERROR_INT_STATUS_TX_OVERFLOW_MSB 0 +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB 0 +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00000001 +#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> \ + ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_INT_STATUS_TX_OVERFLOW_LSB) & \ + ERROR_INT_STATUS_TX_OVERFLOW_MASK) + +#define COUNTER_INT_STATUS_ADDRESS 0x00000403 +#define COUNTER_INT_STATUS_OFFSET 0x00000403 +#define COUNTER_INT_STATUS_COUNTER_MSB 7 +#define COUNTER_INT_STATUS_COUNTER_LSB 0 +#define COUNTER_INT_STATUS_COUNTER_MASK 0x000000ff +#define COUNTER_INT_STATUS_COUNTER_GET(x) \ + (((x) & COUNTER_INT_STATUS_COUNTER_MASK) >> \ + COUNTER_INT_STATUS_COUNTER_LSB) +#define COUNTER_INT_STATUS_COUNTER_SET(x) \ + (((x) << COUNTER_INT_STATUS_COUNTER_LSB) & \ + COUNTER_INT_STATUS_COUNTER_MASK) + +#define MBOX_FRAME_ADDRESS 0x00000404 +#define MBOX_FRAME_OFFSET 0x00000404 +#define MBOX_FRAME_RX_EOM_MSB 7 +#define MBOX_FRAME_RX_EOM_LSB 4 +#define MBOX_FRAME_RX_EOM_MASK 0x000000f0 +#define MBOX_FRAME_RX_EOM_GET(x) \ + (((x) & MBOX_FRAME_RX_EOM_MASK) >> MBOX_FRAME_RX_EOM_LSB) +#define MBOX_FRAME_RX_EOM_SET(x) \ + (((x) << MBOX_FRAME_RX_EOM_LSB) & MBOX_FRAME_RX_EOM_MASK) +#define MBOX_FRAME_RX_SOM_MSB 3 +#define MBOX_FRAME_RX_SOM_LSB 0 +#define MBOX_FRAME_RX_SOM_MASK 0x0000000f +#define MBOX_FRAME_RX_SOM_GET(x) \ + (((x) & MBOX_FRAME_RX_SOM_MASK) >> MBOX_FRAME_RX_SOM_LSB) +#define MBOX_FRAME_RX_SOM_SET(x) \ + (((x) << MBOX_FRAME_RX_SOM_LSB) & MBOX_FRAME_RX_SOM_MASK) + +#define RX_LOOKAHEAD_VALID_ADDRESS 0x00000405 +#define RX_LOOKAHEAD_VALID_OFFSET 0x00000405 +#define RX_LOOKAHEAD_VALID_MBOX_MSB 3 +#define RX_LOOKAHEAD_VALID_MBOX_LSB 0 +#define RX_LOOKAHEAD_VALID_MBOX_MASK 0x0000000f +#define RX_LOOKAHEAD_VALID_MBOX_GET(x) \ + (((x) & RX_LOOKAHEAD_VALID_MBOX_MASK) >> RX_LOOKAHEAD_VALID_MBOX_LSB) +#define RX_LOOKAHEAD_VALID_MBOX_SET(x) \ + (((x) << RX_LOOKAHEAD_VALID_MBOX_LSB) & RX_LOOKAHEAD_VALID_MBOX_MASK) + +#define RX_LOOKAHEAD0_ADDRESS 0x00000408 +#define RX_LOOKAHEAD0_OFFSET 0x00000408 +#define RX_LOOKAHEAD0_DATA_MSB 7 +#define RX_LOOKAHEAD0_DATA_LSB 0 +#define RX_LOOKAHEAD0_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD0_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD0_DATA_MASK) >> RX_LOOKAHEAD0_DATA_LSB) +#define RX_LOOKAHEAD0_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD0_DATA_LSB) & RX_LOOKAHEAD0_DATA_MASK) + +#define RX_LOOKAHEAD1_ADDRESS 0x0000040c +#define RX_LOOKAHEAD1_OFFSET 0x0000040c +#define RX_LOOKAHEAD1_DATA_MSB 7 +#define RX_LOOKAHEAD1_DATA_LSB 0 +#define RX_LOOKAHEAD1_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD1_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD1_DATA_MASK) >> RX_LOOKAHEAD1_DATA_LSB) +#define RX_LOOKAHEAD1_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD1_DATA_LSB) & RX_LOOKAHEAD1_DATA_MASK) + +#define RX_LOOKAHEAD2_ADDRESS 0x00000410 +#define RX_LOOKAHEAD2_OFFSET 0x00000410 +#define RX_LOOKAHEAD2_DATA_MSB 7 +#define RX_LOOKAHEAD2_DATA_LSB 0 +#define RX_LOOKAHEAD2_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD2_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD2_DATA_MASK) >> RX_LOOKAHEAD2_DATA_LSB) +#define RX_LOOKAHEAD2_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD2_DATA_LSB) & RX_LOOKAHEAD2_DATA_MASK) + +#define RX_LOOKAHEAD3_ADDRESS 0x00000414 +#define RX_LOOKAHEAD3_OFFSET 0x00000414 +#define RX_LOOKAHEAD3_DATA_MSB 7 +#define RX_LOOKAHEAD3_DATA_LSB 0 +#define RX_LOOKAHEAD3_DATA_MASK 0x000000ff +#define RX_LOOKAHEAD3_DATA_GET(x) \ + (((x) & RX_LOOKAHEAD3_DATA_MASK) >> RX_LOOKAHEAD3_DATA_LSB) +#define RX_LOOKAHEAD3_DATA_SET(x) \ + (((x) << RX_LOOKAHEAD3_DATA_LSB) & RX_LOOKAHEAD3_DATA_MASK) + +#define INT_STATUS_ENABLE_ADDRESS 0x00000418 +#define INT_STATUS_ENABLE_OFFSET 0x00000418 +#define INT_STATUS_ENABLE_ERROR_MSB 7 +#define INT_STATUS_ENABLE_ERROR_LSB 7 +#define INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define INT_STATUS_ENABLE_ERROR_GET(x) \ + (((x) & INT_STATUS_ENABLE_ERROR_MASK) >> INT_STATUS_ENABLE_ERROR_LSB) +#define INT_STATUS_ENABLE_ERROR_SET(x) \ + (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_MSB 6 +#define INT_STATUS_ENABLE_CPU_LSB 6 +#define INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define INT_STATUS_ENABLE_CPU_GET(x) \ + (((x) & INT_STATUS_ENABLE_CPU_MASK) >> INT_STATUS_ENABLE_CPU_LSB) +#define INT_STATUS_ENABLE_CPU_SET(x) \ + (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_DRAGON_INT_MSB 5 +#define INT_STATUS_ENABLE_DRAGON_INT_LSB 5 +#define INT_STATUS_ENABLE_DRAGON_INT_MASK 0x00000020 +#define INT_STATUS_ENABLE_DRAGON_INT_GET(x) \ + (((x) & INT_STATUS_ENABLE_DRAGON_INT_MASK) >> \ + INT_STATUS_ENABLE_DRAGON_INT_LSB) +#define INT_STATUS_ENABLE_DRAGON_INT_SET(x) \ + (((x) << INT_STATUS_ENABLE_DRAGON_INT_LSB) & \ + INT_STATUS_ENABLE_DRAGON_INT_MASK) +#define INT_STATUS_ENABLE_COUNTER_MSB 4 +#define INT_STATUS_ENABLE_COUNTER_LSB 4 +#define INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define INT_STATUS_ENABLE_COUNTER_GET(x) \ + (((x) & INT_STATUS_ENABLE_COUNTER_MASK) >> \ + INT_STATUS_ENABLE_COUNTER_LSB) +#define INT_STATUS_ENABLE_COUNTER_SET(x) \ + (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & \ + INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_MSB 3 +#define INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define INT_STATUS_ENABLE_MBOX_DATA_GET(x) \ + (((x) & INT_STATUS_ENABLE_MBOX_DATA_MASK) >> \ + INT_STATUS_ENABLE_MBOX_DATA_LSB) +#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) \ + (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & \ + INT_STATUS_ENABLE_MBOX_DATA_MASK) + +#define CPU_INT_STATUS_ENABLE_ADDRESS 0x00000419 +#define CPU_INT_STATUS_ENABLE_OFFSET 0x00000419 +#define CPU_INT_STATUS_ENABLE_BIT_MSB 7 +#define CPU_INT_STATUS_ENABLE_BIT_LSB 0 +#define CPU_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define CPU_INT_STATUS_ENABLE_BIT_GET(x) \ + (((x) & CPU_INT_STATUS_ENABLE_BIT_MASK) >> \ + CPU_INT_STATUS_ENABLE_BIT_LSB) +#define CPU_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & \ + CPU_INT_STATUS_ENABLE_BIT_MASK) + +#define ERROR_STATUS_ENABLE_ADDRESS 0x0000041a +#define ERROR_STATUS_ENABLE_OFFSET 0x0000041a +#define ERROR_STATUS_ENABLE_WAKEUP_MSB 2 +#define ERROR_STATUS_ENABLE_WAKEUP_LSB 2 +#define ERROR_STATUS_ENABLE_WAKEUP_MASK 0x00000004 +#define ERROR_STATUS_ENABLE_WAKEUP_GET(x) \ + (((x) & ERROR_STATUS_ENABLE_WAKEUP_MASK) >> \ + ERROR_STATUS_ENABLE_WAKEUP_LSB) +#define ERROR_STATUS_ENABLE_WAKEUP_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_WAKEUP_LSB) & \ + ERROR_STATUS_ENABLE_WAKEUP_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MSB 1 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 1 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00000002 +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) >> \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MSB 0 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 0 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00000001 +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) >> \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) + +#define COUNTER_INT_STATUS_ENABLE_ADDRESS 0x0000041b +#define COUNTER_INT_STATUS_ENABLE_OFFSET 0x0000041b +#define COUNTER_INT_STATUS_ENABLE_BIT_MSB 7 +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB 0 +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK 0x000000ff +#define COUNTER_INT_STATUS_ENABLE_BIT_GET(x) \ + (((x) & COUNTER_INT_STATUS_ENABLE_BIT_MASK) >> \ + COUNTER_INT_STATUS_ENABLE_BIT_LSB) +#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & \ + COUNTER_INT_STATUS_ENABLE_BIT_MASK) + +#define COUNT_ADDRESS 0x00000420 +#define COUNT_OFFSET 0x00000420 +#define COUNT_VALUE_MSB 7 +#define COUNT_VALUE_LSB 0 +#define COUNT_VALUE_MASK 0x000000ff +#define COUNT_VALUE_GET(x) (((x) & COUNT_VALUE_MASK) >> COUNT_VALUE_LSB) +#define COUNT_VALUE_SET(x) (((x) << COUNT_VALUE_LSB) & COUNT_VALUE_MASK) + +#define COUNT_DEC_ADDRESS 0x00000440 +#define COUNT_DEC_OFFSET 0x00000440 +#define COUNT_DEC_VALUE_MSB 7 +#define COUNT_DEC_VALUE_LSB 0 +#define COUNT_DEC_VALUE_MASK 0x000000ff +#define COUNT_DEC_VALUE_GET(x) \ + (((x) & COUNT_DEC_VALUE_MASK) >> COUNT_DEC_VALUE_LSB) +#define COUNT_DEC_VALUE_SET(x) \ + (((x) << COUNT_DEC_VALUE_LSB) & COUNT_DEC_VALUE_MASK) + +#define SCRATCH_ADDRESS 0x00000460 +#define SCRATCH_OFFSET 0x00000460 +#define SCRATCH_VALUE_MSB 7 +#define SCRATCH_VALUE_LSB 0 +#define SCRATCH_VALUE_MASK 0x000000ff +#define SCRATCH_VALUE_GET(x) (((x) & SCRATCH_VALUE_MASK) >> SCRATCH_VALUE_LSB) +#define SCRATCH_VALUE_SET(x) (((x) << SCRATCH_VALUE_LSB) & SCRATCH_VALUE_MASK) + +#define FIFO_TIMEOUT_ADDRESS 0x00000468 +#define FIFO_TIMEOUT_OFFSET 0x00000468 +#define FIFO_TIMEOUT_VALUE_MSB 7 +#define FIFO_TIMEOUT_VALUE_LSB 0 +#define FIFO_TIMEOUT_VALUE_MASK 0x000000ff +#define FIFO_TIMEOUT_VALUE_GET(x) \ + (((x) & FIFO_TIMEOUT_VALUE_MASK) >> FIFO_TIMEOUT_VALUE_LSB) +#define FIFO_TIMEOUT_VALUE_SET(x) \ + (((x) << FIFO_TIMEOUT_VALUE_LSB) & FIFO_TIMEOUT_VALUE_MASK) + +#define FIFO_TIMEOUT_ENABLE_ADDRESS 0x00000469 +#define FIFO_TIMEOUT_ENABLE_OFFSET 0x00000469 +#define FIFO_TIMEOUT_ENABLE_SET_MSB 0 +#define FIFO_TIMEOUT_ENABLE_SET_LSB 0 +#define FIFO_TIMEOUT_ENABLE_SET_MASK 0x00000001 +#define FIFO_TIMEOUT_ENABLE_SET_GET(x) \ + (((x) & FIFO_TIMEOUT_ENABLE_SET_MASK) >> FIFO_TIMEOUT_ENABLE_SET_LSB) +#define FIFO_TIMEOUT_ENABLE_SET_SET(x) \ + (((x) << FIFO_TIMEOUT_ENABLE_SET_LSB) & FIFO_TIMEOUT_ENABLE_SET_MASK) + +#define INT_WLAN_ADDRESS 0x00000472 +#define INT_TARGET_ADDRESS INT_WLAN_ADDRESS +#define INT_WLAN_OFFSET 0x00000472 +#define INT_WLAN_VECTOR_MSB 7 +#define INT_WLAN_VECTOR_LSB 0 +#define INT_WLAN_VECTOR_MASK 0x000000ff +#define INT_WLAN_VECTOR_GET(x) \ + (((x) & INT_WLAN_VECTOR_MASK) >> INT_WLAN_VECTOR_LSB) +#define INT_WLAN_VECTOR_SET(x) \ + (((x) << INT_WLAN_VECTOR_LSB) & INT_WLAN_VECTOR_MASK) + +#define SPI_CONFIG_ADDRESS 0x00000480 +#define SPI_CONFIG_OFFSET 0x00000480 +#define SPI_CONFIG_SPI_RESET_MSB 4 +#define SPI_CONFIG_SPI_RESET_LSB 4 +#define SPI_CONFIG_SPI_RESET_MASK 0x00000010 +#define SPI_CONFIG_SPI_RESET_GET(x) \ + (((x) & SPI_CONFIG_SPI_RESET_MASK) >> SPI_CONFIG_SPI_RESET_LSB) +#define SPI_CONFIG_SPI_RESET_SET(x) \ + (((x) << SPI_CONFIG_SPI_RESET_LSB) & SPI_CONFIG_SPI_RESET_MASK) +#define SPI_CONFIG_INTERRUPT_ENABLE_MSB 3 +#define SPI_CONFIG_INTERRUPT_ENABLE_LSB 3 +#define SPI_CONFIG_INTERRUPT_ENABLE_MASK 0x00000008 +#define SPI_CONFIG_INTERRUPT_ENABLE_GET(x) \ + (((x) & SPI_CONFIG_INTERRUPT_ENABLE_MASK) >> \ + SPI_CONFIG_INTERRUPT_ENABLE_LSB) +#define SPI_CONFIG_INTERRUPT_ENABLE_SET(x) \ + (((x) << SPI_CONFIG_INTERRUPT_ENABLE_LSB) & \ + SPI_CONFIG_INTERRUPT_ENABLE_MASK) +#define SPI_CONFIG_TEST_MODE_MSB 2 +#define SPI_CONFIG_TEST_MODE_LSB 2 +#define SPI_CONFIG_TEST_MODE_MASK 0x00000004 +#define SPI_CONFIG_TEST_MODE_GET(x) \ + (((x) & SPI_CONFIG_TEST_MODE_MASK) >> SPI_CONFIG_TEST_MODE_LSB) +#define SPI_CONFIG_TEST_MODE_SET(x) \ + (((x) << SPI_CONFIG_TEST_MODE_LSB) & SPI_CONFIG_TEST_MODE_MASK) +#define SPI_CONFIG_DATA_SIZE_MSB 1 +#define SPI_CONFIG_DATA_SIZE_LSB 0 +#define SPI_CONFIG_DATA_SIZE_MASK 0x00000003 +#define SPI_CONFIG_DATA_SIZE_GET(x) \ + (((x) & SPI_CONFIG_DATA_SIZE_MASK) >> SPI_CONFIG_DATA_SIZE_LSB) +#define SPI_CONFIG_DATA_SIZE_SET(x) \ + (((x) << SPI_CONFIG_DATA_SIZE_LSB) & SPI_CONFIG_DATA_SIZE_MASK) + +#define SPI_STATUS_ADDRESS 0x00000481 +#define SPI_STATUS_OFFSET 0x00000481 +#define SPI_STATUS_ADDR_ERR_MSB 3 +#define SPI_STATUS_ADDR_ERR_LSB 3 +#define SPI_STATUS_ADDR_ERR_MASK 0x00000008 +#define SPI_STATUS_ADDR_ERR_GET(x) \ + (((x) & SPI_STATUS_ADDR_ERR_MASK) >> SPI_STATUS_ADDR_ERR_LSB) +#define SPI_STATUS_ADDR_ERR_SET(x) \ + (((x) << SPI_STATUS_ADDR_ERR_LSB) & SPI_STATUS_ADDR_ERR_MASK) +#define SPI_STATUS_RD_ERR_MSB 2 +#define SPI_STATUS_RD_ERR_LSB 2 +#define SPI_STATUS_RD_ERR_MASK 0x00000004 +#define SPI_STATUS_RD_ERR_GET(x) \ + (((x) & SPI_STATUS_RD_ERR_MASK) >> SPI_STATUS_RD_ERR_LSB) +#define SPI_STATUS_RD_ERR_SET(x) \ + (((x) << SPI_STATUS_RD_ERR_LSB) & SPI_STATUS_RD_ERR_MASK) +#define SPI_STATUS_WR_ERR_MSB 1 +#define SPI_STATUS_WR_ERR_LSB 1 +#define SPI_STATUS_WR_ERR_MASK 0x00000002 +#define SPI_STATUS_WR_ERR_GET(x) \ + (((x) & SPI_STATUS_WR_ERR_MASK) >> SPI_STATUS_WR_ERR_LSB) +#define SPI_STATUS_WR_ERR_SET(x) \ + (((x) << SPI_STATUS_WR_ERR_LSB) & SPI_STATUS_WR_ERR_MASK) +#define SPI_STATUS_READY_MSB 0 +#define SPI_STATUS_READY_LSB 0 +#define SPI_STATUS_READY_MASK 0x00000001 +#define SPI_STATUS_READY_GET(x) \ + (((x) & SPI_STATUS_READY_MASK) >> SPI_STATUS_READY_LSB) +#define SPI_STATUS_READY_SET(x) \ + (((x) << SPI_STATUS_READY_LSB) & SPI_STATUS_READY_MASK) +#define INT_WLAN_ADDRESS 0x00000472 +#define INT_WLAN_OFFSET 0x00000472 +#define INT_WLAN_VECTOR_MSB 7 +#define INT_WLAN_VECTOR_LSB 0 +#define INT_WLAN_VECTOR_MASK 0x000000ff +#define INT_WLAN_VECTOR_GET(x) \ + (((x) & INT_WLAN_VECTOR_MASK) >> INT_WLAN_VECTOR_LSB) +#define INT_WLAN_VECTOR_SET(x) \ + (((x) << INT_WLAN_VECTOR_LSB) & INT_WLAN_VECTOR_MASK) + +#endif /* _MBOX_HOST_REG_H_ */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c index ec2ea56f7933162b1d131f0b251a36e3bb2470fa..fdbd35954d150ba6b7b81125b54d1899fd48b0a8 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c @@ -304,9 +304,6 @@ static void _rtl92c_get_txpower_writeval_by_regulatory(struct ieee80211_hw *hw, writeVal = 0x00000000; if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1) writeVal = writeVal - 0x06060606; - else if (rtlpriv->dm.dynamic_txhighpower_lvl == - TXHIGHPWRLEVEL_BT2) - writeVal = writeVal; *(p_outwriteval + rf) = writeVal; } } diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 8311a93cabd8966342f19f091c7518ad88b84320..c1a65ce312432da83a0605629b62703bcf2a8024 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -505,14 +505,18 @@ int nvdimm_revalidate_disk(struct gendisk *disk) { struct device *dev = disk_to_dev(disk)->parent; struct nd_region *nd_region = to_nd_region(dev->parent); - const char *pol = nd_region->ro ? "only" : "write"; + int disk_ro = get_disk_ro(disk); - if (nd_region->ro == get_disk_ro(disk)) + /* + * Upgrade to read-only if the region is read-only preserve as + * read-only if the disk is already read-only. + */ + if (disk_ro || nd_region->ro == disk_ro) return 0; - dev_info(dev, "%s read-%s, marking %s read-%s\n", - dev_name(&nd_region->dev), pol, disk->disk_name, pol); - set_disk_ro(disk, nd_region->ro); + dev_info(dev, "%s read-only, marking %s read-only\n", + dev_name(&nd_region->dev), disk->disk_name); + set_disk_ro(disk, 1); return 0; diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 642ee00e914302d0bec9b16b9c1765dc3b9af115..a55d112583bd4409f55a58a5edfab5d46d28eb57 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1126,11 +1126,11 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid) if (result < 0) goto release_cq; + nvme_init_queue(nvmeq, qid); result = queue_request_irq(nvmeq); if (result < 0) goto release_sq; - nvme_init_queue(nvmeq, qid); return result; release_sq: @@ -1248,6 +1248,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev) return result; nvmeq->cq_vector = 0; + nvme_init_queue(nvmeq, 0); result = queue_request_irq(nvmeq); if (result) { nvmeq->cq_vector = -1; @@ -1776,7 +1777,6 @@ static void nvme_reset_work(struct work_struct *work) if (result) goto out; - nvme_init_queue(dev->queues[0], 0); result = nvme_alloc_admin_tags(dev); if (result) goto out; diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index f791d46fe50f717bdcf994e790ab72e7915f305f..2caed285fd7bd9ee99a03dd72be614bf956698d7 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -166,11 +166,21 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req) nvmet_req_complete(req, status); } +static void copy_and_pad(char *dst, int dst_len, const char *src, int src_len) +{ + int len = min(src_len, dst_len); + + memcpy(dst, src, len); + if (dst_len > len) + memset(dst + len, ' ', dst_len - len); +} + static void nvmet_execute_identify_ctrl(struct nvmet_req *req) { struct nvmet_ctrl *ctrl = req->sq->ctrl; struct nvme_id_ctrl *id; u16 status = 0; + const char model[] = "Linux"; id = kzalloc(sizeof(*id), GFP_KERNEL); if (!id) { @@ -182,14 +192,10 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) id->vid = 0; id->ssvid = 0; - memset(id->sn, ' ', sizeof(id->sn)); - snprintf(id->sn, sizeof(id->sn), "%llx", ctrl->serial); - - memset(id->mn, ' ', sizeof(id->mn)); - strncpy((char *)id->mn, "Linux", sizeof(id->mn)); - - memset(id->fr, ' ', sizeof(id->fr)); - strncpy((char *)id->fr, UTS_RELEASE, sizeof(id->fr)); + bin2hex(id->sn, &ctrl->subsys->serial, + min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2)); + copy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1); + copy_and_pad(id->fr, sizeof(id->fr), UTS_RELEASE, strlen(UTS_RELEASE)); id->rab = 6; diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 3a044922b048cf5dc060317bc7862093081952f1..64b40a12abcf8cf36b00e443f760b5f01653c013 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -743,9 +743,6 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); - /* generate a random serial number as our controllers are ephemeral: */ - get_random_bytes(&ctrl->serial, sizeof(ctrl->serial)); - kref_init(&ctrl->ref); ctrl->subsys = subsys; @@ -904,6 +901,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, return NULL; subsys->ver = NVME_VS(1, 2, 1); /* NVMe 1.2.1 */ + /* generate a random serial number as our controllers are ephemeral: */ + get_random_bytes(&subsys->serial, sizeof(subsys->serial)); switch (type) { case NVME_NQN_NVME: diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 26b87dc843d289b890e32e59decb6fb97a249bb8..0bc530cdf2b40a4f55f7086d02cc422e8b7d34d2 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -110,7 +110,6 @@ struct nvmet_ctrl { struct mutex lock; u64 cap; - u64 serial; u32 cc; u32 csts; @@ -151,6 +150,7 @@ struct nvmet_subsys { u16 max_qid; u64 ver; + u64 serial; char *subsysnqn; struct config_group group; diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c index 53c83d66eb7e23461294aa22f77f41f6c0739eb5..90b5a898d6b1af7ae5c1d53e8471298e5516674c 100644 --- a/drivers/of/unittest.c +++ b/drivers/of/unittest.c @@ -155,20 +155,20 @@ static void __init of_unittest_dynamic(void) /* Add a new property - should pass*/ prop->name = "new-property"; prop->value = "new-property-data"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_add_property(np, prop) == 0, "Adding a new property failed\n"); /* Try to add an existing property - should fail */ prop++; prop->name = "new-property"; prop->value = "new-property-data-should-fail"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_add_property(np, prop) != 0, "Adding an existing property should have failed\n"); /* Try to modify an existing property - should pass */ prop->value = "modify-property-data-should-pass"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_update_property(np, prop) == 0, "Updating an existing property should have passed\n"); @@ -176,7 +176,7 @@ static void __init of_unittest_dynamic(void) prop++; prop->name = "modify-property"; prop->value = "modify-missing-property-data-should-pass"; - prop->length = strlen(prop->value); + prop->length = strlen(prop->value) + 1; unittest(of_update_property(np, prop) == 0, "Updating a missing property should have passed\n"); diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 37d70b5ad22f99b8bcdef898aaacf49b6caaa814..2bba8481beb172312d48358bbd359e0f8802ac6a 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -134,7 +134,7 @@ struct controller *pcie_init(struct pcie_device *dev); int pcie_init_notification(struct controller *ctrl); int pciehp_enable_slot(struct slot *p_slot); int pciehp_disable_slot(struct slot *p_slot); -void pcie_enable_notification(struct controller *ctrl); +void pcie_reenable_notification(struct controller *ctrl); int pciehp_power_on_slot(struct slot *slot); void pciehp_power_off_slot(struct slot *slot); void pciehp_get_power_status(struct slot *slot, u8 *status); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 7d32fa33dcef902a926b1603a06f2002971675a4..6620b1095046905f4492f4733be7ac00908bc15d 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -297,7 +297,7 @@ static int pciehp_resume(struct pcie_device *dev) ctrl = get_service_data(dev); /* reinitialize the chipset's event detection logic */ - pcie_enable_notification(ctrl); + pcie_reenable_notification(ctrl); slot = ctrl->slot; diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index d08dfc8b9ba983c6b83e182ce831f98e24b095df..8d811ea353c85b7323fcc37d32bb77b54f3030ae 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -673,7 +673,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) return handled; } -void pcie_enable_notification(struct controller *ctrl) +static void pcie_enable_notification(struct controller *ctrl) { u16 cmd, mask; @@ -711,6 +711,17 @@ void pcie_enable_notification(struct controller *ctrl) pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd); } +void pcie_reenable_notification(struct controller *ctrl) +{ + /* + * Clear both Presence and Data Link Layer Changed to make sure + * those events still fire after we have re-enabled them. + */ + pcie_capability_write_word(ctrl->pcie->port, PCI_EXP_SLTSTA, + PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC); + pcie_enable_notification(ctrl); +} + static void pcie_disable_notification(struct controller *ctrl) { u16 mask; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index b55f9179c94ed6e913751965af8abcf488f8aab5..a05d143ac43b8da2db18f0580eaecdbadf042efd 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4225,11 +4225,29 @@ static int pci_quirk_qcom_rp_acs(struct pci_dev *dev, u16 acs_flags) * 0xa290-0xa29f PCI Express Root port #{0-16} * 0xa2e7-0xa2ee PCI Express Root port #{17-24} * + * Mobile chipsets are also affected, 7th & 8th Generation + * Specification update confirms ACS errata 22, status no fix: (7th Generation + * Intel Processor Family I/O for U/Y Platforms and 8th Generation Intel + * Processor Family I/O for U Quad Core Platforms Specification Update, + * August 2017, Revision 002, Document#: 334660-002)[6] + * Device IDs from I/O datasheet: (7th Generation Intel Processor Family I/O + * for U/Y Platforms and 8th Generation Intel ® Processor Family I/O for U + * Quad Core Platforms, Vol 1 of 2, August 2017, Document#: 334658-003)[7] + * + * 0x9d10-0x9d1b PCI Express Root port #{1-12} + * + * The 300 series chipset suffers from the same bug so include those root + * ports here as well. + * + * 0xa32c-0xa343 PCI Express Root port #{0-24} + * * [1] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-2.html * [2] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-datasheet-vol-1.html * [3] http://www.intel.com/content/www/us/en/chipsets/100-series-chipset-spec-update.html * [4] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-spec-update.html * [5] http://www.intel.com/content/www/us/en/chipsets/200-series-chipset-pch-datasheet-vol-1.html + * [6] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-spec-update.html + * [7] https://www.intel.com/content/www/us/en/processors/core/7th-gen-core-family-mobile-u-y-processor-lines-i-o-datasheet-vol-1.html */ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) { @@ -4239,6 +4257,8 @@ static bool pci_quirk_intel_spt_pch_acs_match(struct pci_dev *dev) switch (dev->device) { case 0xa110 ... 0xa11f: case 0xa167 ... 0xa16a: /* Sunrise Point */ case 0xa290 ... 0xa29f: case 0xa2e7 ... 0xa2ee: /* Union Point */ + case 0x9d10 ... 0x9d1b: /* 7th & 8th Gen Mobile */ + case 0xa32c ... 0xa343: /* 300 series */ return true; } diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index f9a245465fd099f64037711523f7b0903b9b226d..6a25bfd4541ea228dc54667c881997576f21482f 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c @@ -49,7 +49,6 @@ static int ec_response_timed_out(void) static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, struct cros_ec_command *msg) { - struct ec_host_request *request; struct ec_host_response response; u8 sum = 0; int i; @@ -62,8 +61,6 @@ static int cros_ec_pkt_xfer_lpc(struct cros_ec_device *ec, for (i = 0; i < ret; i++) outb(ec->dout[i], EC_LPC_ADDR_HOST_PACKET + i); - request = (struct ec_host_request *)ec->dout; - /* Here we go */ outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 2c29538c35c625c84e340deb1ae8b5ffd42cb7e2..c38f1be7e3fb0a611d34bcb6185f5373a9ec8e03 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -23,7 +23,7 @@ #include "gsi_emulation.h" #define GSI_CMD_TIMEOUT (5*HZ) -#define GSI_STOP_CMD_TIMEOUT_MS 20 +#define GSI_STOP_CMD_TIMEOUT_MS 50 #define GSI_MAX_CH_LOW_WEIGHT 15 #define GSI_RESET_WA_MIN_SLEEP 1000 @@ -2788,27 +2788,21 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) return -GSI_STATUS_UNSUPPORTED_OP; } + spin_lock_irqsave(&gsi_ctx->slock, flags); if (curr == GSI_CHAN_MODE_CALLBACK && mode == GSI_CHAN_MODE_POLL) { - spin_lock_irqsave(&gsi_ctx->slock, flags); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, 0); - spin_unlock_irqrestore(&gsi_ctx->slock, flags); - spin_lock_irqsave(&ctx->ring.slock, flags); atomic_set(&ctx->poll_mode, mode); - spin_unlock_irqrestore(&ctx->ring.slock, flags); ctx->stats.callback_to_poll++; } if (curr == GSI_CHAN_MODE_POLL && mode == GSI_CHAN_MODE_CALLBACK) { - spin_lock_irqsave(&ctx->ring.slock, flags); atomic_set(&ctx->poll_mode, mode); - spin_unlock_irqrestore(&ctx->ring.slock, flags); - spin_lock_irqsave(&gsi_ctx->slock, flags); __gsi_config_ieob_irq(gsi_ctx->per.ee, 1 << ctx->evtr->id, ~0); - spin_unlock_irqrestore(&gsi_ctx->slock, flags); ctx->stats.poll_to_callback++; } + spin_unlock_irqrestore(&gsi_ctx->slock, flags); return GSI_STATUS_SUCCESS; } diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c index 5812d8df9c9a654ffea8b3cf35a1e85b189d92e7..4e3a565e1a0a5b289efde9ac747a5253d94227d6 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c @@ -132,7 +132,7 @@ struct ipa_gsb_iface_info { * struct ipa_gsb_context - GSB driver context information * @logbuf: buffer of ipc logging * @logbuf_low: buffer of ipc logging (low priority) - * @lock: mutex lock + * @lock: global mutex lock for global variables * @prod_hdl: handle for prod pipe * @cons_hdl: handle for cons pipe * @ipa_sys_desc_size: sys pipe desc size @@ -141,6 +141,8 @@ struct ipa_gsb_iface_info { * @num_connected_iface: number of connected interface * @num_resumed_iface: number of resumed interface * @iface: interface information + * @iface_lock: interface mutex lock for control path + * @iface_spinlock: interface spinlock for data path * @pm_hdl: IPA PM handle */ struct ipa_gsb_context { @@ -155,6 +157,8 @@ struct ipa_gsb_context { int num_connected_iface; int num_resumed_iface; struct ipa_gsb_iface_info *iface[MAX_SUPPORTED_IFACE]; + struct mutex iface_lock[MAX_SUPPORTED_IFACE]; + spinlock_t iface_spinlock[MAX_SUPPORTED_IFACE]; u32 pm_hdl; }; @@ -240,6 +244,7 @@ static void ipa_gsb_debugfs_destroy(void) static int ipa_gsb_driver_init(struct odu_bridge_params *params) { + int i; if (!ipa_is_ready()) { IPA_GSB_ERR("IPA is not ready\n"); return -EFAULT; @@ -252,6 +257,10 @@ static int ipa_gsb_driver_init(struct odu_bridge_params *params) return -ENOMEM; mutex_init(&ipa_gsb_ctx->lock); + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) { + mutex_init(&ipa_gsb_ctx->iface_lock[i]); + spin_lock_init(&ipa_gsb_ctx->iface_spinlock[i]); + } ipa_gsb_debugfs_init(); return 0; @@ -475,7 +484,7 @@ int ipa_bridge_init(struct ipa_bridge_init_params *params, u32 *hdl) if (!params || !params->wakeup_request || !hdl || !params->info.netdev_name || !params->info.tx_dp_notify || !params->info.send_dl_skb) { - IPA_GSB_ERR("NULL parameters\n"); + IPA_GSB_ERR("Invalid parameters\n"); return -EINVAL; } @@ -596,6 +605,7 @@ static void ipa_gsb_deregister_pm(void) int ipa_bridge_cleanup(u32 hdl) { + int i; if (!ipa_gsb_ctx) { IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); return -EFAULT; @@ -606,39 +616,44 @@ int ipa_bridge_cleanup(u32 hdl) return -EINVAL; } - if (ipa_gsb_ctx->iface[hdl] == NULL) { - IPA_GSB_ERR("fail to find interface\n"); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } IPA_GSB_DBG("client hdl: %d\n", hdl); - mutex_lock(&ipa_gsb_ctx->lock); if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("cannot cleanup when iface is connected\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } - ipa_gsb_dereg_intf_props(ipa_gsb_ctx->iface[hdl]); ipa_gsb_delete_partial_hdr(ipa_gsb_ctx->iface[hdl]); + spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); kfree(ipa_gsb_ctx->iface[hdl]); ipa_gsb_ctx->iface[hdl] = NULL; ipa_gsb_ctx->iface_hdl[hdl] = false; + spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + mutex_lock(&ipa_gsb_ctx->lock); ipa_gsb_ctx->num_iface--; IPA_GSB_DBG("num_iface %d\n", ipa_gsb_ctx->num_iface); - if (ipa_gsb_ctx->num_iface == 0) { ipa_gsb_deregister_pm(); ipa_gsb_debugfs_destroy(); ipc_log_context_destroy(ipa_gsb_ctx->logbuf); ipc_log_context_destroy(ipa_gsb_ctx->logbuf_low); mutex_unlock(&ipa_gsb_ctx->lock); + mutex_destroy(&ipa_gsb_ctx->lock); + for (i = 0; i < MAX_SUPPORTED_IFACE; i++) + mutex_destroy(&ipa_gsb_ctx->iface_lock[i]); kfree(ipa_gsb_ctx); ipa_gsb_ctx = NULL; return 0; } - mutex_unlock(&ipa_gsb_ctx->lock); return 0; } @@ -670,6 +685,10 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, (pkt_size + sizeof(*mux_hdr) + ETH_HLEN + IPA_GSB_SKB_DUMMY_HEADER); hdl = mux_hdr->iface_hdl; + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + break; + } IPA_GSB_DBG_LOW("pkt_size: %d, pad_byte: %d, hdl: %d\n", pkt_size, pad_byte, hdl); @@ -683,11 +702,21 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, break; } skb_trim(skb2, pkt_size + ETH_HLEN); - ipa_gsb_ctx->iface[hdl]->send_dl_skb( - ipa_gsb_ctx->iface[hdl]->priv, skb2); - ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; - skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); + spin_lock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + if (ipa_gsb_ctx->iface[hdl] != NULL) { + ipa_gsb_ctx->iface[hdl]->send_dl_skb( + ipa_gsb_ctx->iface[hdl]->priv, skb2); + ipa_gsb_ctx->iface[hdl]->iface_stats.num_dl_packets++; + spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + skb_pull(skb, pkt_size + ETH_HLEN + pad_byte); + } else { + IPA_GSB_ERR("Invalid hdl: %d, drop the skb\n", hdl); + spin_unlock_bh(&ipa_gsb_ctx->iface_spinlock[hdl]); + dev_kfree_skb_any(skb2); + break; + } } + if (skb) { dev_kfree_skb_any(skb); skb = NULL; @@ -695,7 +724,7 @@ static void ipa_gsb_cons_cb(void *priv, enum ipa_dp_evt_type evt, } static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, - unsigned long data) + unsigned long data) { struct sk_buff *skb; struct ipa_gsb_mux_hdr *mux_hdr; @@ -714,13 +743,18 @@ static void ipa_gsb_tx_dp_notify(void *priv, enum ipa_dp_evt_type evt, /* change to host order */ *(u32 *)mux_hdr = ntohl(*(u32 *)mux_hdr); hdl = mux_hdr->iface_hdl; + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("invalid hdl: %d and cb, drop the skb\n", hdl); + dev_kfree_skb_any(skb); + return; + } IPA_GSB_DBG_LOW("evt: %d, hdl in tx_dp_notify: %d\n", evt, hdl); /* remove 4 byte mux header */ skb_pull(skb, sizeof(struct ipa_gsb_mux_hdr)); ipa_gsb_ctx->iface[hdl]->tx_dp_notify( - ipa_gsb_ctx->iface[hdl]->priv, evt, - (unsigned long)skb); + ipa_gsb_ctx->iface[hdl]->priv, evt, + (unsigned long)skb); } static int ipa_gsb_connect_sys_pipe(void) @@ -797,13 +831,23 @@ int ipa_bridge_connect(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG("client hdl: %d\n", hdl); - mutex_lock(&ipa_gsb_ctx->lock); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } if (ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was already connected\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } @@ -811,13 +855,13 @@ int ipa_bridge_connect(u32 hdl) ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to activate ipa pm\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } ret = ipa_gsb_connect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to connect pipe\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } @@ -833,7 +877,7 @@ int ipa_bridge_connect(u32 hdl) IPA_GSB_DBG("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_connect); @@ -871,13 +915,23 @@ int ipa_bridge_disconnect(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG("client hdl: %d\n", hdl); - mutex_lock(&ipa_gsb_ctx->lock); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_DBG("iface was not connected\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } @@ -885,14 +939,14 @@ int ipa_bridge_disconnect(u32 hdl) ret = ipa_gsb_disconnect_sys_pipe(); if (ret) { IPA_GSB_ERR("fail to discon pipes\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } ret = ipa_pm_deactivate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("failed to deactivate ipa pm\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } } @@ -910,7 +964,7 @@ int ipa_bridge_disconnect(u32 hdl) ipa_gsb_ctx->num_resumed_iface); } - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_disconnect); @@ -924,25 +978,37 @@ int ipa_bridge_resume(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG_LOW("iface was already resumed\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } - mutex_lock(&ipa_gsb_ctx->lock); - if (ipa_gsb_ctx->num_resumed_iface == 0) { ret = ipa_pm_activate_sync(ipa_gsb_ctx->pm_hdl); if (ret) { IPA_GSB_ERR("fail to activate ipa pm\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } @@ -952,7 +1018,7 @@ int ipa_bridge_resume(u32 hdl) IPA_GSB_ERR( "fail to start con ep %d\n", ret); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } @@ -962,7 +1028,7 @@ int ipa_bridge_resume(u32 hdl) IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_resume); @@ -976,20 +1042,32 @@ int ipa_bridge_suspend(u32 hdl) return -EFAULT; } + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); + return -EFAULT; + } + if (!ipa_gsb_ctx->iface[hdl]->is_connected) { IPA_GSB_ERR("iface is not connected\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return -EFAULT; } if (!ipa_gsb_ctx->iface[hdl]->is_resumed) { IPA_GSB_DBG_LOW("iface was already suspended\n"); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } - mutex_lock(&ipa_gsb_ctx->lock); - if (ipa_gsb_ctx->num_resumed_iface == 1) { ret = ipa_stop_gsi_channel( ipa_gsb_ctx->cons_hdl); @@ -997,7 +1075,7 @@ int ipa_bridge_suspend(u32 hdl) IPA_GSB_ERR( "fail to stop cons ep %d\n", ret); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } @@ -1005,7 +1083,7 @@ int ipa_bridge_suspend(u32 hdl) if (ret) { IPA_GSB_ERR("fail to deactivate ipa pm\n"); ipa_start_gsi_channel(ipa_gsb_ctx->cons_hdl); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } } @@ -1015,7 +1093,7 @@ int ipa_bridge_suspend(u32 hdl) IPA_GSB_DBG_LOW("num resumed iface: %d\n", ipa_gsb_ctx->num_resumed_iface); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return 0; } EXPORT_SYMBOL(ipa_bridge_suspend); @@ -1024,16 +1102,26 @@ int ipa_bridge_set_perf_profile(u32 hdl, u32 bandwidth) { int ret; + if (!ipa_gsb_ctx) { + IPA_GSB_ERR("ipa_gsb_ctx was not initialized\n"); + return -EFAULT; + } + + if (hdl >= MAX_SUPPORTED_IFACE) { + IPA_GSB_ERR("invalid hdl: %d\n", hdl); + return -EINVAL; + } + IPA_GSB_DBG("client hdl: %d, BW: %d\n", hdl, bandwidth); - mutex_lock(&ipa_gsb_ctx->lock); + mutex_lock(&ipa_gsb_ctx->iface_lock[hdl]); ret = ipa_pm_set_perf_profile(ipa_gsb_ctx->pm_hdl, bandwidth); if (ret) IPA_GSB_ERR("fail to set perf profile\n"); - mutex_unlock(&ipa_gsb_ctx->lock); + mutex_unlock(&ipa_gsb_ctx->iface_lock[hdl]); return ret; } EXPORT_SYMBOL(ipa_bridge_set_perf_profile); @@ -1047,6 +1135,11 @@ int ipa_bridge_tx_dp(u32 hdl, struct sk_buff *skb, IPA_GSB_DBG_LOW("client hdl: %d\n", hdl); + if (!ipa_gsb_ctx->iface[hdl]) { + IPA_GSB_ERR("fail to find interface, hdl: %d\n", hdl); + return -EFAULT; + } + /* make sure skb has enough headroom */ if (unlikely(skb_headroom(skb) < sizeof(struct ipa_gsb_mux_hdr))) { IPA_GSB_DBG_LOW("skb doesn't have enough headroom\n"); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index 10468f34c85b352c58337e5669405f7fc7242c66..6f9afa678dfbd01aca98cf1ef03859c201e68432 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -3938,11 +3938,8 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, } ipa_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); - if (ipa_ctx->logbuf == NULL) { - IPAERR("failed to get logbuf\n"); - result = -ENOMEM; - goto fail_logbuf; - } + if (ipa_ctx->logbuf == NULL) + IPADBG("failed to create IPC log, continue...\n"); ipa_ctx->pdev = ipa_dev; ipa_ctx->uc_pdev = ipa_dev; @@ -4488,7 +4485,6 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, kfree(ipa_ctx->ctrl); fail_mem_ctrl: ipc_log_context_destroy(ipa_ctx->logbuf); -fail_logbuf: kfree(ipa_ctx); ipa_ctx = NULL; fail_mem_ctx: diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index c2f7aae63a1241e5e777443a4e416d3c9658b36c..0224f98f2812cb99fb89468f8c9c1afa82a7a48e 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -91,6 +91,7 @@ const char *ipa_event_name[] = { __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT), __stringify(ADD_BRIDGE_VLAN_MAPPING), __stringify(DEL_BRIDGE_VLAN_MAPPING), + __stringify(WLAN_FWR_SSR_BEFORE_SHUTDOWN), }; const char *ipa_hdr_l2_type_name[] = { @@ -1903,7 +1904,7 @@ static ssize_t ipa_enable_ipc_low(struct file *file, ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa_low", 0); if (ipa_ipc_low_buff == NULL) - IPAERR("failed to get logbuf_low\n"); + IPADBG("failed to get logbuf_low\n"); } ipa_ctx->logbuf_low = ipa_ipc_low_buff; } else { diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index 130afc729c2192970e3378cc5224a73b57522cb1..e7abbe9410fa5d6f5872ef1e87e25e73a29d6312 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -53,6 +53,7 @@ #define IPA_WWAN_DEV_NAME "rmnet_ipa%d" #define IPA_UPSTEAM_WLAN_IFACE_NAME "wlan0" +#define IPA_UPSTEAM_WLAN1_IFACE_NAME "wlan1" #define IPA_WWAN_DEVICE_COUNT (1) @@ -790,7 +791,8 @@ static enum ipa_upstream_type find_upstream_type(const char *upstreamIface) return IPA_UPSTEAM_MODEM; } - if (strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) + if ((strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) || + (strcmp(IPA_UPSTEAM_WLAN1_IFACE_NAME, upstreamIface) == 0)) return IPA_UPSTEAM_WLAN; else return IPA_UPSTEAM_MAX; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index c7422c79533fa2d26b9ac035128309cfed84a350..5bfb8e4d030444314ccd129e5873a4e59e27f828 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -5018,7 +5018,7 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->logbuf = ipc_log_context_create(IPA_IPC_LOG_PAGES, "ipa", 0); if (ipa3_ctx->logbuf == NULL) - IPAERR("failed to create IPC log, continue...\n"); + IPADBG("failed to create IPC log, continue...\n"); /* ipa3_ctx->pdev and ipa3_ctx->uc_pdev will be set in the smmu probes*/ ipa3_ctx->master_pdev = ipa_pdev; @@ -6205,15 +6205,17 @@ static int ipa_smmu_ap_cb_probe(struct device *dev) } IPADBG("AP/USB SMMU atomic set\n"); - if (iommu_domain_set_attr(cb->mapping->domain, + if (smmu_info.fast_map) { + if (iommu_domain_set_attr(cb->mapping->domain, DOMAIN_ATTR_FAST, &fast)) { - IPAERR("couldn't set fast map\n"); - arm_iommu_release_mapping(cb->mapping); - cb->valid = false; - return -EIO; + IPAERR("couldn't set fast map\n"); + arm_iommu_release_mapping(cb->mapping); + cb->valid = false; + return -EIO; + } + IPADBG("SMMU fast map set\n"); } - IPADBG("SMMU fast map set\n"); } pr_info("IPA smmu_info.s1_bypass_arr[AP]=%d smmu_info.fast_map=%d\n", diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 5bcd49ec24bf885d6fa7f79735f20d1aec1eb5e2..cfac126312b719cca29ba61d30160d4153208e12 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -63,7 +63,15 @@ int ipa3_enable_data_path(u32 clnt_hdl) IPADBG("Enabling data path\n"); if (IPA_CLIENT_IS_CONS(ep->client)) { memset(&holb_cfg, 0, sizeof(holb_cfg)); - holb_cfg.en = IPA_HOLB_TMR_DIS; + /* + * Set HOLB on USB DPL CONS to avoid IPA stall + * if DPL client is not pulling the data + * on other end from IPA hw. + */ + if (ep->client == IPA_CLIENT_USB_DPL_CONS) + holb_cfg.en = IPA_HOLB_TMR_EN; + else + holb_cfg.en = IPA_HOLB_TMR_DIS; holb_cfg.tmr_val = 0; res = ipa3_cfg_ep_holb(clnt_hdl, &holb_cfg); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 10abdcf4549969b0cb81e4ae62a79ebf98f3333a..0925e8c885b932be1558d5684b29b0436b24880f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -75,6 +75,7 @@ const char *ipa3_event_name[] = { __stringify(IPA_PER_CLIENT_STATS_DISCONNECT_EVENT), __stringify(ADD_BRIDGE_VLAN_MAPPING), __stringify(DEL_BRIDGE_VLAN_MAPPING), + __stringify(WLAN_FWR_SSR_BEFORE_SHUTDOWN), }; const char *ipa3_hdr_l2_type_name[] = { @@ -2089,7 +2090,7 @@ static ssize_t ipa3_enable_ipc_low(struct file *file, "ipa_low", 0); } if (ipa_ipc_low_buff == NULL) - IPAERR("failed to get logbuf_low\n"); + IPADBG("failed to get logbuf_low\n"); ipa3_ctx->logbuf_low = ipa_ipc_low_buff; } else { ipa3_ctx->logbuf_low = NULL; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c index 7065e2c270e339adc083d87f35c8279cf8ac8048..2716d4aa396a943e0f91be4ea37925f432c56b8d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c @@ -1516,6 +1516,8 @@ int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del) ipa3_ctx->nat_mem.pdn_mem.size, ipa3_ctx->nat_mem.pdn_mem.base, ipa3_ctx->nat_mem.pdn_mem.phys_base); + ipa3_ctx->nat_mem.pdn_mem.base = NULL; + ipa3_ctx->nat_mem.dev.is_mem_allocated = false; } ipa3_nat_ipv6ct_free_mem(&ipa3_ctx->nat_mem.dev); diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index f1e2e6df037f4570070ac8d7c07fe4d7d2711b02..5ec331c1fb0b2766acbd8035c81a83f5874c4033 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -53,6 +53,7 @@ #define IPA_WWAN_DEV_NAME "rmnet_ipa%d" #define IPA_UPSTEAM_WLAN_IFACE_NAME "wlan0" +#define IPA_UPSTEAM_WLAN1_IFACE_NAME "wlan1" #define IPA_WWAN_RX_SOFTIRQ_THRESH 16 @@ -820,7 +821,8 @@ static enum ipa_upstream_type find_upstream_type(const char *upstreamIface) return IPA_UPSTEAM_MODEM; } - if (strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) + if ((strcmp(IPA_UPSTEAM_WLAN_IFACE_NAME, upstreamIface) == 0) || + (strcmp(IPA_UPSTEAM_WLAN1_IFACE_NAME, upstreamIface) == 0)) return IPA_UPSTEAM_WLAN; else return MAX_NUM_OF_MUX_CHANNEL; diff --git a/drivers/platform/msm/mhi_dev/mhi.h b/drivers/platform/msm/mhi_dev/mhi.h index 35590210bfe6e4b5c6253bec4fabb2fe9f33ea26..6cb2d7d270d3b4339e550391c122474d6327ebc3 100644 --- a/drivers/platform/msm/mhi_dev/mhi.h +++ b/drivers/platform/msm/mhi_dev/mhi.h @@ -14,9 +14,8 @@ #define __MHI_H #include -#include #include -#include +#include /** * MHI control data structures alloted by the host, including @@ -276,8 +275,6 @@ struct mhi_config { #define MHI_MASK_ROWS_CH_EV_DB 4 #define TRB_MAX_DATA_SIZE 8192 #define MHI_CTRL_STATE 100 -#define IPA_DMA_SYNC 1 -#define IPA_DMA_ASYNC 0 /*maximum trasnfer completion events buffer*/ #define MAX_TR_EVENTS 50 @@ -360,13 +357,6 @@ enum mhi_dev_ch_operation { MHI_DEV_POLL, }; -enum mhi_ctrl_info { - MHI_STATE_CONFIGURED = 0, - MHI_STATE_CONNECTED = 1, - MHI_STATE_DISCONNECTED = 2, - MHI_STATE_INVAL, -}; - enum mhi_dev_tr_compl_evt_type { SEND_EVENT_BUFFER, SEND_EVENT_RD_OFFSET, @@ -420,38 +410,6 @@ static inline void mhi_dev_ring_inc_index(struct mhi_dev_ring *ring, #define MHI_DEV_MMIO_RANGE 0xc80 -enum cb_reason { - MHI_DEV_TRE_AVAILABLE = 0, - MHI_DEV_CTRL_UPDATE, -}; - -struct mhi_dev_client_cb_reason { - uint32_t ch_id; - enum cb_reason reason; -}; - -struct mhi_dev_client { - struct list_head list; - struct mhi_dev_channel *channel; - void (*event_trigger)(struct mhi_dev_client_cb_reason *cb); - - /* mhi_dev calls are fully synchronous -- only one call may be - * active per client at a time for now. - */ - struct mutex write_lock; - wait_queue_head_t wait; - - /* trace logs */ - spinlock_t tr_lock; - unsigned int tr_head; - unsigned int tr_tail; - struct mhi_dev_trace *tr_log; - - /* client buffers */ - struct mhi_dev_iov *iov; - uint32_t nr_iov; -}; - struct ring_cache_req { struct completion *done; void *context; @@ -609,32 +567,15 @@ struct mhi_dev { /* MHI state info */ enum mhi_ctrl_info ctrl_info; - /*Register for interrupt */ + /*Register for interrupt*/ bool mhi_int; bool mhi_int_en; - /* Registered client callback list */ struct list_head client_cb_list; struct kobj_uevent_env kobj_env; }; -struct mhi_req { - u32 chan; - u32 mode; - u32 chain; - void *buf; - dma_addr_t dma; - u32 snd_cmpl; - void *context; - size_t len; - size_t actual_len; - uint32_t rd_offset; - struct mhi_dev_client *client; - struct list_head list; - union mhi_dev_ring_element_type *el; - void (*client_cb)(void *req); -}; enum mhi_msg_level { MHI_MSG_VERBOSE = 0x0, @@ -660,72 +601,8 @@ extern void *mhi_ipc_log; } \ } while (0) -/* SW channel client list */ -enum mhi_client_channel { - MHI_CLIENT_LOOPBACK_OUT = 0, - MHI_CLIENT_LOOPBACK_IN = 1, - MHI_CLIENT_SAHARA_OUT = 2, - MHI_CLIENT_SAHARA_IN = 3, - MHI_CLIENT_DIAG_OUT = 4, - MHI_CLIENT_DIAG_IN = 5, - MHI_CLIENT_SSR_OUT = 6, - MHI_CLIENT_SSR_IN = 7, - MHI_CLIENT_QDSS_OUT = 8, - MHI_CLIENT_QDSS_IN = 9, - MHI_CLIENT_EFS_OUT = 10, - MHI_CLIENT_EFS_IN = 11, - MHI_CLIENT_MBIM_OUT = 12, - MHI_CLIENT_MBIM_IN = 13, - MHI_CLIENT_QMI_OUT = 14, - MHI_CLIENT_QMI_IN = 15, - MHI_CLIENT_IP_CTRL_0_OUT = 16, - MHI_CLIENT_IP_CTRL_0_IN = 17, - MHI_CLIENT_IP_CTRL_1_OUT = 18, - MHI_CLIENT_IP_CTRL_1_IN = 19, - MHI_CLIENT_DCI_OUT = 20, - MHI_CLIENT_DCI_IN = 21, - MHI_CLIENT_IP_CTRL_3_OUT = 22, - MHI_CLIENT_IP_CTRL_3_IN = 23, - MHI_CLIENT_IP_CTRL_4_OUT = 24, - MHI_CLIENT_IP_CTRL_4_IN = 25, - MHI_CLIENT_IP_CTRL_5_OUT = 26, - MHI_CLIENT_IP_CTRL_5_IN = 27, - MHI_CLIENT_IP_CTRL_6_OUT = 28, - MHI_CLIENT_IP_CTRL_6_IN = 29, - MHI_CLIENT_IP_CTRL_7_OUT = 30, - MHI_CLIENT_IP_CTRL_7_IN = 31, - MHI_CLIENT_DUN_OUT = 32, - MHI_CLIENT_DUN_IN = 33, - MHI_CLIENT_IP_SW_0_OUT = 34, - MHI_CLIENT_IP_SW_0_IN = 35, - MHI_CLIENT_IP_SW_1_OUT = 36, - MHI_CLIENT_IP_SW_1_IN = 37, - MHI_CLIENT_IP_SW_2_OUT = 38, - MHI_CLIENT_IP_SW_2_IN = 39, - MHI_CLIENT_IP_SW_3_OUT = 40, - MHI_CLIENT_IP_SW_3_IN = 41, - MHI_CLIENT_CSVT_OUT = 42, - MHI_CLIENT_CSVT_IN = 43, - MHI_CLIENT_SMCT_OUT = 44, - MHI_CLIENT_SMCT_IN = 45, - MHI_CLIENT_IP_SW_4_OUT = 46, - MHI_CLIENT_IP_SW_4_IN = 47, - MHI_CLIENT_ADB_OUT = 48, - MHI_CLIENT_ADB_IN = 49, - MHI_MAX_SOFTWARE_CHANNELS, - MHI_CLIENT_TEST_OUT = 60, - MHI_CLIENT_TEST_IN = 61, - MHI_CLIENT_RESERVED_1_LOWER = 62, - MHI_CLIENT_RESERVED_1_UPPER = 99, - MHI_CLIENT_IP_HW_0_OUT = 100, - MHI_CLIENT_IP_HW_0_IN = 101, - MHI_CLIENT_RESERVED_2_LOWER = 102, - MHI_CLIENT_RESERVED_2_UPPER = 127, - MHI_MAX_CHANNELS = 102, - MHI_CLIENT_INVALID = 0xFFFFFFFF -}; -/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 is used for internal only */ +/* Use ID 0 for legacy /dev/mhi_ctrl. Channel 0 used for internal only */ #define MHI_DEV_UEVENT_CTRL 0 struct mhi_dev_uevent_info { @@ -738,58 +615,6 @@ struct mhi_dev_iov { uint32_t buf_size; }; -struct mhi_dev_client_cb_data { - void *user_data; - enum mhi_client_channel channel; - enum mhi_ctrl_info ctrl_info; -}; - -typedef void (*mhi_state_cb)(struct mhi_dev_client_cb_data *cb_dat); - -struct mhi_dev_ready_cb_info { - struct list_head list; - mhi_state_cb cb; - struct mhi_dev_client_cb_data cb_data; -}; - -/** - * mhi_dev_open_channel() - Channel open for a given client done prior - * to read/write. - * @chan_id: Software Channel ID for the assigned client. - * @handle_client: Structure device for client handle. - * @notifier: Client issued callback notification. - */ -int mhi_dev_open_channel(uint32_t chan_id, - struct mhi_dev_client **handle_client, - void (*event_trigger)(struct mhi_dev_client_cb_reason *cb)); -/** - * mhi_dev_close_channel() - Channel close for a given client. - */ -int mhi_dev_close_channel(struct mhi_dev_client *handle_client); - -/** - * mhi_dev_read_channel() - Channel read for a given client - * @mreq: mreq is the client argument which includes meta info - * like write data location, buffer len, read offset, mode, - * chain and client call back function which will be invoked - * when data read is completed. - */ -int mhi_dev_read_channel(struct mhi_req *mreq); - -/** - * mhi_dev_write_channel() - Channel write for a given software client. - * @wreq wreq is the client argument which includes meta info like - * client handle, read data location, buffer length, mode, - * and client call back function which will free the packet. - * when data write is completed. - */ -int mhi_dev_write_channel(struct mhi_req *wreq); - -/** - * mhi_dev_channel_isempty() - Checks if there is any pending TRE's to process. - * @handle_client: Client Handle issued during mhi_dev_open_channel - */ -int mhi_dev_channel_isempty(struct mhi_dev_client *handle); struct mhi_dev_trace { unsigned int timestamp; @@ -1067,7 +892,7 @@ int mhi_dev_mmio_read_chdb_status_interrupts(struct mhi_dev *dev); int mhi_dev_mmio_enable_erdb_interrupts(struct mhi_dev *dev); /** - * mhi_dev_mmio_mask_erdb_interrupts() - Mask all Event doorbell + *mhi_dev_mmio_mask_erdb_interrupts() - Mask all Event doorbell * interrupts. * @dev: MHI device structure. */ @@ -1258,43 +1083,8 @@ int mhi_uci_init(void); */ int mhi_dev_net_interface_init(void); -/** - * mhi_dev_net_exit() - Clean up and close MHI Network interface module. - */ -void mhi_dev_net_exit(void); - -/** - * mhi_dev_notify_a7_event() - Used by PCIe driver to notify A7 MHI device - * interrupt after doorbell is received. Used by PCIe driver when MHI - * A7 interrupts are routed to PCIe instead of MHI device. - */ void mhi_dev_notify_a7_event(struct mhi_dev *mhi); -/** - * mhi_ctrl_state_info() - Provide MHI state info - * @idx: Channel number idx. Look at channel_state_info and - * pass the index for the corresponding channel. - * @info: Return the control info. - * MHI_STATE=CONFIGURED - MHI device is present but not ready - * for data traffic. - * MHI_STATE=CONNECTED - MHI device is ready for data transfer. - * MHI_STATE=DISCONNECTED - MHI device has its pipes suspended. - * exposes device nodes for the supported MHI software - * channels. - */ -int mhi_ctrl_state_info(uint32_t idx, uint32_t *info); - -/** - * uci_ctrl_update() - Update UCI once TRE's are available for clients to - * consume. - */ void uci_ctrl_update(struct mhi_dev_client_cb_reason *reason); -/** - * mhi_register_state_cb() - Clients can register and receive callback after - * MHI channel is connected or disconnected. - */ -int mhi_register_state_cb(void (*mhi_state_cb) - (struct mhi_dev_client_cb_data *cb_data), void *data, - enum mhi_client_channel channel); -#endif /* _MHI_H_ */ +#endif /* _MHI_H */ diff --git a/drivers/platform/msm/mhi_dev/mhi_ring.c b/drivers/platform/msm/mhi_dev/mhi_ring.c index d6791eab3a107af0a9f108fdafacc32ee33328de..92b061648cd88800a4ade3c0943faa4503da6137 100644 --- a/drivers/platform/msm/mhi_dev/mhi_ring.c +++ b/drivers/platform/msm/mhi_dev/mhi_ring.c @@ -278,11 +278,12 @@ EXPORT_SYMBOL(mhi_dev_process_ring); int mhi_dev_add_element(struct mhi_dev_ring *ring, union mhi_dev_ring_element_type *element, - struct event_req *ereq, int evt_offset) + struct event_req *ereq, int size) { uint32_t old_offset = 0; struct mhi_addr host_addr; - uint32_t num_elem = 0; + uint32_t num_elem = 1; + uint32_t num_free_elem; if (!ring || !element) { pr_err("%s: Invalid context\n", __func__); @@ -291,16 +292,24 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, mhi_dev_update_wr_offset(ring); - if ((ring->rd_offset + 1) % ring->ring_size == ring->wr_offset) { - mhi_log(MHI_MSG_VERBOSE, "ring full to insert element\n"); + if (ereq) + num_elem = size / (sizeof(union mhi_dev_ring_element_type)); + + if (ring->rd_offset < ring->wr_offset) + num_free_elem = ring->wr_offset - ring->rd_offset - 1; + else + num_free_elem = ring->ring_size - ring->rd_offset + + ring->wr_offset - 1; + + if (num_free_elem < num_elem) { + mhi_log(MHI_MSG_ERROR, "No space to add %d elem in ring (%d)\n", + num_elem, ring->id); return -EINVAL; } old_offset = ring->rd_offset; - if (evt_offset) { - num_elem = evt_offset / - (sizeof(union mhi_dev_ring_element_type)); + if (ereq) { ring->rd_offset += num_elem; if (ring->rd_offset >= ring->ring_size) ring->rd_offset -= ring->ring_size; @@ -322,23 +331,47 @@ int mhi_dev_add_element(struct mhi_dev_ring *ring, host_addr.device_va = ring->ring_shadow.device_va + sizeof(union mhi_dev_ring_element_type) * old_offset; - host_addr.virt_addr = element; - - if (evt_offset) - host_addr.size = evt_offset; - else + if (!ereq) { + /* We're adding only a single ring element */ + host_addr.virt_addr = element; host_addr.size = sizeof(union mhi_dev_ring_element_type); - mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", ring->id); - mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset); - mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type); + mhi_log(MHI_MSG_VERBOSE, "adding element to ring (%d)\n", + ring->id); + mhi_log(MHI_MSG_VERBOSE, "rd_ofset %d\n", ring->rd_offset); + mhi_log(MHI_MSG_VERBOSE, "type %d\n", element->generic.type); - if (ereq) mhi_dev_write_to_host(ring->mhi_dev, &host_addr, - ereq, MHI_DEV_DMA_ASYNC); - else + NULL, MHI_DEV_DMA_SYNC); + return 0; + } + + /* Adding multiple ring elements */ + if (ring->rd_offset == 0 || (ring->rd_offset > old_offset)) { + /* No wrap-around case */ + host_addr.virt_addr = element; + host_addr.size = size; + mhi_dev_write_to_host(ring->mhi_dev, &host_addr, + ereq, MHI_DEV_DMA_ASYNC); + } else { + /* Wrap-around case - first chunk uses dma sync */ + host_addr.virt_addr = element; + host_addr.size = (ring->ring_size - old_offset) * + sizeof(union mhi_dev_ring_element_type); + mhi_dev_write_to_host(ring->mhi_dev, &host_addr, + NULL, MHI_DEV_DMA_SYNC); + + /* Copy remaining elements */ + if (ring->mhi_dev->use_ipa) + host_addr.host_pa = ring->ring_shadow.host_pa; + else + host_addr.device_va = ring->ring_shadow.device_va; + host_addr.virt_addr = element + (ring->ring_size - old_offset); + host_addr.size = ring->rd_offset * + sizeof(union mhi_dev_ring_element_type); mhi_dev_write_to_host(ring->mhi_dev, &host_addr, - NULL, MHI_DEV_DMA_SYNC); + ereq, MHI_DEV_DMA_ASYNC); + } return 0; } EXPORT_SYMBOL(mhi_dev_add_element); diff --git a/drivers/platform/msm/mhi_dev/mhi_sm.h b/drivers/platform/msm/mhi_dev/mhi_sm.h index 01e127b77f20c711a1b89aa28959bd36536fa975..4b9307d6c71d3a29a2f7d519f454275200a3c162 100644 --- a/drivers/platform/msm/mhi_dev/mhi_sm.h +++ b/drivers/platform/msm/mhi_dev/mhi_sm.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015,2017-2018 The Linux Foundation. All rights reserved. +/* Copyright (c) 2015,2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index 6e54fbfae6718bd9c12ab488b9d4dde604324830..05a8c66d57aa45933e417644afbee4807afafcc0 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -1020,8 +1020,6 @@ static void sps_device_de_init(void) "sps:%s:BAMs are still registered", __func__); sps_map_de_init(); - - kfree(sps); } sps_mem_de_init(); @@ -3006,6 +3004,7 @@ static struct platform_driver msm_sps_driver = { .name = SPS_DRV_NAME, .owner = THIS_MODULE, .of_match_table = msm_sps_match, + .suppress_bind_attrs = true, }, .remove = msm_sps_remove, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 8a1bfd489c26865cb5c867e4db1adfc79c12a31e..ed277685da1db3c5d2f22cf2a1f4fa3d29493d10 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -161,6 +161,16 @@ MODULE_LICENSE("GPL"); static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL }; +static bool ashs_present(void) +{ + int i = 0; + while (ashs_ids[i]) { + if (acpi_dev_found(ashs_ids[i++])) + return true; + } + return false; +} + struct bios_args { u32 arg0; u32 arg1; @@ -966,6 +976,9 @@ static int asus_new_rfkill(struct asus_wmi *asus, static void asus_wmi_rfkill_exit(struct asus_wmi *asus) { + if (asus->driver->wlan_ctrl_by_user && ashs_present()) + return; + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); @@ -2062,16 +2075,6 @@ static int asus_wmi_fan_init(struct asus_wmi *asus) return 0; } -static bool ashs_present(void) -{ - int i = 0; - while (ashs_ids[i]) { - if (acpi_dev_found(ashs_ids[i++])) - return true; - } - return false; -} - /* * WMI Driver */ diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 8281c413ca3426c5368dab998d9c44038f47f0c4..a0b9bca138b3c174fb8d4afaeb3033585e8405cb 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -339,6 +339,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(esr_nominal), POWER_SUPPLY_ATTR(soh), POWER_SUPPLY_ATTR(qc_opti_disable), + POWER_SUPPLY_ATTR(fcc_stepper_enable), /* Local extensions of type int64_t */ POWER_SUPPLY_ATTR(charge_counter_ext), /* Properties of type `const char *' */ diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index b3bf42a2fb2de723138b0ef0a4802867c3a12d3a..b0ff18c5cdb062c48f3a95e65c643e1610168eaf 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -134,6 +134,7 @@ struct qpnp_qg { u32 esr_last; ktime_t last_user_update_time; ktime_t last_fifo_update_time; + unsigned long last_maint_soc_update_time; /* soc params */ int catch_up_soc; @@ -143,6 +144,9 @@ struct qpnp_qg { int batt_soc; int cc_soc; int full_soc; + int sys_soc; + int last_adj_ssoc; + int recharge_soc; struct alarm alarm_timer; u32 sdam_data[SDAM_MAX]; diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c index af8b158b7c9575f14e668b05a742a67b2dc40667..711bd2b9e4539328329cbc735b5517521900a99d 100644 --- a/drivers/power/supply/qcom/qg-soc.c +++ b/drivers/power/supply/qcom/qg-soc.c @@ -17,15 +17,19 @@ #include #include #include +#include #include "fg-alg.h" #include "qg-sdam.h" #include "qg-core.h" #include "qg-reg.h" #include "qg-util.h" #include "qg-defs.h" +#include "qg-soc.h" #define DEFAULT_UPDATE_TIME_MS 64000 #define SOC_SCALE_HYST_MS 2000 +#define VBAT_LOW_HYST_UV 50000 +#define FULL_SOC 100 static int qg_delta_soc_interval_ms = 20000; module_param_named( @@ -37,6 +41,44 @@ module_param_named( soc_cold_interval_ms, qg_delta_soc_cold_interval_ms, int, 0600 ); +static int qg_maint_soc_update_ms = 120000; +module_param_named( + maint_soc_update_ms, qg_maint_soc_update_ms, int, 0600 +); + +int qg_adjust_sys_soc(struct qpnp_qg *chip) +{ + int soc, vbat_uv, rc; + int vcutoff_uv = chip->dt.vbatt_cutoff_mv * 1000; + + chip->sys_soc = CAP(QG_MIN_SOC, QG_MAX_SOC, chip->sys_soc); + + if (chip->sys_soc == QG_MIN_SOC) { + /* Hold SOC to 1% of VBAT has not dropped below cutoff */ + rc = qg_get_battery_voltage(chip, &vbat_uv); + if (!rc && vbat_uv >= (vcutoff_uv + VBAT_LOW_HYST_UV)) + soc = 1; + else + soc = 0; + } else if (chip->sys_soc == QG_MAX_SOC) { + soc = FULL_SOC; + } else if (chip->sys_soc >= (QG_MAX_SOC - 100)) { + /* Hold SOC to 100% if we are dropping from 100 to 99 */ + if (chip->last_adj_ssoc == FULL_SOC) + soc = FULL_SOC; + else /* Hold SOC at 99% until we hit 100% */ + soc = FULL_SOC - 1; + } else { + soc = DIV_ROUND_CLOSEST(chip->sys_soc, 100); + } + + qg_dbg(chip, QG_DEBUG_SOC, "last_adj_sys_soc=%d adj_sys_soc=%d\n", + chip->last_adj_ssoc, soc); + chip->last_adj_ssoc = soc; + + return soc; +} + static void get_next_update_time(struct qpnp_qg *chip) { int soc_points = 0, batt_temp = 0; @@ -56,10 +98,11 @@ static void get_next_update_time(struct qpnp_qg *chip) /* Lower the delta soc interval by half at cold */ rc = qg_get_battery_temp(chip, &batt_temp); - if (rc < 0) - pr_err("Failed to read battery temperature rc=%d\n", rc); - else if (batt_temp < chip->dt.cold_temp_threshold) + if (!rc && batt_temp < chip->dt.cold_temp_threshold) min_delta_soc_interval_ms = qg_delta_soc_cold_interval_ms; + else if (chip->maint_soc > 0 && chip->maint_soc >= chip->recharge_soc) + /* if in maintenance mode scale slower */ + min_delta_soc_interval_ms = qg_maint_soc_update_ms; if (!min_delta_soc_interval_ms) min_delta_soc_interval_ms = 1000; /* 1 second */ @@ -98,9 +141,34 @@ static bool is_scaling_required(struct qpnp_qg *chip) return true; } +static bool maint_soc_timeout(struct qpnp_qg *chip) +{ + unsigned long now; + int rc; + + if (chip->maint_soc < 0) + return false; + + rc = get_rtc_time(&now); + if (rc < 0) + return true; + + /* Do not scale if we have dropped below recharge-soc */ + if (chip->maint_soc < chip->recharge_soc) + return true; + + if ((now - chip->last_maint_soc_update_time) >= + (qg_maint_soc_update_ms / 1000)) { + chip->last_maint_soc_update_time = now; + return true; + } + + return false; +} + static void update_msoc(struct qpnp_qg *chip) { - int rc = 0, batt_temp = 0, batt_soc_32bit = 0; + int rc = 0, sdam_soc, batt_temp = 0, batt_soc_32bit = 0; bool usb_present = is_usb_present(chip); if (chip->catch_up_soc > chip->msoc) { @@ -113,7 +181,8 @@ static void update_msoc(struct qpnp_qg *chip) } chip->msoc = CAP(0, 100, chip->msoc); - if (chip->maint_soc > 0 && chip->msoc < chip->maint_soc) { + if (chip->maint_soc > 0 && chip->msoc < chip->maint_soc + && maint_soc_timeout(chip)) { chip->maint_soc -= chip->dt.delta_soc; chip->maint_soc = CAP(0, 100, chip->maint_soc); } @@ -128,8 +197,9 @@ static void update_msoc(struct qpnp_qg *chip) pr_err("Failed to update MSOC register rc=%d\n", rc); /* update SDAM with the new MSOC */ - chip->sdam_data[SDAM_SOC] = chip->msoc; - rc = qg_sdam_write(SDAM_SOC, chip->msoc); + sdam_soc = (chip->maint_soc > 0) ? chip->maint_soc : chip->msoc; + chip->sdam_data[SDAM_SOC] = sdam_soc; + rc = qg_sdam_write(SDAM_SOC, sdam_soc); if (rc < 0) pr_err("Failed to update SDAM with MSOC rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/qg-soc.h b/drivers/power/supply/qcom/qg-soc.h index 3b4eb6031c1a5a14faa45d919218056aeeeda2b6..cd64bd5de79223086915ab57b0ed1408a6acedae 100644 --- a/drivers/power/supply/qcom/qg-soc.h +++ b/drivers/power/supply/qcom/qg-soc.h @@ -16,5 +16,6 @@ int qg_scale_soc(struct qpnp_qg *chip, bool force_soc); int qg_soc_init(struct qpnp_qg *chip); void qg_soc_exit(struct qpnp_qg *chip); +int qg_adjust_sys_soc(struct qpnp_qg *chip); #endif /* __QG_SOC_H__ */ diff --git a/drivers/power/supply/qcom/qg-util.c b/drivers/power/supply/qcom/qg-util.c index 85efdbf54efc41ffa5e50c6067a29e2b474824c5..a3e045e93f358308e23a76d6ed4a695315e12ec5 100644 --- a/drivers/power/supply/qcom/qg-util.c +++ b/drivers/power/supply/qcom/qg-util.c @@ -367,3 +367,25 @@ int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua) BURST_AVG_HOLD_FOR_READ_BIT, 0); return rc; } + +int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv) +{ + int rc = 0; + u64 last_vbat = 0; + + if (chip->battery_missing) { + *vbat_uv = 3700000; + return 0; + } + + rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG, + (u8 *)&last_vbat, 2); + if (rc < 0) { + pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc); + return rc; + } + + *vbat_uv = V_RAW_TO_UV(last_vbat); + + return rc; +} diff --git a/drivers/power/supply/qcom/qg-util.h b/drivers/power/supply/qcom/qg-util.h index 2dbafe7973db1a09ee0b516fc87264db0c5d822d..5dd6c85728f833f66422dd37dc3e4b4a9cdd2789 100644 --- a/drivers/power/supply/qcom/qg-util.h +++ b/drivers/power/supply/qcom/qg-util.h @@ -26,5 +26,6 @@ bool is_parallel_enabled(struct qpnp_qg *chip); int qg_write_monotonic_soc(struct qpnp_qg *chip, int msoc); int qg_get_battery_temp(struct qpnp_qg *chip, int *batt_temp); int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua); +int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv); #endif diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index d1b6beaa8507b36e358484a0ef3fdd5ba1cb239e..fede66fd574122d59939b3d1f4020c4f40c50873 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -452,13 +452,11 @@ static int qg_process_rt_fifo(struct qpnp_qg *chip) } #define MIN_FIFO_FULL_TIME_MS 12000 -static int process_rt_fifo_data(struct qpnp_qg *chip, - bool update_vbat_low, bool update_smb) +static int process_rt_fifo_data(struct qpnp_qg *chip, bool update_smb) { int rc = 0; ktime_t now = ktime_get(); s64 time_delta; - u8 fifo_length; /* * Reject the FIFO read event if there are back-to-back requests @@ -467,11 +465,10 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, */ time_delta = ktime_ms_delta(now, chip->last_user_update_time); - qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_vbat_low=%d update_smb=%d\n", - time_delta, update_vbat_low, update_smb); + qg_dbg(chip, QG_DEBUG_FIFO, "time_delta=%lld ms update_smb=%d\n", + time_delta, update_smb); - if (time_delta > MIN_FIFO_FULL_TIME_MS || update_vbat_low - || update_smb) { + if (time_delta > MIN_FIFO_FULL_TIME_MS || update_smb) { rc = qg_master_hold(chip, true); if (rc < 0) { pr_err("Failed to hold master, rc=%d\n", rc); @@ -484,20 +481,6 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, goto done; } - if (update_vbat_low) { - /* change FIFO length */ - fifo_length = chip->vbat_low ? - chip->dt.s2_vbat_low_fifo_length : - chip->dt.s2_fifo_length; - rc = qg_update_fifo_length(chip, fifo_length); - if (rc < 0) - goto done; - - qg_dbg(chip, QG_DEBUG_STATUS, - "FIFO length updated to %d vbat_low=%d\n", - fifo_length, chip->vbat_low); - } - if (update_smb) { rc = qg_masked_write(chip, chip->qg_base + QG_MODE_CTL1_REG, PARALLEL_IBAT_SENSE_EN_BIT, @@ -539,60 +522,67 @@ static int process_rt_fifo_data(struct qpnp_qg *chip, static int qg_vbat_low_wa(struct qpnp_qg *chip) { int rc, i, temp = 0; - u32 vbat_low_uv = 0; + u32 vbat_low_uv = 0, fifo_length = 0; - rc = qg_get_battery_temp(chip, &temp); - if (rc < 0) { - pr_err("Failed to read batt_temp rc=%d\n", rc); - temp = 250; + if ((chip->wa_flags & QG_VBAT_LOW_WA) && chip->vbat_low) { + rc = qg_get_battery_temp(chip, &temp); + if (rc < 0) { + pr_err("Failed to read batt_temp rc=%d\n", rc); + temp = 250; + } + + vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? + chip->dt.vbatt_low_cold_mv : + chip->dt.vbatt_low_mv); + vbat_low_uv += VBAT_LOW_HYST_UV; + /* + * PMI632 1.0 does not generate a falling VBAT_LOW IRQ. + * To exit from VBAT_LOW config, check if any of the FIFO + * averages is > vbat_low threshold and reconfigure the + * FIFO length to normal. + */ + for (i = 0; i < chip->kdata.fifo_length; i++) { + if (chip->kdata.fifo[i].v > vbat_low_uv) { + chip->vbat_low = false; + pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n", + chip->kdata.fifo[i].v, vbat_low_uv, + chip->dt.s2_fifo_length); + break; + } + } } - vbat_low_uv = 1000 * ((temp < chip->dt.cold_temp_threshold) ? - chip->dt.vbatt_low_cold_mv : - chip->dt.vbatt_low_mv); - vbat_low_uv += VBAT_LOW_HYST_UV; + rc = get_fifo_length(chip, &fifo_length, false); + if (rc < 0) { + pr_err("Failed to get FIFO length, rc=%d\n", rc); + return rc; + } - if (!(chip->wa_flags & QG_VBAT_LOW_WA) || !chip->vbat_low) + if (chip->vbat_low && fifo_length == chip->dt.s2_vbat_low_fifo_length) return 0; - /* - * PMI632 1.0 does not generate a falling VBAT_LOW IRQ. - * To exit from VBAT_LOW config, check if any of the FIFO - * averages is > vbat_low threshold and reconfigure the - * FIFO length to normal. - */ - for (i = 0; i < chip->kdata.fifo_length; i++) { - if (chip->kdata.fifo[i].v > vbat_low_uv) { - rc = qg_master_hold(chip, true); - if (rc < 0) { - pr_err("Failed to hold master, rc=%d\n", rc); - goto done; - } - rc = qg_update_fifo_length(chip, - chip->dt.s2_fifo_length); - if (rc < 0) - goto done; - - rc = qg_master_hold(chip, false); - if (rc < 0) { - pr_err("Failed to release master, rc=%d\n", rc); - goto done; - } - /* FIFOs restarted */ - chip->last_fifo_update_time = ktime_get(); + if (!chip->vbat_low && fifo_length == chip->dt.s2_fifo_length) + return 0; - chip->vbat_low = false; - pr_info("Exit VBAT_LOW vbat_avg=%duV vbat_low=%duV updated fifo_length=%d\n", - chip->kdata.fifo[i].v, vbat_low_uv, - chip->dt.s2_fifo_length); - break; - } + rc = qg_master_hold(chip, true); + if (rc < 0) { + pr_err("Failed to hold master, rc=%d\n", rc); + goto done; } - return 0; + fifo_length = chip->vbat_low ? chip->dt.s2_vbat_low_fifo_length : + chip->dt.s2_fifo_length; + rc = qg_update_fifo_length(chip, fifo_length); + if (rc < 0) + goto done; + + qg_dbg(chip, QG_DEBUG_STATUS, "FIFO length updated to %d vbat_low=%d\n", + fifo_length, chip->vbat_low); done: qg_master_hold(chip, false); + /* FIFOs restarted */ + chip->last_fifo_update_time = ktime_get(); return rc; } @@ -1039,11 +1029,23 @@ static void process_udata_work(struct work_struct *work) if (chip->udata.param[QG_FULL_SOC].valid) chip->full_soc = chip->udata.param[QG_FULL_SOC].data; - if (chip->udata.param[QG_SOC].valid) { - qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n", - chip->udata.param[QG_SOC].data, chip->catch_up_soc); + if (chip->udata.param[QG_SOC].valid || + chip->udata.param[QG_SYS_SOC].valid) { + + qg_dbg(chip, QG_DEBUG_SOC, "udata update: QG_SOC=%d QG_SYS_SOC=%d last_catchup_soc=%d\n", + chip->udata.param[QG_SOC].valid ? + chip->udata.param[QG_SOC].data : -EINVAL, + chip->udata.param[QG_SYS_SOC].valid ? + chip->udata.param[QG_SYS_SOC].data : -EINVAL, + chip->catch_up_soc); + + if (chip->udata.param[QG_SYS_SOC].valid) { + chip->sys_soc = chip->udata.param[QG_SYS_SOC].data; + chip->catch_up_soc = qg_adjust_sys_soc(chip); + } else { + chip->catch_up_soc = chip->udata.param[QG_SOC].data; + } - chip->catch_up_soc = chip->udata.param[QG_SOC].data; qg_scale_soc(chip, false); /* update parameters to SDAM */ @@ -1174,10 +1176,6 @@ static irqreturn_t qg_vbat_low_handler(int irq, void *data) chip->vbat_low = !!(status & VBAT_LOW_INT_RT_STS_BIT); - rc = process_rt_fifo_data(chip, true, false); - if (rc < 0) - pr_err("Failed to process RT FIFO data, rc=%d\n", rc); - qg_dbg(chip, QG_DEBUG_IRQ, "VBAT_LOW = %d\n", chip->vbat_low); done: mutex_unlock(&chip->data_lock); @@ -1514,28 +1512,6 @@ static const char *qg_get_battery_type(struct qpnp_qg *chip) return DEFAULT_BATT_TYPE; } -static int qg_get_battery_voltage(struct qpnp_qg *chip, int *vbat_uv) -{ - int rc = 0; - u64 last_vbat = 0; - - if (chip->battery_missing) { - *vbat_uv = 3700000; - return 0; - } - - rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_V_DATA0_REG, - (u8 *)&last_vbat, 2); - if (rc < 0) { - pr_err("Failed to read LAST_ADV_V reg, rc=%d\n", rc); - return rc; - } - - *vbat_uv = V_RAW_TO_UV(last_vbat); - - return rc; -} - #define DEBUG_BATT_SOC 67 #define BATT_MISSING_SOC 50 #define EMPTY_SOC 0 @@ -1882,9 +1858,11 @@ static int qg_charge_full_update(struct qpnp_qg *chip) recharge_soc = DEFAULT_RECHARGE_SOC; } recharge_soc = prop.intval; + chip->recharge_soc = recharge_soc; - qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d\n", - chip->msoc, health, chip->charge_full); + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d health=%d charge_full=%d charge_done=%d\n", + chip->msoc, health, chip->charge_full, + chip->charge_done); if (chip->charge_done && !chip->charge_full) { if (chip->msoc >= 99 && health == POWER_SUPPLY_HEALTH_GOOD) { chip->charge_full = true; @@ -1895,10 +1873,18 @@ static int qg_charge_full_update(struct qpnp_qg *chip) qg_dbg(chip, QG_DEBUG_STATUS, "Terminated charging @ msoc=%d\n", chip->msoc); } - } else if ((!chip->charge_done || chip->msoc < recharge_soc) + } else if ((!chip->charge_done || chip->msoc <= recharge_soc) && chip->charge_full) { - if (chip->wa_flags & QG_RECHARGE_SOC_WA) { + bool usb_present = is_usb_present(chip); + + /* + * force a recharge only if SOC <= recharge SOC and + * we have not started charging. + */ + if ((chip->wa_flags & QG_RECHARGE_SOC_WA) && + usb_present && chip->msoc <= recharge_soc && + chip->charge_status != POWER_SUPPLY_STATUS_CHARGING) { /* Force recharge */ prop.intval = 0; rc = power_supply_set_property(chip->batt_psy, @@ -1906,23 +1892,33 @@ static int qg_charge_full_update(struct qpnp_qg *chip) if (rc < 0) pr_err("Failed to force recharge rc=%d\n", rc); else - qg_dbg(chip, QG_DEBUG_STATUS, - "Forced recharge\n"); + qg_dbg(chip, QG_DEBUG_STATUS, "Forced recharge\n"); } + + if (chip->charge_done) + return 0; /* wait for recharge */ + /* - * If recharge or discharge has started and - * if linearize soc dtsi property defined - * scale msoc from 100% for better UX. + * If SOC has indeed dropped below recharge-SOC or + * the USB is removed, if linearize-soc is set scale + * msoc from 100% for better UX. */ - if (chip->dt.linearize_soc && chip->msoc < 99) { - chip->maint_soc = FULL_SOC; - qg_scale_soc(chip, false); - } - - qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n", + if (chip->msoc < recharge_soc || !usb_present) { + if (chip->dt.linearize_soc) { + get_rtc_time(&chip->last_maint_soc_update_time); + chip->maint_soc = FULL_SOC; + qg_scale_soc(chip, false); + } + chip->charge_full = false; + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full (1->0)\n", chip->msoc, recharge_soc); - chip->charge_full = false; + } else { + /* continue with charge_full state */ + qg_dbg(chip, QG_DEBUG_STATUS, "msoc=%d recharge_soc=%d charge_full=%d usb_present=%d\n", + chip->msoc, recharge_soc, + chip->charge_full, usb_present); + } } out: return 0; @@ -1950,7 +1946,7 @@ static int qg_parallel_status_update(struct qpnp_qg *chip) if (!chip->dt.qg_ext_sense) update_smb = true; - rc = process_rt_fifo_data(chip, false, update_smb); + rc = process_rt_fifo_data(chip, update_smb); if (rc < 0) pr_err("Failed to process RT FIFO data, rc=%d\n", rc); @@ -2634,7 +2630,7 @@ static int qg_determine_pon_soc(struct qpnp_qg *chip) return rc; } - chip->pon_soc = chip->catch_up_soc = chip->msoc = soc; + chip->last_adj_ssoc = chip->catch_up_soc = chip->msoc = soc; chip->kdata.param[QG_PON_OCV_UV].data = ocv_uv; chip->kdata.param[QG_PON_OCV_UV].valid = true; @@ -2889,10 +2885,6 @@ static int qg_post_init(struct qpnp_qg *chip) PROFILE_IRQ_DISABLE, true, 0); vote(chip->good_ocv_irq_disable_votable, PROFILE_IRQ_DISABLE, true, 0); - } else { - /* disable GOOD_OCV IRQ at init */ - vote(chip->good_ocv_irq_disable_votable, - QG_INIT_STATE_IRQ_DISABLE, true, 0); } /* restore ESR data */ @@ -3450,7 +3442,7 @@ static int process_resume(struct qpnp_qg *chip) { u8 status2 = 0, rt_status = 0; u32 ocv_uv = 0, ocv_raw = 0; - int rc, batt_temp = 0; + int rc; /* skip if profile is not loaded */ if (!chip->profile_loaded) @@ -3468,16 +3460,11 @@ static int process_resume(struct qpnp_qg *chip) pr_err("Failed to read good_ocv, rc=%d\n", rc); return rc; } - rc = qg_get_battery_temp(chip, &batt_temp); - if (rc < 0) { - pr_err("Failed to read BATT_TEMP, rc=%d\n", rc); - return rc; - } - chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; - chip->kdata.param[QG_GOOD_OCV_UV].valid = true; /* Clear suspend data as there has been a GOOD OCV */ memset(&chip->kdata, 0, sizeof(chip->kdata)); + chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; + chip->kdata.param[QG_GOOD_OCV_UV].valid = true; chip->suspend_data = false; qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n", @@ -3620,6 +3607,7 @@ static int qpnp_qg_probe(struct platform_device *pdev) chip->maint_soc = -EINVAL; chip->batt_soc = INT_MIN; chip->cc_soc = INT_MIN; + chip->sys_soc = INT_MIN; chip->full_soc = QG_SOC_FULL; chip->chg_iterm_ma = INT_MIN; chip->soh = -EINVAL; diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c index 53af3415ec6aa2f3b99c1d93d37c5d43bc031787..6adc19a2012a006f215cf61dee74dc6bcc993ee2 100644 --- a/drivers/power/supply/qcom/qpnp-qnovo.c +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -127,6 +127,7 @@ #define DC_READY_VOTER "DC_READY_VOTER" #define PT_RESTART_VOTER "PT_RESTART_VOTER" +#define REG_WRITE_VOTER "REG_WRITE_VOTER" struct qnovo_dt_props { bool external_rsense; @@ -145,6 +146,7 @@ struct qnovo { struct votable *not_ok_to_qnovo_votable; struct votable *chg_ready_votable; struct votable *awake_votable; + struct votable *auto_esr_votable; struct class qnovo_class; struct pmic_revid_data *pmic_rev_id; u32 wa_flags; @@ -340,15 +342,7 @@ static int qnovo_disable_cb(struct votable *votable, void *data, int disable, return -EINVAL; } - /* - * fg must be available for enable FG_AVAILABLE_VOTER - * won't enable it otherwise - */ - - if (is_fg_available(chip)) - power_supply_set_property(chip->bms_psy, - POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, - &pval); + vote(chip->auto_esr_votable, QNOVO_OVERALL_VOTER, disable, 0); vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, disable, 0); rc = qnovo_batt_psy_update(chip, disable); @@ -420,6 +414,27 @@ static int awake_cb(struct votable *votable, void *data, int awake, return 0; } +static int auto_esr_cb(struct votable *votable, void *data, int auto_esr, + const char *client) +{ + struct qnovo *chip = data; + union power_supply_propval pval = {0}; + + pval.intval = !auto_esr; + if (is_fg_available(chip)) + power_supply_set_property(chip->bms_psy, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, + &pval); + + return 0; +} + +static void pe_ctrl2_write_cb(struct qnovo *chip, u8 *val) +{ + if (get_effective_result(chip->disable_votable) == 0) + vote(chip->auto_esr_votable, REG_WRITE_VOTER, (*val == 0), 0); +} + static int qnovo_parse_dt(struct qnovo *chip) { struct device_node *node = chip->dev->of_node; @@ -497,6 +512,7 @@ struct param_info { int reg_to_unit_offset; int min_val; int max_val; + void (*callback)(struct qnovo *chip, u8 *val); char *units_str; }; @@ -523,6 +539,7 @@ static struct param_info params[] = { .name = "PE_CTRL2_REG", .start_addr = QNOVO_PE_CTRL2, .num_regs = 1, + .callback = pe_ctrl2_write_cb, .units_str = "", }, [PTRAIN_STS_REG] = { @@ -892,6 +909,10 @@ static ssize_t reg_store(struct class *c, struct class_attribute *attr, pr_err("Couldn't write %s rc = %d\n", params[i].name, rc); return -EINVAL; } + + if (params[i].callback) + params[i].callback(chip, buf); + return count; } @@ -1464,6 +1485,8 @@ static int qnovo_hw_init(struct qnovo *chip) vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, true, 0); vote(chip->pt_dis_votable, ESR_VOTER, false, 0); + vote(chip->auto_esr_votable, QNOVO_OVERALL_VOTER, true, 0); + val = 0; rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); if (rc < 0) { @@ -1656,6 +1679,13 @@ static int qnovo_probe(struct platform_device *pdev) goto destroy_chg_ready_votable; } + chip->auto_esr_votable = create_votable("AUTO_ESR", VOTE_SET_ANY, + auto_esr_cb, chip); + if (IS_ERR(chip->auto_esr_votable)) { + rc = PTR_ERR(chip->auto_esr_votable); + goto destroy_auto_esr_votable; + } + INIT_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work); INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work); @@ -1700,6 +1730,8 @@ static int qnovo_probe(struct platform_device *pdev) unreg_notifier: power_supply_unreg_notifier(&chip->nb); +destroy_auto_esr_votable: + destroy_votable(chip->auto_esr_votable); destroy_awake_votable: destroy_votable(chip->awake_votable); destroy_chg_ready_votable: diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 122c08696e5d6a1742ead1e66547b33946d1235a..71a4369be1eb87ecbd1a13d2225d2ae4b3fe713a 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -283,6 +283,8 @@ static int smb5_chg_config_init(struct smb5 *chip) case PMI632_SUBTYPE: chip->chg.smb_version = PMI632_SUBTYPE; chg->wa_flags |= WEAK_ADAPTER_WA; + if (pmic_rev_id->rev4 >= 2) + chg->wa_flags |= MOISTURE_PROTECTION_WA; chg->param = smb5_pmi632_params; chg->use_extcon = true; chg->name = "pmi632_charger"; @@ -499,6 +501,9 @@ static int smb5_parse_dt(struct smb5 *chip) of_property_read_u32(node, "qcom,connector-internal-pull-kohm", &chg->connector_pull_up); + chg->moisture_protection_enabled = of_property_read_bool(node, + "qcom,moisture-protection-enable"); + return 0; } @@ -617,6 +622,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, + POWER_SUPPLY_PROP_MOISTURE_DETECTED, }; static int smb5_usb_get_prop(struct power_supply *psy, @@ -755,6 +761,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, if (chg->hw_connector_mitigation) val->intval |= POWER_SUPPLY_QC_CTM_DISABLE; break; + case POWER_SUPPLY_PROP_MOISTURE_DETECTED: + val->intval = chg->moisture_present; + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -1248,6 +1257,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_RECHARGE_SOC, + POWER_SUPPLY_PROP_CHARGE_FULL, }; static int smb5_batt_get_prop(struct power_supply *psy, @@ -1296,14 +1306,16 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = chg->sw_jeita_enabled; break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - rc = smblib_get_prop_batt_voltage_now(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, val); break; case POWER_SUPPLY_PROP_VOLTAGE_MAX: val->intval = get_client_vote(chg->fv_votable, BATT_PROFILE_VOTER); break; case POWER_SUPPLY_PROP_CURRENT_NOW: - rc = smblib_get_prop_batt_current_now(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CURRENT_NOW, val); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: val->intval = get_client_vote(chg->fcc_votable, @@ -1313,7 +1325,7 @@ static int smb5_batt_get_prop(struct power_supply *psy, rc = smblib_get_prop_batt_iterm(chg, val); break; case POWER_SUPPLY_PROP_TEMP: - rc = smblib_get_prop_batt_temp(chg, val); + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_TEMP, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; @@ -1342,14 +1354,20 @@ static int smb5_batt_get_prop(struct power_supply *psy, val->intval = 0; break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: - rc = smblib_get_prop_batt_charge_counter(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_COUNTER, val); break; case POWER_SUPPLY_PROP_CYCLE_COUNT: - rc = smblib_get_prop_batt_cycle_count(chg, val); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CYCLE_COUNT, val); break; case POWER_SUPPLY_PROP_RECHARGE_SOC: val->intval = chg->auto_recharge_soc; break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_CHARGE_FULL, val); + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; @@ -1646,14 +1664,6 @@ static int smb5_configure_typec(struct smb_charger *chg) return rc; } - rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, - TYPEC_WATER_DETECTION_INT_EN_BIT); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure Type-C interrupts rc=%d\n", rc); - return rc; - } - rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, EN_TRY_SNK_BIT, EN_TRY_SNK_BIT); if (rc < 0) { @@ -1692,6 +1702,37 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) return rc; } + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + /* Enable moisture detection interrupt */ + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, + TYPEC_WATER_DETECTION_INT_EN_BIT, + TYPEC_WATER_DETECTION_INT_EN_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable moisture detection interrupt rc=%d\n", + rc); + return rc; + } + + /* Enable uUSB factory mode */ + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, + EN_MICRO_USB_FACTORY_MODE_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable uUSB factory mode c=%d\n", + rc); + return rc; + } + + /* Disable periodic monitoring of CC_ID pin */ + rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", + rc); + return rc; + } + } + return rc; } diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index be0832ee92282e851a2fd728b2d73605eef6f9aa..054d153ae05fd445cac909ba322c3cb88550a029 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "smb5-lib.h" #include "smb5-reg.h" #include "battery.h" @@ -586,6 +587,21 @@ int smblib_set_aicl_cont_threshold(struct smb_chg_param *param, /******************** * HELPER FUNCTIONS * ********************/ + +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, psp, val); + + return rc; +} + int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable) { int rc; @@ -688,10 +704,11 @@ static int smblib_notifier_call(struct notifier_block *nb, chg->bms_psy = psy; if (ev == PSY_EVENT_PROP_CHANGED) schedule_work(&chg->bms_update_work); - if (!chg->jeita_configured) - schedule_work(&chg->jeita_update_work); } + if (!chg->jeita_configured) + schedule_work(&chg->jeita_update_work); + if (!chg->pl.psy && !strcmp(psy->desc->name, "parallel")) { chg->pl.psy = psy; schedule_work(&chg->pl_update_work); @@ -814,7 +831,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg) int rc; union power_supply_propval val; - rc = power_supply_get_property(chg->bms_psy, + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_DEBUG_BATTERY, &val); if (rc < 0) { smblib_err(chg, "Couldn't get debug battery prop rc=%d\n", rc); @@ -1045,6 +1062,100 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua) return 0; } +/******************** + * Moisture Protection * + ********************/ +#define MICRO_USB_DETECTION_ON_TIME_20_MS 0x08 +#define MICRO_USB_DETECTION_PERIOD_X_100 0x03 +#define U_USB_STATUS_WATER_PRESENT 0x00 +static int smblib_set_moisture_protection(struct smb_charger *chg, + bool enable) +{ + int rc = 0; + + if (chg->moisture_present == enable) { + smblib_dbg(chg, PR_MISC, "No change in moisture protection status\n"); + return rc; + } + + if (enable) { + chg->moisture_present = true; + + /* Disable uUSB factory mode detection */ + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", + rc); + return rc; + } + + /* Disable moisture detection and uUSB state change interrupt */ + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, + TYPEC_WATER_DETECTION_INT_EN_BIT | + MICRO_USB_STATE_CHANGE_INT_EN_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable moisture detection interrupt rc=%d\n", + rc); + return rc; + } + + /* Set 1% duty cycle on ID detection */ + rc = smblib_masked_write(chg, + TYPEC_U_USB_WATER_PROTECTION_CFG_REG, + EN_MICRO_USB_WATER_PROTECTION_BIT | + MICRO_USB_DETECTION_ON_TIME_CFG_MASK | + MICRO_USB_DETECTION_PERIOD_CFG_MASK, + EN_MICRO_USB_WATER_PROTECTION_BIT | + MICRO_USB_DETECTION_ON_TIME_20_MS | + MICRO_USB_DETECTION_PERIOD_X_100); + if (rc < 0) { + smblib_err(chg, "Couldn't set 1 percent CC_ID duty cycle rc=%d\n", + rc); + return rc; + } + + vote(chg->usb_icl_votable, MOISTURE_VOTER, true, 0); + } else { + chg->moisture_present = false; + vote(chg->usb_icl_votable, MOISTURE_VOTER, false, 0); + + /* Enable moisture detection and uUSB state change interrupt */ + rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, + TYPEC_WATER_DETECTION_INT_EN_BIT | + MICRO_USB_STATE_CHANGE_INT_EN_BIT, + TYPEC_WATER_DETECTION_INT_EN_BIT | + MICRO_USB_STATE_CHANGE_INT_EN_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable moisture detection and uUSB state change interrupt rc=%d\n", + rc); + return rc; + } + + /* Disable periodic monitoring of CC_ID pin */ + rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable 1 percent CC_ID duty cycle rc=%d\n", + rc); + return rc; + } + + /* Enable uUSB factory mode detection */ + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, + EN_MICRO_USB_FACTORY_MODE_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't disable uUSB factory mode detection rc=%d\n", + rc); + return rc; + } + } + + smblib_dbg(chg, PR_MISC, "Moisture protection %s\n", + chg->moisture_present ? "enabled" : "disabled"); + return rc; +} + /********************* * VOTABLE CALLBACKS * *********************/ @@ -1271,9 +1382,8 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg, return 0; } - if (chg->bms_psy) - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CAPACITY, val); + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CAPACITY, val); + return rc; } @@ -1416,7 +1526,8 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - rc = smblib_get_prop_batt_voltage_now(chg, &pval); + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); if (!rc) { /* * If Vbatt is within 40mV above Vfloat, then don't @@ -1487,32 +1598,6 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_VOLTAGE_NOW, val); - return rc; -} - -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CURRENT_NOW, val); - return rc; -} - int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val) { @@ -1552,19 +1637,6 @@ int smblib_get_prop_batt_iterm(struct smb_charger *chg, return rc; } -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_TEMP, val); - return rc; -} - int smblib_get_prop_batt_charge_done(struct smb_charger *chg, union power_supply_propval *val) { @@ -1583,32 +1655,6 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg, return 0; } -int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CHARGE_COUNTER, val); - return rc; -} - -int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, - union power_supply_propval *val) -{ - int rc; - - if (!chg->bms_psy) - return -EINVAL; - - rc = power_supply_get_property(chg->bms_psy, - POWER_SUPPLY_PROP_CYCLE_COUNT, val); - return rc; -} - /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -3495,11 +3541,28 @@ irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + /* + * Adding pm_stay_awake as because pm_relax is called + * on exit path from the work routine. + */ + pm_stay_awake(chg->dev); + schedule_work(&chg->moisture_protection_work); + } + cancel_delayed_work_sync(&chg->uusb_otg_work); - vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); - smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); - schedule_delayed_work(&chg->uusb_otg_work, - msecs_to_jiffies(chg->otg_delay_ms)); + /* + * Skip OTG enablement if RID interrupt triggers with moisture + * protection still enabled. + */ + if (!chg->moisture_present) { + vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); + smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); + schedule_delayed_work(&chg->uusb_otg_work, + msecs_to_jiffies(chg->otg_delay_ms)); + } + return IRQ_HANDLED; } @@ -3867,6 +3930,96 @@ static void smblib_pl_enable_work(struct work_struct *work) vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); } +#define MOISTURE_PROTECTION_CHECK_DELAY_MS 300000 /* 5 mins */ +static void smblib_moisture_protection_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + moisture_protection_work); + int rc; + bool usb_plugged_in; + u8 stat; + + /* + * Disable 1% duty cycle on CC_ID pin and enable uUSB factory mode + * detection to track any change on RID, as interrupts are disable. + */ + rc = smblib_write(chg, TYPEC_U_USB_WATER_PROTECTION_CFG_REG, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't disable periodic monitoring of CC_ID rc=%d\n", + rc); + goto out; + } + + rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, + EN_MICRO_USB_FACTORY_MODE_BIT, + EN_MICRO_USB_FACTORY_MODE_BIT); + if (rc < 0) { + smblib_err(chg, "Couldn't enable uUSB factory mode detection rc=%d\n", + rc); + goto out; + } + + /* + * Add a delay of 100ms to allow change in rid to reflect on + * status registers. + */ + msleep(100); + + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); + goto out; + } + usb_plugged_in = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); + + /* Check uUSB status for moisture presence */ + rc = smblib_read(chg, TYPEC_U_USB_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_U_USB_STATUS_REG rc=%d\n", + rc); + goto out; + } + + /* + * Factory mode detection happens in case of USB plugged-in by using + * a different current source of 2uA which can hamper moisture + * detection. Since factory mode is not supported in kernel, factory + * mode detection can be considered as equivalent to presence of + * moisture. + */ + if (stat == U_USB_STATUS_WATER_PRESENT || stat == U_USB_FMB1_BIT || + stat == U_USB_FMB2_BIT || (usb_plugged_in && + stat == U_USB_FLOAT1_BIT)) { + smblib_set_moisture_protection(chg, true); + alarm_start_relative(&chg->moisture_protection_alarm, + ms_to_ktime(MOISTURE_PROTECTION_CHECK_DELAY_MS)); + } else { + smblib_set_moisture_protection(chg, false); + rc = alarm_cancel(&chg->moisture_protection_alarm); + if (rc < 0) + smblib_err(chg, "Couldn't cancel moisture protection alarm\n"); + } + +out: + pm_relax(chg->dev); +} + +static enum alarmtimer_restart moisture_protection_alarm_cb(struct alarm *alarm, + ktime_t now) +{ + struct smb_charger *chg = container_of(alarm, struct smb_charger, + moisture_protection_alarm); + + smblib_dbg(chg, PR_MISC, "moisture Protection Alarm Triggered %lld\n", + ktime_to_ms(now)); + + /* Atomic context, cannot use voter */ + pm_stay_awake(chg->dev); + schedule_work(&chg->moisture_protection_work); + + return ALARMTIMER_NORESTART; +} + #define JEITA_SOFT 0 #define JEITA_HARD 1 static int smblib_update_jeita(struct smb_charger *chg, u32 *thresholds, @@ -3919,13 +4072,21 @@ static void jeita_update_work(struct work_struct *work) goto out; } - rc = power_supply_get_property(chg->bms_psy, + /* if BMS is not ready, defer the work */ + if (!chg->bms_psy) + return; + + rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_RESISTANCE_ID, &val); if (rc < 0) { smblib_err(chg, "Failed to get batt-id rc=%d\n", rc); goto out; } + /* if BMS hasn't read out the batt_id yet, defer the work */ + if (val.intval <= 0) + return; + pnode = of_batterydata_get_best_profile(batt_node, val.intval / 1000, NULL); if (IS_ERR(pnode)) { @@ -4069,6 +4230,21 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); + + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + INIT_WORK(&chg->moisture_protection_work, + smblib_moisture_protection_work); + + if (alarmtimer_get_rtcdev()) { + alarm_init(&chg->moisture_protection_alarm, + ALARM_BOOTTIME, moisture_protection_alarm_cb); + } else { + smblib_err(chg, "Failed to initialize moisture protection alarm\n"); + return -ENODEV; + } + } + chg->fake_capacity = -EINVAL; chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; @@ -4130,6 +4306,11 @@ int smblib_deinit(struct smb_charger *chg) { switch (chg->mode) { case PARALLEL_MASTER: + if (chg->moisture_protection_enabled && + (chg->wa_flags & MOISTURE_PROTECTION_WA)) { + alarm_cancel(&chg->moisture_protection_alarm); + cancel_work_sync(&chg->moisture_protection_work); + } cancel_work_sync(&chg->bms_update_work); cancel_work_sync(&chg->jeita_update_work); cancel_work_sync(&chg->pl_update_work); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 5be985e09f88251998ddd323413ae6b05da6989e..c252ef008a3b7a8c69f6ade10338b4a9bebe33ff 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -18,6 +18,7 @@ #include #include #include +#include #include "storm-watch.h" enum print_reason { @@ -68,6 +69,7 @@ enum print_reason { #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define AICL_THRESHOLD_VOTER "AICL_THRESHOLD_VOTER" +#define MOISTURE_VOTER "MOISTURE_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 @@ -99,6 +101,7 @@ enum sink_src_mode { enum { BOOST_BACK_WA = BIT(0), WEAK_ADAPTER_WA = BIT(1), + MOISTURE_PROTECTION_WA = BIT(2), }; enum { @@ -339,6 +342,7 @@ struct smb_charger { struct work_struct bms_update_work; struct work_struct pl_update_work; struct work_struct jeita_update_work; + struct work_struct moisture_protection_work; struct delayed_work ps_change_timeout_work; struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; @@ -346,6 +350,9 @@ struct smb_charger { struct delayed_work uusb_otg_work; struct delayed_work bb_removal_work; + /* alarm */ + struct alarm moisture_protection_alarm; + /* pd */ int voltage_min_uv; int voltage_max_uv; @@ -394,6 +401,8 @@ struct smb_charger { int aicl_cont_threshold_mv; int default_aicl_cont_threshold_mv; bool aicl_max_reached; + bool moisture_present; + bool moisture_protection_enabled; /* workaround flag */ u32 wa_flags; @@ -491,18 +500,8 @@ int smblib_get_prop_system_temp_level_max(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_current_now(struct smb_charger *chg, - union power_supply_propval *val); int smblib_get_prop_batt_iterm(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_batt_temp(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, - union power_supply_propval *val); -int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, - union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, @@ -576,6 +575,9 @@ int smblib_get_prop_pr_swap_in_progress(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_get_prop_from_bms(struct smb_charger *chg, + enum power_supply_property psp, + union power_supply_propval *val); int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override); int smblib_configure_wdog(struct smb_charger *chg, bool enable); int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index e9c4a0f5491e55a34109f3c0e142db27c3c39671..57eb22af838db6373aa3b3d2fc6eb935a273496a 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -126,6 +126,7 @@ enum { #define USBIN_SUSPEND_STS_BIT BIT(6) #define USE_USBIN_BIT BIT(4) #define USE_DCIN_BIT BIT(3) +#define POWER_PATH_MASK GENMASK(2, 1) #define VALID_INPUT_POWER_SOURCE_STS_BIT BIT(0) #define DCDC_CMD_OTG_REG (DCDC_BASE + 0x40) @@ -294,6 +295,7 @@ enum { #define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) +#define TYPEC_WATER_DETECTION_STATUS_BIT BIT(7) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) #define CC_ORIENTATION_BIT BIT(1) @@ -306,6 +308,10 @@ enum { #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) #define U_USB_GROUND_NOVBUS_BIT BIT(6) #define U_USB_GROUND_BIT BIT(4) +#define U_USB_FMB1_BIT BIT(3) +#define U_USB_FLOAT1_BIT BIT(2) +#define U_USB_FMB2_BIT BIT(1) +#define U_USB_FLOAT2_BIT BIT(0) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) #define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 1) @@ -351,8 +357,14 @@ enum { #define REDUCE_TCCDEBOUNCE_TO_2MS_BIT BIT(2) #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) +#define EN_MICRO_USB_FACTORY_MODE_BIT BIT(1) #define EN_MICRO_USB_MODE_BIT BIT(0) +#define TYPEC_U_USB_WATER_PROTECTION_CFG_REG (TYPEC_BASE + 0x72) +#define EN_MICRO_USB_WATER_PROTECTION_BIT BIT(4) +#define MICRO_USB_DETECTION_ON_TIME_CFG_MASK GENMASK(3, 2) +#define MICRO_USB_DETECTION_PERIOD_CFG_MASK GENMASK(1, 0) + #define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73) #define MICRO_USB_MODE_ONLY_BIT BIT(0) /******************************** diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index 54433fc6d1a4e491e9e046b20558e093d7c5c4de..e4eaefc2a2ef2f618069983a9d3a7d2f3e7b2c1f 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -52,6 +52,10 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev) return pwm_lpss_remove(lpwm); } +static SIMPLE_DEV_PM_OPS(pwm_lpss_platform_pm_ops, + pwm_lpss_suspend, + pwm_lpss_resume); + static const struct acpi_device_id pwm_lpss_acpi_match[] = { { "80860F09", (unsigned long)&pwm_lpss_byt_info }, { "80862288", (unsigned long)&pwm_lpss_bsw_info }, @@ -64,6 +68,7 @@ static struct platform_driver pwm_lpss_driver_platform = { .driver = { .name = "pwm-lpss", .acpi_match_table = pwm_lpss_acpi_match, + .pm = &pwm_lpss_platform_pm_ops, }, .probe = pwm_lpss_probe_platform, .remove = pwm_lpss_remove_platform, diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 72c0bce5a75cc646dc0094d77774c48cbeb5ce6a..5208b3f80ad85cd4838e5529a9eb3064c520a496 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -31,10 +31,13 @@ /* Size of each PWM register space if multiple */ #define PWM_SIZE 0x400 +#define MAX_PWMS 4 + struct pwm_lpss_chip { struct pwm_chip chip; void __iomem *regs; const struct pwm_lpss_boardinfo *info; + u32 saved_ctrl[MAX_PWMS]; }; /* BayTrail */ @@ -168,6 +171,9 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, unsigned long c; int ret; + if (WARN_ON(info->npwm > MAX_PWMS)) + return ERR_PTR(-ENODEV); + lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL); if (!lpwm) return ERR_PTR(-ENOMEM); @@ -203,6 +209,30 @@ int pwm_lpss_remove(struct pwm_lpss_chip *lpwm) } EXPORT_SYMBOL_GPL(pwm_lpss_remove); +int pwm_lpss_suspend(struct device *dev) +{ + struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); + int i; + + for (i = 0; i < lpwm->info->npwm; i++) + lpwm->saved_ctrl[i] = readl(lpwm->regs + i * PWM_SIZE + PWM); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_lpss_suspend); + +int pwm_lpss_resume(struct device *dev) +{ + struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); + int i; + + for (i = 0; i < lpwm->info->npwm; i++) + writel(lpwm->saved_ctrl[i], lpwm->regs + i * PWM_SIZE + PWM); + + return 0; +} +EXPORT_SYMBOL_GPL(pwm_lpss_resume); + MODULE_DESCRIPTION("PWM driver for Intel LPSS"); MODULE_AUTHOR("Mika Westerberg "); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h index 04766e0d41aab2a4b503c56d35fff4ba4c02778e..27d5081ec218596bb0ab8c3ee4919ed20648efb6 100644 --- a/drivers/pwm/pwm-lpss.h +++ b/drivers/pwm/pwm-lpss.h @@ -31,5 +31,7 @@ extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info; struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r, const struct pwm_lpss_boardinfo *info); int pwm_lpss_remove(struct pwm_lpss_chip *lpwm); +int pwm_lpss_suspend(struct device *dev); +int pwm_lpss_resume(struct device *dev); #endif /* __PWM_LPSS_H */ diff --git a/drivers/regulator/qpnp-labibb-regulator.c b/drivers/regulator/qpnp-labibb-regulator.c index 88c5697c938646669d17e8b40252a60c7a3548e7..d72af209559335ad78105f2cfd40038dc955ff81 100644 --- a/drivers/regulator/qpnp-labibb-regulator.c +++ b/drivers/regulator/qpnp-labibb-regulator.c @@ -597,6 +597,7 @@ struct qpnp_labibb { struct device *dev; struct platform_device *pdev; struct regmap *regmap; + struct class labibb_class; struct pmic_revid_data *pmic_rev_id; u16 lab_base; u16 ibb_base; @@ -624,6 +625,8 @@ struct qpnp_labibb { bool notify_lab_vreg_ok_sts; bool detect_lab_sc; bool sc_detected; + /* Tracks the secure UI mode entry/exit */ + bool secure_mode; u32 swire_2nd_cmd_delay; u32 swire_ibb_ps_enable_delay; }; @@ -2463,6 +2466,9 @@ static int qpnp_lab_regulator_enable(struct regulator_dev *rdev) int rc; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->sc_detected) { pr_info("Short circuit detected: disabled LAB/IBB rails\n"); return 0; @@ -2500,6 +2506,9 @@ static int qpnp_lab_regulator_disable(struct regulator_dev *rdev) u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->lab_vreg.vreg_enabled && !labibb->swire_control) { if (!labibb->standalone) @@ -2693,7 +2702,7 @@ static int qpnp_lab_regulator_set_voltage(struct regulator_dev *rdev, u8 val; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); - if (labibb->swire_control) + if (labibb->swire_control || labibb->secure_mode) return 0; if (min_uV < labibb->lab_vreg.min_volt) { @@ -3072,6 +3081,8 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } if (is_lab_vreg_ok_irq_available(labibb)) { + irq_set_status_flags(labibb->lab_vreg.lab_vreg_ok_irq, + IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(labibb->dev, labibb->lab_vreg.lab_vreg_ok_irq, NULL, lab_vreg_ok_handler, @@ -3085,6 +3096,8 @@ static int register_qpnp_lab_regulator(struct qpnp_labibb *labibb, } if (labibb->lab_vreg.lab_sc_irq != -EINVAL) { + irq_set_status_flags(labibb->lab_vreg.lab_sc_irq, + IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(labibb->dev, labibb->lab_vreg.lab_sc_irq, NULL, labibb_sc_err_handler, @@ -3568,6 +3581,9 @@ static int qpnp_ibb_regulator_enable(struct regulator_dev *rdev) int rc = 0; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->sc_detected) { pr_info("Short circuit detected: disabled LAB/IBB rails\n"); return 0; @@ -3593,6 +3609,9 @@ static int qpnp_ibb_regulator_disable(struct regulator_dev *rdev) int rc; struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); + if (labibb->secure_mode) + return 0; + if (labibb->ibb_vreg.vreg_enabled && !labibb->swire_control) { if (!labibb->standalone) @@ -3626,7 +3645,7 @@ static int qpnp_ibb_regulator_set_voltage(struct regulator_dev *rdev, struct qpnp_labibb *labibb = rdev_get_drvdata(rdev); - if (labibb->swire_control) + if (labibb->swire_control || labibb->secure_mode) return 0; rc = labibb->ibb_ver_ops->set_voltage(labibb, min_uV, max_uV); @@ -3855,6 +3874,8 @@ static int register_qpnp_ibb_regulator(struct qpnp_labibb *labibb, } if (labibb->ibb_vreg.ibb_sc_irq != -EINVAL) { + irq_set_status_flags(labibb->ibb_vreg.ibb_sc_irq, + IRQ_DISABLE_UNLAZY); rc = devm_request_threaded_irq(labibb->dev, labibb->ibb_vreg.ibb_sc_irq, NULL, labibb_sc_err_handler, @@ -4016,6 +4037,49 @@ static int qpnp_labibb_check_ttw_supported(struct qpnp_labibb *labibb) return rc; } +static ssize_t qpnp_labibb_irq_control(struct class *c, + struct class_attribute *attr, + const char *buf, size_t count) +{ + struct qpnp_labibb *labibb = container_of(c, struct qpnp_labibb, + labibb_class); + int val, rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val != 0 && val != 1) + return count; + + /* Disable irqs */ + if (val == 1 && !labibb->secure_mode) { + if (labibb->lab_vreg.lab_vreg_ok_irq > 0) + disable_irq(labibb->lab_vreg.lab_vreg_ok_irq); + if (labibb->lab_vreg.lab_sc_irq > 0) + disable_irq(labibb->lab_vreg.lab_sc_irq); + if (labibb->ibb_vreg.ibb_sc_irq > 0) + disable_irq(labibb->ibb_vreg.ibb_sc_irq); + labibb->secure_mode = true; + } else if (val == 0 && labibb->secure_mode) { + if (labibb->lab_vreg.lab_vreg_ok_irq > 0) + enable_irq(labibb->lab_vreg.lab_vreg_ok_irq); + if (labibb->lab_vreg.lab_sc_irq > 0) + enable_irq(labibb->lab_vreg.lab_sc_irq); + if (labibb->ibb_vreg.ibb_sc_irq > 0) + enable_irq(labibb->ibb_vreg.ibb_sc_irq); + labibb->secure_mode = false; + } + + return count; +} + +static struct class_attribute labibb_attributes[] = { + [0] = __ATTR(secure_mode, 0664, NULL, + qpnp_labibb_irq_control), + __ATTR_NULL, +}; + static int qpnp_labibb_regulator_probe(struct platform_device *pdev) { struct qpnp_labibb *labibb; @@ -4208,6 +4272,17 @@ static int qpnp_labibb_regulator_probe(struct platform_device *pdev) CLOCK_MONOTONIC, HRTIMER_MODE_REL); labibb->sc_err_check_timer.function = labibb_check_sc_err_count; dev_set_drvdata(&pdev->dev, labibb); + + labibb->labibb_class.name = "lcd_bias"; + labibb->labibb_class.owner = THIS_MODULE; + labibb->labibb_class.class_attrs = labibb_attributes; + + rc = class_register(&labibb->labibb_class); + if (rc < 0) { + pr_err("Failed to register labibb class rc=%d\n", rc); + return rc; + } + pr_info("LAB/IBB registered successfully, lab_vreg enable=%d ibb_vreg enable=%d swire_control=%d\n", labibb->lab_vreg.vreg_enabled, labibb->ibb_vreg.vreg_enabled, diff --git a/drivers/rpmsg/qcom_smd.c b/drivers/rpmsg/qcom_smd.c index 1d4770c02e57e2c0b0eda4c5b6313c8f69dae4f2..fd3d9419c4687e4525b0440a4fef7cdd4cb9f551 100644 --- a/drivers/rpmsg/qcom_smd.c +++ b/drivers/rpmsg/qcom_smd.c @@ -1006,12 +1006,12 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed void *info; int ret; - channel = devm_kzalloc(&edge->dev, sizeof(*channel), GFP_KERNEL); + channel = kzalloc(sizeof(*channel), GFP_KERNEL); if (!channel) return ERR_PTR(-ENOMEM); channel->edge = edge; - channel->name = devm_kstrdup(&edge->dev, name, GFP_KERNEL); + channel->name = kstrdup(name, GFP_KERNEL); if (!channel->name) return ERR_PTR(-ENOMEM); @@ -1061,8 +1061,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed return channel; free_name_and_channel: - devm_kfree(&edge->dev, channel->name); - devm_kfree(&edge->dev, channel); + kfree(channel->name); + kfree(channel); return ERR_PTR(ret); } @@ -1279,13 +1279,13 @@ static int qcom_smd_parse_edge(struct device *dev, */ static void qcom_smd_edge_release(struct device *dev) { - struct qcom_smd_channel *channel; + struct qcom_smd_channel *channel, *tmp; struct qcom_smd_edge *edge = to_smd_edge(dev); - list_for_each_entry(channel, &edge->channels, list) { - SET_RX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED); - SET_RX_CHANNEL_INFO(channel, head, 0); - SET_RX_CHANNEL_INFO(channel, tail, 0); + list_for_each_entry_safe(channel, tmp, &edge->channels, list) { + list_del(&channel->list); + kfree(channel->name); + kfree(channel); } kfree(edge); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 4534a7ce77b823fae8e6bf1ebec0b09a907ef551..b6caad0fee24cd5fe28e8213ff400c0f121e5a82 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -625,6 +625,46 @@ void zfcp_dbf_scsi(char *tag, int level, struct scsi_cmnd *sc, spin_unlock_irqrestore(&dbf->scsi_lock, flags); } +/** + * zfcp_dbf_scsi_eh() - Trace event for special cases of scsi_eh callbacks. + * @tag: Identifier for event. + * @adapter: Pointer to zfcp adapter as context for this event. + * @scsi_id: SCSI ID/target to indicate scope of task management function (TMF). + * @ret: Return value of calling function. + * + * This SCSI trace variant does not depend on any of: + * scsi_cmnd, zfcp_fsf_req, scsi_device. + */ +void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, + unsigned int scsi_id, int ret) +{ + struct zfcp_dbf *dbf = adapter->dbf; + struct zfcp_dbf_scsi *rec = &dbf->scsi_buf; + unsigned long flags; + static int const level = 1; + + if (unlikely(!debug_level_enabled(adapter->dbf->scsi, level))) + return; + + spin_lock_irqsave(&dbf->scsi_lock, flags); + memset(rec, 0, sizeof(*rec)); + + memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN); + rec->id = ZFCP_DBF_SCSI_CMND; + rec->scsi_result = ret; /* re-use field, int is 4 bytes and fits */ + rec->scsi_retries = ~0; + rec->scsi_allowed = ~0; + rec->fcp_rsp_info = ~0; + rec->scsi_id = scsi_id; + rec->scsi_lun = (u32)ZFCP_DBF_INVALID_LUN; + rec->scsi_lun_64_hi = (u32)(ZFCP_DBF_INVALID_LUN >> 32); + rec->host_scribble = ~0; + memset(rec->scsi_opcode, 0xff, ZFCP_DBF_SCSI_OPCODE); + + debug_event(dbf->scsi, level, rec, sizeof(*rec)); + spin_unlock_irqrestore(&dbf->scsi_lock, flags); +} + static debug_info_t *zfcp_dbf_reg(const char *name, int size, int rec_size) { struct debug_info *d; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 3b23d675459829a2d3d2be60c3e1d7b24ecc341e..2abcd331b05d39aa6da95c0841b6171836dba433 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -34,11 +34,28 @@ enum zfcp_erp_steps { ZFCP_ERP_STEP_LUN_OPENING = 0x2000, }; +/** + * enum zfcp_erp_act_type - Type of ERP action object. + * @ZFCP_ERP_ACTION_REOPEN_LUN: LUN recovery. + * @ZFCP_ERP_ACTION_REOPEN_PORT: Port recovery. + * @ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: Forced port recovery. + * @ZFCP_ERP_ACTION_REOPEN_ADAPTER: Adapter recovery. + * @ZFCP_ERP_ACTION_NONE: Eyecatcher pseudo flag to bitwise or-combine with + * either of the first four enum values. + * Used to indicate that an ERP action could not be + * set up despite a detected need for some recovery. + * @ZFCP_ERP_ACTION_FAILED: Eyecatcher pseudo flag to bitwise or-combine with + * either of the first four enum values. + * Used to indicate that ERP not needed because + * the object has ZFCP_STATUS_COMMON_ERP_FAILED. + */ enum zfcp_erp_act_type { ZFCP_ERP_ACTION_REOPEN_LUN = 1, ZFCP_ERP_ACTION_REOPEN_PORT = 2, ZFCP_ERP_ACTION_REOPEN_PORT_FORCED = 3, ZFCP_ERP_ACTION_REOPEN_ADAPTER = 4, + ZFCP_ERP_ACTION_NONE = 0xc0, + ZFCP_ERP_ACTION_FAILED = 0xe0, }; enum zfcp_erp_act_state { @@ -125,6 +142,49 @@ static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) } } +static int zfcp_erp_handle_failed(int want, struct zfcp_adapter *adapter, + struct zfcp_port *port, + struct scsi_device *sdev) +{ + int need = want; + struct zfcp_scsi_dev *zsdev; + + switch (want) { + case ZFCP_ERP_ACTION_REOPEN_LUN: + zsdev = sdev_to_zfcp(sdev); + if (atomic_read(&zsdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + need = 0; + break; + case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: + if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) + need = 0; + break; + case ZFCP_ERP_ACTION_REOPEN_PORT: + if (atomic_read(&port->status) & + ZFCP_STATUS_COMMON_ERP_FAILED) { + need = 0; + /* ensure propagation of failed status to new devices */ + zfcp_erp_set_port_status( + port, ZFCP_STATUS_COMMON_ERP_FAILED); + } + break; + case ZFCP_ERP_ACTION_REOPEN_ADAPTER: + if (atomic_read(&adapter->status) & + ZFCP_STATUS_COMMON_ERP_FAILED) { + need = 0; + /* ensure propagation of failed status to new devices */ + zfcp_erp_set_adapter_status( + adapter, ZFCP_STATUS_COMMON_ERP_FAILED); + } + break; + default: + need = 0; + break; + } + + return need; +} + static int zfcp_erp_required_act(int want, struct zfcp_adapter *adapter, struct zfcp_port *port, struct scsi_device *sdev) @@ -248,16 +308,27 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, int retval = 1, need; struct zfcp_erp_action *act; - if (!adapter->erp_thread) - return -EIO; + need = zfcp_erp_handle_failed(want, adapter, port, sdev); + if (!need) { + need = ZFCP_ERP_ACTION_FAILED; /* marker for trace */ + goto out; + } + + if (!adapter->erp_thread) { + need = ZFCP_ERP_ACTION_NONE; /* marker for trace */ + retval = -EIO; + goto out; + } need = zfcp_erp_required_act(want, adapter, port, sdev); if (!need) goto out; act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); - if (!act) + if (!act) { + need |= ZFCP_ERP_ACTION_NONE; /* marker for trace */ goto out; + } atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); @@ -268,18 +339,32 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, return retval; } +void zfcp_erp_port_forced_no_port_dbf(char *id, struct zfcp_adapter *adapter, + u64 port_name, u32 port_id) +{ + unsigned long flags; + static /* don't waste stack */ struct zfcp_port tmpport; + + write_lock_irqsave(&adapter->erp_lock, flags); + /* Stand-in zfcp port with fields just good enough for + * zfcp_dbf_rec_trig() and zfcp_dbf_set_common(). + * Under lock because tmpport is static. + */ + atomic_set(&tmpport.status, -1); /* unknown */ + tmpport.wwpn = port_name; + tmpport.d_id = port_id; + zfcp_dbf_rec_trig(id, adapter, &tmpport, NULL, + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, + ZFCP_ERP_ACTION_NONE); + write_unlock_irqrestore(&adapter->erp_lock, flags); +} + static int _zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear_mask, char *id) { zfcp_erp_adapter_block(adapter, clear_mask); zfcp_scsi_schedule_rports_block(adapter); - /* ensure propagation of failed status to new devices */ - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - zfcp_erp_set_adapter_status(adapter, - ZFCP_STATUS_COMMON_ERP_FAILED); - return -EIO; - } return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, NULL, NULL, id, 0); } @@ -298,12 +383,8 @@ void zfcp_erp_adapter_reopen(struct zfcp_adapter *adapter, int clear, char *id) zfcp_scsi_schedule_rports_block(adapter); write_lock_irqsave(&adapter->erp_lock, flags); - if (atomic_read(&adapter->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - zfcp_erp_set_adapter_status(adapter, - ZFCP_STATUS_COMMON_ERP_FAILED); - else - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, - NULL, NULL, id, 0); + zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_ADAPTER, adapter, + NULL, NULL, id, 0); write_unlock_irqrestore(&adapter->erp_lock, flags); } @@ -344,9 +425,6 @@ static void _zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear, zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT_FORCED, port->adapter, port, NULL, id, 0); } @@ -372,12 +450,6 @@ static int _zfcp_erp_port_reopen(struct zfcp_port *port, int clear, char *id) zfcp_erp_port_block(port, clear); zfcp_scsi_schedule_rport_block(port); - if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_FAILED) { - /* ensure propagation of failed status to new devices */ - zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ERP_FAILED); - return -EIO; - } - return zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_PORT, port->adapter, port, NULL, id, 0); } @@ -417,9 +489,6 @@ static void _zfcp_erp_lun_reopen(struct scsi_device *sdev, int clear, char *id, zfcp_erp_lun_block(sdev, clear); - if (atomic_read(&zfcp_sdev->status) & ZFCP_STATUS_COMMON_ERP_FAILED) - return; - zfcp_erp_action_enqueue(ZFCP_ERP_ACTION_REOPEN_LUN, adapter, zfcp_sdev->port, sdev, id, act_status); } diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 7a7984a50683e0ecdbe0fa1feb10eb4d94eb9cb4..b326f05c7f89fe4b32a6a64bacc2447f8c0c40d1 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -52,10 +52,15 @@ extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_scsi(char *, int, struct scsi_cmnd *, struct zfcp_fsf_req *); +extern void zfcp_dbf_scsi_eh(char *tag, struct zfcp_adapter *adapter, + unsigned int scsi_id, int ret); /* zfcp_erp.c */ extern void zfcp_erp_set_adapter_status(struct zfcp_adapter *, u32); extern void zfcp_erp_clear_adapter_status(struct zfcp_adapter *, u32); +extern void zfcp_erp_port_forced_no_port_dbf(char *id, + struct zfcp_adapter *adapter, + u64 port_name, u32 port_id); extern void zfcp_erp_adapter_reopen(struct zfcp_adapter *, int, char *); extern void zfcp_erp_adapter_shutdown(struct zfcp_adapter *, int, char *); extern void zfcp_erp_set_port_status(struct zfcp_port *, u32); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index bb99db2948ab2392fb0fc1eda6ac4a28cd6a958c..3afb200b2829cc5a0662b3c750e945703ff791b8 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -180,6 +180,7 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) if (abrt_req) break; + zfcp_dbf_scsi_abort("abrt_wt", scpnt, NULL); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) { @@ -276,6 +277,7 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (fsf_req) break; + zfcp_dbf_scsi_devreset("wait", scpnt, tm_flags, NULL); zfcp_erp_wait(adapter); ret = fc_block_scsi_eh(scpnt); if (ret) { @@ -322,15 +324,16 @@ static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); struct zfcp_adapter *adapter = zfcp_sdev->port->adapter; - int ret; + int ret = SUCCESS, fc_ret; zfcp_erp_adapter_reopen(adapter, 0, "schrh_1"); zfcp_erp_wait(adapter); - ret = fc_block_scsi_eh(scpnt); - if (ret) - return ret; + fc_ret = fc_block_scsi_eh(scpnt); + if (fc_ret) + ret = fc_ret; - return SUCCESS; + zfcp_dbf_scsi_eh("schrh_r", adapter, ~0, ret); + return ret; } struct scsi_transport_template *zfcp_scsi_transport_template; @@ -600,6 +603,11 @@ static void zfcp_scsi_terminate_rport_io(struct fc_rport *rport) if (port) { zfcp_erp_port_forced_reopen(port, 0, "sctrpi1"); put_device(&port->dev); + } else { + zfcp_erp_port_forced_no_port_dbf( + "sctrpin", adapter, + rport->port_name /* zfcp_scsi_rport_register */, + rport->port_id /* zfcp_scsi_rport_register */); } } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4441a559f1391ed88373a15a284a1879375c4038..34bbcfcae67ccd90295ab3fbf6aad506102ca159 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -3319,7 +3319,8 @@ qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) return; if (fcport->fp_speed == PORT_SPEED_UNKNOWN || - fcport->fp_speed > ha->link_data_rate) + fcport->fp_speed > ha->link_data_rate || + !ha->flags.gpsc_supported) return; rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed, diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index e3cd3ece44121c7d8ee3806a40a42acf069f6958..c3d1891d2d3f32dccf62966fc59140bf6d362b7b 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -52,6 +52,8 @@ struct srp_internal { struct transport_container rport_attr_cont; }; +static int scsi_is_srp_rport(const struct device *dev); + #define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) #define dev_to_rport(d) container_of(d, struct srp_rport, dev) @@ -61,9 +63,24 @@ static inline struct Scsi_Host *rport_to_shost(struct srp_rport *r) return dev_to_shost(r->dev.parent); } +static int find_child_rport(struct device *dev, void *data) +{ + struct device **child = data; + + if (scsi_is_srp_rport(dev)) { + WARN_ON_ONCE(*child); + *child = dev; + } + return 0; +} + static inline struct srp_rport *shost_to_rport(struct Scsi_Host *shost) { - return transport_class_to_srp_rport(&shost->shost_gendev); + struct device *child = NULL; + + WARN_ON_ONCE(device_for_each_child(&shost->shost_gendev, &child, + find_child_rport) < 0); + return child ? dev_to_rport(child) : NULL; } /** @@ -637,7 +654,8 @@ static enum blk_eh_timer_return srp_timed_out(struct scsi_cmnd *scmd) struct srp_rport *rport = shost_to_rport(shost); pr_debug("timeout for sdev %s\n", dev_name(&sdev->sdev_gendev)); - return rport->fast_io_fail_tmo < 0 && rport->dev_loss_tmo < 0 && + return rport && rport->fast_io_fail_tmo < 0 && + rport->dev_loss_tmo < 0 && i->f->reset_timer_if_blocked && scsi_device_blocked(sdev) ? BLK_EH_RESET_TIMER : BLK_EH_NOT_HANDLED; } diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 15d5af00e65bc491b4948425799165399397d47a..0f657b8c6811db79d1aec591bf73809df2c84d22 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -51,6 +51,7 @@ static int sg_version_num = 30536; /* 2 digits for each component */ #include #include #include +#include /* for sg_check_file_access() */ #include "scsi.h" #include @@ -210,6 +211,33 @@ static void sg_device_destroy(struct kref *kref); sdev_prefix_printk(prefix, (sdp)->device, \ (sdp)->disk->disk_name, fmt, ##a) +/* + * The SCSI interfaces that use read() and write() as an asynchronous variant of + * ioctl(..., SG_IO, ...) are fundamentally unsafe, since there are lots of ways + * to trigger read() and write() calls from various contexts with elevated + * privileges. This can lead to kernel memory corruption (e.g. if these + * interfaces are called through splice()) and privilege escalation inside + * userspace (e.g. if a process with access to such a device passes a file + * descriptor to a SUID binary as stdin/stdout/stderr). + * + * This function provides protection for the legacy API by restricting the + * calling context. + */ +static int sg_check_file_access(struct file *filp, const char *caller) +{ + if (filp->f_cred != current_real_cred()) { + pr_err_once("%s: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + caller, task_tgid_vnr(current), current->comm); + return -EPERM; + } + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) { + pr_err_once("%s: process %d (%s) called from kernel context, this is not allowed.\n", + caller, task_tgid_vnr(current), current->comm); + return -EACCES; + } + return 0; +} + static int sg_allow_access(struct file *filp, unsigned char *cmd) { struct sg_fd *sfp = filp->private_data; @@ -394,6 +422,14 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) struct sg_header *old_hdr = NULL; int retval = 0; + /* + * This could cause a response to be stranded. Close the associated + * file descriptor to free up any resources being held. + */ + retval = sg_check_file_access(filp, __func__); + if (retval) + return retval; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, @@ -581,9 +617,11 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) struct sg_header old_hdr; sg_io_hdr_t *hp; unsigned char cmnd[SG_MAX_CDB_SIZE]; + int retval; - if (unlikely(segment_eq(get_fs(), KERNEL_DS))) - return -EINVAL; + retval = sg_check_file_access(filp, __func__); + if (retval) + return retval; if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 93c3af09b6d337d3e372df79c61bbb63e45ac200..0ae6979b5fc50a9a4f5fe508f8d4b42e4a676887 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -727,6 +727,11 @@ static int ufs_qcom_config_vreg(struct device *dev, reg = vreg->reg; if (regulator_count_voltages(reg) > 0) { + uA_load = on ? vreg->max_uA : 0; + ret = regulator_set_load(vreg->reg, uA_load); + if (ret) + goto out; + min_uV = on ? vreg->min_uV : 0; ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); if (ret) { @@ -734,11 +739,6 @@ static int ufs_qcom_config_vreg(struct device *dev, __func__, vreg->name, ret); goto out; } - - uA_load = on ? vreg->max_uA : 0; - ret = regulator_set_load(vreg->reg, uA_load); - if (ret) - goto out; } out: return ret; diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c6cfd18c6510776d1593aeea3110b8432d0a9625..6c97870dba3b9b96deb88e297f13f66356a276ad 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -8368,7 +8368,7 @@ static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer) switch (ioctl_data->idn) { case QUERY_ATTR_IDN_BOOT_LU_EN: index = 0; - if (att > QUERY_ATTR_IDN_BOOT_LU_EN_MAX) { + if (!att || att > QUERY_ATTR_IDN_BOOT_LU_EN_MAX) { dev_err(hba->dev, "%s: Illegal ufs query ioctl data, opcode 0x%x, idn 0x%x, att 0x%x\n", __func__, ioctl_data->opcode, @@ -8611,6 +8611,11 @@ static int ufshcd_config_vreg(struct device *dev, name = vreg->name; if (regulator_count_voltages(reg) > 0) { + uA_load = on ? vreg->max_uA : 0; + ret = ufshcd_config_vreg_load(dev, vreg, uA_load); + if (ret) + goto out; + min_uV = on ? vreg->min_uV : 0; ret = regulator_set_voltage(reg, min_uV, vreg->max_uV); if (ret) { @@ -8618,11 +8623,6 @@ static int ufshcd_config_vreg(struct device *dev, __func__, name, ret); goto out; } - - uA_load = on ? vreg->max_uA : 0; - ret = ufshcd_config_vreg_load(dev, vreg, uA_load); - if (ret) - goto out; } out: return ret; @@ -10239,7 +10239,15 @@ static int ufshcd_devfreq_scale(struct ufs_hba *hba, bool scale_up) * racing during clock frequency scaling sequence. */ if (ufshcd_is_auto_hibern8_supported(hba)) { + /* + * Scaling prepare acquires the rw_sem: lock + * h8 may sleep in case of errors. + * 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; @@ -10370,6 +10378,8 @@ static ssize_t ufshcd_clkscale_enable_store(struct device *dev, hba->clk_scaling.is_allowed = value; + flush_work(&hba->eh_work); + if (value) { ufshcd_resume_clkscaling(hba); } else { diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 3ecca591bb7c22b432afa10e0b0799cecc3427d0..52d9f65c711eb1aa5fab0f72606eb15be56ab370 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -52,6 +52,14 @@ config QCOM_SDM670_LLCC can start using the LLCC slices. Say yes here to enable llcc driver for SDM670. +config QCOM_QCS605_LLCC + tristate "Qualcomm Technologies, Inc. QCS605 LLCC driver" + depends on QCOM_LLCC + help + This provides Last level cache controller driver for QCS605. + This driver provides data required to configure LLCC, so that clients + can start using the LLCC slices. + Say yes here to enable llcc driver for QCS605. config QCOM_LLCC_AMON tristate "Qualcomm Technologies, Inc. LLCC Activity Monitor(AMON) driver" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 0b711214389d1b527da0f941c6bf5ffe218f1f8c..1da834679417e99154e6cc09adcf4ed6432c40b2 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_LLCC) += llcc-core.o llcc-slice.o obj-$(CONFIG_QCOM_SDM845_LLCC) += llcc-sdm845.o obj-$(CONFIG_QCOM_SDM670_LLCC) += llcc-sdm670.o +obj-$(CONFIG_QCOM_QCS605_LLCC) += llcc-qcs605.o obj-$(CONFIG_QCOM_LLCC_PERFMON) += llcc_perfmon.o obj-$(CONFIG_QCOM_LLCC_AMON) += llcc-amon.o obj-$(CONFIG_QPNP_PBS) += qpnp-pbs.o diff --git a/drivers/soc/qcom/bgcom_interface.c b/drivers/soc/qcom/bgcom_interface.c index 1cde8c654188610f234f2824815facb90fc783db..75c99287e85139c96e2f64d9c07a3d3770aa80d1 100644 --- a/drivers/soc/qcom/bgcom_interface.c +++ b/drivers/soc/qcom/bgcom_interface.c @@ -306,10 +306,23 @@ static int bgchar_write_cmd(struct bg_ui_data *fui_obj_msg, int type) int bg_soft_reset(void) { - /*pull down reset gpio */ - gpio_direction_output(bgreset_gpio, 0); + pr_debug("do BG reset using gpio %d\n", bgreset_gpio); + if (!gpio_is_valid(bgreset_gpio)) { + pr_err("gpio %d is not valid\n", bgreset_gpio); + return -ENXIO; + } + if (gpio_direction_output(bgreset_gpio, 1)) + pr_err("gpio %d direction not set\n", bgreset_gpio); + + /* Sleep for 50ms for hardware to detect signal as high */ + msleep(50); + + gpio_set_value(bgreset_gpio, 0); + + /* Sleep for 50ms for hardware to detect signal as high */ msleep(50); gpio_set_value(bgreset_gpio, 1); + return 0; } EXPORT_SYMBOL(bg_soft_reset); diff --git a/drivers/soc/qcom/bgcom_spi.c b/drivers/soc/qcom/bgcom_spi.c index d2dc05f39d99d634f8bd573db2fd6d9354b58e07..446669f30a97ae9eedffbecabf39ae9332c902d9 100644 --- a/drivers/soc/qcom/bgcom_spi.c +++ b/drivers/soc/qcom/bgcom_spi.c @@ -47,6 +47,7 @@ #define HED_EVENT_ID_LEN (0x02) #define HED_EVENT_SIZE_LEN (0x02) #define HED_EVENT_DATA_STRT_LEN (0x05) +#define CMA_BFFR_POOL_SIZE (128*1024) #define MAX_RETRY 500 @@ -116,6 +117,9 @@ static struct mutex bg_resume_mutex; static atomic_t bg_is_spi_active; static int bg_irq; +static uint8_t *fxd_mem_buffer; +static struct mutex cma_buffer_lock; + static struct spi_device *get_spi_device(void) { struct bg_spi_priv *bg_spi = container_of(bg_com_drv, @@ -529,6 +533,7 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, uint8_t *tx_buf; uint32_t size; int ret; + bool is_cma_used = false; uint8_t cmnd = 0; uint32_t ahb_addr = 0; struct spi_device *spi = get_spi_device(); @@ -552,11 +557,22 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, return -EBUSY; } + + mutex_lock(&cma_buffer_lock); size = num_words*BG_SPI_WORD_SIZE; txn_len = BG_SPI_AHB_CMD_LEN + size; - tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, &dma_hndl, GFP_KERNEL); - if (!tx_buf) + if (fxd_mem_buffer != NULL && txn_len <= CMA_BFFR_POOL_SIZE) { + memset(fxd_mem_buffer, 0, txn_len); + tx_buf = fxd_mem_buffer; + is_cma_used = true; + } else + tx_buf = dma_zalloc_coherent(&spi->dev, txn_len, + &dma_hndl, GFP_KERNEL); + + if (!tx_buf) { + mutex_unlock(&cma_buffer_lock); return -ENOMEM; + } cmnd |= BG_SPI_AHB_WRITE_CMD; ahb_addr |= ahb_start_addr; @@ -566,7 +582,9 @@ int bgcom_ahb_write(void *handle, uint32_t ahb_start_addr, memcpy(tx_buf+BG_SPI_AHB_CMD_LEN, write_buf, size); ret = bgcom_transfer(handle, tx_buf, NULL, txn_len); - dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + if (!is_cma_used) + dma_free_coherent(&spi->dev, txn_len, tx_buf, dma_hndl); + mutex_unlock(&cma_buffer_lock); return ret; } EXPORT_SYMBOL(bgcom_ahb_write); @@ -943,6 +961,10 @@ static void bg_spi_init(struct bg_spi_priv *bg_spi) bg_com_drv = &bg_spi->lhandle; mutex_init(&bg_resume_mutex); + + fxd_mem_buffer = kmalloc(CMA_BFFR_POOL_SIZE, GFP_KERNEL | GFP_ATOMIC); + + mutex_init(&cma_buffer_lock); } static int bg_spi_probe(struct spi_device *spi) @@ -1006,7 +1028,9 @@ static int bg_spi_remove(struct spi_device *spi) mutex_destroy(&bg_spi->xfer_mutex); devm_kfree(&spi->dev, bg_spi); spi_set_drvdata(spi, NULL); - + if (fxd_mem_buffer != NULL) + kfree(fxd_mem_buffer); + mutex_destroy(&cma_buffer_lock); return 0; } diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c index e6412905b0f94e18b738b7601be73750b10fab06..ac509961ecbb40d328283348478c897612171f7d 100644 --- a/drivers/soc/qcom/dcc_v2.c +++ b/drivers/soc/qcom/dcc_v2.c @@ -990,6 +990,14 @@ static ssize_t dcc_store_config(struct device *dev, apb_bus = 1; } + if (len == 0) + len = 1; + + if (base == 0) { + dev_err(drvdata->dev, "DCC: Invalid Address\n"); + return -EINVAL; + } + ret = dcc_config_add(drvdata, base, len, apb_bus); if (ret) return ret; diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index b8e9268cd55e2b592683009259afd68d73f545be..b9572bdeede31432e2f4f5e23b7fcb28891e0c90 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -284,6 +284,8 @@ enum icnss_driver_state { ICNSS_HOST_TRIGGERED_PDR, ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, + ICNSS_REJUVENATE, + ICNSS_MODE_ON, }; struct ce_irq_list { @@ -1172,6 +1174,14 @@ bool icnss_is_fw_down(void) } EXPORT_SYMBOL(icnss_is_fw_down); +bool icnss_is_rejuvenate(void) +{ + if (!penv) + return false; + else + return test_bit(ICNSS_REJUVENATE, &penv->state); +} +EXPORT_SYMBOL(icnss_is_rejuvenate); int icnss_power_off(struct device *dev) { @@ -1601,6 +1611,16 @@ static int wlfw_wlan_mode_send_sync_msg(enum wlfw_driver_mode_enum_v01 mode) } penv->stats.mode_resp++; + if (mode == QMI_WLFW_OFF_V01) { + icnss_pr_dbg("Clear mode on 0x%lx, mode: %d\n", + penv->state, mode); + clear_bit(ICNSS_MODE_ON, &penv->state); + } else { + icnss_pr_dbg("Set mode on 0x%lx, mode: %d\n", + penv->state, mode); + set_bit(ICNSS_MODE_ON, &penv->state); + } + return 0; out: @@ -2093,6 +2113,7 @@ static void icnss_qmi_wlfw_clnt_ind(struct qmi_handle *handle, event_data->crashed = true; event_data->fw_rejuvenate = true; fw_down_data.crashed = true; + set_bit(ICNSS_REJUVENATE, &penv->state); icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_DOWN, &fw_down_data); icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, @@ -2283,6 +2304,7 @@ static int icnss_pd_restart_complete(struct icnss_priv *priv) icnss_call_driver_shutdown(priv); + clear_bit(ICNSS_REJUVENATE, &penv->state); clear_bit(ICNSS_PD_RESTART, &priv->state); priv->early_crash_ind = false; @@ -2333,6 +2355,7 @@ static int icnss_driver_event_fw_ready_ind(void *data) return -ENODEV; set_bit(ICNSS_FW_READY, &penv->state); + clear_bit(ICNSS_MODE_ON, &penv->state); icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state); @@ -3287,6 +3310,12 @@ int icnss_wlan_enable(struct device *dev, struct icnss_wlan_enable_cfg *config, return -EINVAL; } + if (test_bit(ICNSS_MODE_ON, &penv->state)) { + icnss_pr_err("Already Mode on, ignoring wlan_enable state: 0x%lx\n", + penv->state); + return -EINVAL; + } + icnss_pr_dbg("Mode: %d, config: %p, host_version: %s\n", mode, config, host_version); @@ -3525,6 +3554,7 @@ static int icnss_smmu_init(struct icnss_priv *priv) int atomic_ctx = 1; int s1_bypass = 1; int fast = 1; + int stall_disable = 1; int ret = 0; icnss_pr_dbg("Initializing SMMU\n"); @@ -3568,6 +3598,16 @@ static int icnss_smmu_init(struct icnss_priv *priv) goto set_attr_fail; } icnss_pr_dbg("SMMU FAST map set\n"); + + ret = iommu_domain_set_attr(mapping->domain, + DOMAIN_ATTR_CB_STALL_DISABLE, + &stall_disable); + if (ret < 0) { + icnss_pr_err("Set stall disable map attribute failed, err = %d\n", + ret); + goto set_attr_fail; + } + icnss_pr_dbg("SMMU STALL DISABLE map set\n"); } ret = arm_iommu_attach_device(&priv->pdev->dev, mapping); @@ -3989,8 +4029,14 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_FW_DOWN: seq_puts(s, "FW DOWN"); continue; + case ICNSS_REJUVENATE: + seq_puts(s, "FW REJUVENATE"); + continue; case ICNSS_DRIVER_UNLOADING: seq_puts(s, "DRIVER UNLOADING"); + continue; + case ICNSS_MODE_ON: + seq_puts(s, "MODE ON DONE"); } seq_printf(s, "UNKNOWN-%d", i); diff --git a/drivers/soc/qcom/llcc-qcs605.c b/drivers/soc/qcom/llcc-qcs605.c new file mode 100644 index 0000000000000000000000000000000000000000..d3d339007c517f8d63531ffca9a3d4ab8257ebc4 --- /dev/null +++ b/drivers/soc/qcom/llcc-qcs605.c @@ -0,0 +1,106 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +/* + * SCT entry contains of the following parameters + * name: Name of the client's use case for which the llcc slice is used + * uid: Unique id for the client's use case + * slice_id: llcc slice id for each client + * max_cap: The maximum capacity of the cache slice provided in KB + * priority: Priority of the client used to select victim line for replacement + * fixed_size: Determine of the slice has a fixed capacity + * bonus_ways: Bonus ways to be used by any slice, bonus way is used only if + * it't not a reserved way. + * res_ways: Reserved ways for the cache slice, the reserved ways cannot be used + * by any other client than the one its assigned to. + * cache_mode: Each slice operates as a cache, this controls the mode of the + * slice normal or TCM + * probe_target_ways: Determines what ways to probe for access hit. When + * configured to 1 only bonus and reseved ways are probed. + * when configured to 0 all ways in llcc are probed. + * dis_cap_alloc: Disable capacity based allocation for a client + * retain_on_pc: If this bit is set and client has maitained active vote + * then the ways assigned to this client are not flushed on power + * collapse. + * activate_on_init: Activate the slice immidiately after the SCT is programmed + */ +#define SCT_ENTRY(n, uid, sid, mc, p, fs, bway, rway, cmod, ptw, dca, rp, a) \ + { \ + .name = n, \ + .usecase_id = uid, \ + .slice_id = sid, \ + .max_cap = mc, \ + .priority = p, \ + .fixed_size = fs, \ + .bonus_ways = bway, \ + .res_ways = rway, \ + .cache_mode = cmod, \ + .probe_target_ways = ptw, \ + .dis_cap_alloc = dca, \ + .retain_on_pc = rp, \ + .activate_on_init = a, \ + } + +static struct llcc_slice_config qcs605_data[] = { + SCT_ENTRY("cpuss", 1, 1, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 1), + SCT_ENTRY("vidsc0", 2, 2, 256, 2, 1, 0x3, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("vidsc1", 3, 3, 256, 2, 1, 0x3, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("voice", 5, 5, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("audio", 6, 6, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("modem", 8, 8, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("compute", 10, 10, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("gpu", 12, 12, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 1, 0), + SCT_ENTRY("mmuhwt", 13, 13, 512, 1, 0, 0xF, 0x0, 0, 0, 1, 0, 1), + SCT_ENTRY("audiohw", 22, 22, 512, 1, 1, 0xF, 0x0, 0, 0, 1, 1, 0), +}; + +static int qcs605_qcom_llcc_probe(struct platform_device *pdev) +{ + return qcom_llcc_probe(pdev, qcs605_data, + ARRAY_SIZE(qcs605_data)); +} + +static const struct of_device_id qcs605_qcom_llcc_of_match[] = { + { .compatible = "qcom,qcs605-llcc", }, + { }, +}; + +static struct platform_driver qcs605_qcom_llcc_driver = { + .driver = { + .name = "qcs605-llcc", + .owner = THIS_MODULE, + .of_match_table = qcs605_qcom_llcc_of_match, + }, + .probe = qcs605_qcom_llcc_probe, + .remove = qcom_llcc_remove, +}; + +static int __init qcs605_init_qcom_llcc_init(void) +{ + return platform_driver_register(&qcs605_qcom_llcc_driver); +} +module_init(qcs605_init_qcom_llcc_init); + +static void __exit qcs605_exit_qcom_llcc_exit(void) +{ + platform_driver_unregister(&qcs605_qcom_llcc_driver); +} +module_exit(qcs605_exit_qcom_llcc_exit); + +MODULE_DESCRIPTION("QTI qcs605 LLCC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/msm_glink_pkt.c b/drivers/soc/qcom/msm_glink_pkt.c index a2928791444cd7185974cf33b4f566759527629c..4559f11b7d52c8fef18b40743cf09566d71d4fd3 100644 --- a/drivers/soc/qcom/msm_glink_pkt.c +++ b/drivers/soc/qcom/msm_glink_pkt.c @@ -398,7 +398,10 @@ void glink_pkt_notify_tx_done(void *handle, const void *priv, GLINK_PKT_INFO("%s(): priv[%p] pkt_priv[%p] ptr[%p]\n", __func__, priv, pkt_priv, ptr); /* Free Tx buffer allocated in glink_pkt_write */ - kvfree(ptr); + if (is_vmalloc_addr(ptr)) + vfree_atomic(ptr); + else + kfree(ptr); } /** @@ -787,14 +790,20 @@ ssize_t glink_pkt_write(struct file *file, GLINK_PKT_ERR( "%s copy_from_user failed ret[%d] on dev id:%d size %zu\n", __func__, ret, devp->i, count); - kvfree(data); + if (is_vmalloc_addr(data)) + vfree_atomic(data); + else + kfree(data); return -EFAULT; } ret = glink_tx(devp->handle, data, data, count, GLINK_TX_REQ_INTENT); if (ret) { GLINK_PKT_ERR("%s glink_tx failed ret[%d]\n", __func__, ret); - kvfree(data); + if (is_vmalloc_addr(data)) + vfree_atomic(data); + else + kfree(data); return ret; } diff --git a/drivers/soc/qcom/rpm-smd.c b/drivers/soc/qcom/rpm-smd.c index 675551af1b79be23d1a3b53e7f5014b8cbcbadcd..7a4ab97aca6b3fb46571ba2c1b0f6153c6b46a39 100644 --- a/drivers/soc/qcom/rpm-smd.c +++ b/drivers/soc/qcom/rpm-smd.c @@ -751,6 +751,33 @@ static int msm_rpm_read_sleep_ack(void) if (glink_enabled) ret = msm_rpm_glink_rx_poll(glink_data->glink_handle); else { + int timeout = 10; + + while (timeout) { + if (smd_is_pkt_avail(msm_rpm_data.ch_info)) + break; + /* + * Sleep for 50us at a time before checking + * for packet availability. The 50us is based + * on the the max time rpm could take to process + * and send an ack for sleep set request. + */ + udelay(50); + timeout--; + } + + /* + * On timeout return an error and exit the spinlock + * control on this cpu. This will allow any other + * core that has wokenup and trying to acquire the + * spinlock from being locked out. + */ + + if (!timeout) { + pr_err("Timed out waiting for RPM ACK\n"); + return -EAGAIN; + } + ret = msm_rpm_read_smd_data(buf); if (!ret) ret = smd_is_pkt_avail(msm_rpm_data.ch_info); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 60007070a9a2a19baad61c385082fcb5eaf68a7b..9995a842f8447f5b48f94cb588eeeeccda1d6f2f 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -279,8 +279,11 @@ static struct ion_buffer *ion_buffer_create(struct ion_heap *heap, void ion_buffer_destroy(struct ion_buffer *buffer) { - if (WARN_ON(buffer->kmap_cnt > 0)) + if (buffer->kmap_cnt > 0) { + pr_warn_once("%s: buffer still mapped in the kernel\n", + __func__); buffer->heap->ops->unmap_kernel(buffer->heap, buffer); + } buffer->heap->ops->unmap_dma(buffer->heap, buffer); atomic_long_sub(buffer->size, &buffer->heap->total_allocated); @@ -865,7 +868,7 @@ static int ion_debug_client_show(struct seq_file *s, void *unused) struct ion_handle *handle = rb_entry(n, struct ion_handle, node); - seq_printf(s, "%16.16s: %16zx : %16d : %12p", + seq_printf(s, "%16.16s: %16zx : %16d : %12pK", handle->buffer->heap->name, handle->buffer->size, atomic_read(&handle->ref.refcount), diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index 802f51e464050c36db7ae672e116273a5083f5ff..1719605683569c32177cb7e6c335e2546590b919 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -642,7 +642,7 @@ static int daqp_ao_insn_write(struct comedi_device *dev, /* Make sure D/A update mode is direct update */ outb(0, dev->iobase + DAQP_AUX_REG); - for (i = 0; i > insn->n; i++) { + for (i = 0; i < insn->n; i++) { unsigned int val = data[i]; int ret; diff --git a/drivers/thermal/qpnp-temp-alarm.c b/drivers/thermal/qpnp-temp-alarm.c index 7398b7b5d3912d280cecb9e1fc12d9da40626ffd..e8a89078d3954eab37fbce6f02860982272dd285 100644 --- a/drivers/thermal/qpnp-temp-alarm.c +++ b/drivers/thermal/qpnp-temp-alarm.c @@ -586,6 +586,20 @@ static int qpnp_tm_remove(struct platform_device *pdev) return 0; } +static void qpnp_tm_shutdown(struct platform_device *pdev) +{ + struct qpnp_tm_chip *chip = dev_get_drvdata(&pdev->dev); + int rc; + u8 reg; + + /* configure TEMP_ALARM to follow HW_EN */ + reg = ALARM_CTRL_FOLLOW_HW_ENABLE; + rc = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, ®, 1); + if (rc) + pr_err("Failed to cfg. TEMP_ALARM to follow HW_EN rc=%d\n", rc); +} + + static const struct of_device_id qpnp_tm_match_table[] = { { .compatible = QPNP_TM_DRIVER_NAME, }, {} @@ -604,6 +618,7 @@ static struct platform_driver qpnp_tm_driver = { }, .probe = qpnp_tm_probe, .remove = qpnp_tm_remove, + .shutdown = qpnp_tm_shutdown, .id_table = qpnp_tm_id, }; diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 1c70541a146724fcfcea8bda926d9679e7c64d10..0475f9685a41d68d08a02a99e606bd4d3c4c5df9 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -126,6 +126,8 @@ struct n_tty_data { struct mutex output_lock; }; +#define MASK(x) ((x) & (N_TTY_BUF_SIZE - 1)) + static inline size_t read_cnt(struct n_tty_data *ldata) { return ldata->read_head - ldata->read_tail; @@ -143,6 +145,7 @@ static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i) static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i) { + smp_rmb(); /* Matches smp_wmb() in add_echo_byte(). */ return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; } @@ -318,9 +321,7 @@ static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) static void reset_buffer_flags(struct n_tty_data *ldata) { ldata->read_head = ldata->canon_head = ldata->read_tail = 0; - ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; ldata->commit_head = 0; - ldata->echo_mark = 0; ldata->line_start = 0; ldata->erasing = 0; @@ -619,12 +620,19 @@ static size_t __process_echoes(struct tty_struct *tty) old_space = space = tty_write_room(tty); tail = ldata->echo_tail; - while (ldata->echo_commit != tail) { + while (MASK(ldata->echo_commit) != MASK(tail)) { c = echo_buf(ldata, tail); if (c == ECHO_OP_START) { unsigned char op; int no_space_left = 0; + /* + * Since add_echo_byte() is called without holding + * output_lock, we might see only portion of multi-byte + * operation. + */ + if (MASK(ldata->echo_commit) == MASK(tail + 1)) + goto not_yet_stored; /* * If the buffer byte is the start of a multi-byte * operation, get the next byte, which is either the @@ -636,6 +644,8 @@ static size_t __process_echoes(struct tty_struct *tty) unsigned int num_chars, num_bs; case ECHO_OP_ERASE_TAB: + if (MASK(ldata->echo_commit) == MASK(tail + 2)) + goto not_yet_stored; num_chars = echo_buf(ldata, tail + 2); /* @@ -730,7 +740,8 @@ static size_t __process_echoes(struct tty_struct *tty) /* If the echo buffer is nearly full (so that the possibility exists * of echo overrun before the next commit), then discard enough * data at the tail to prevent a subsequent overrun */ - while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { + while (ldata->echo_commit > tail && + ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { if (echo_buf(ldata, tail) == ECHO_OP_START) { if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB) tail += 3; @@ -740,6 +751,7 @@ static size_t __process_echoes(struct tty_struct *tty) tail++; } + not_yet_stored: ldata->echo_tail = tail; return old_space - space; } @@ -750,6 +762,7 @@ static void commit_echoes(struct tty_struct *tty) size_t nr, old, echoed; size_t head; + mutex_lock(&ldata->output_lock); head = ldata->echo_head; ldata->echo_mark = head; old = ldata->echo_commit - ldata->echo_tail; @@ -758,10 +771,12 @@ static void commit_echoes(struct tty_struct *tty) * is over the threshold (and try again each time another * block is accumulated) */ nr = head - ldata->echo_tail; - if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK)) + if (nr < ECHO_COMMIT_WATERMARK || + (nr % ECHO_BLOCK > old % ECHO_BLOCK)) { + mutex_unlock(&ldata->output_lock); return; + } - mutex_lock(&ldata->output_lock); ldata->echo_commit = head; echoed = __process_echoes(tty); mutex_unlock(&ldata->output_lock); @@ -812,7 +827,9 @@ static void flush_echoes(struct tty_struct *tty) static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata) { - *echo_buf_addr(ldata, ldata->echo_head++) = c; + *echo_buf_addr(ldata, ldata->echo_head) = c; + smp_wmb(); /* Matches smp_rmb() in echo_buf(). */ + ldata->echo_head++; } /** @@ -980,14 +997,15 @@ static void eraser(unsigned char c, struct tty_struct *tty) } seen_alnums = 0; - while (ldata->read_head != ldata->canon_head) { + while (MASK(ldata->read_head) != MASK(ldata->canon_head)) { head = ldata->read_head; /* erase a single possibly multibyte character */ do { head--; c = read_buf(ldata, head); - } while (is_continuation(c, tty) && head != ldata->canon_head); + } while (is_continuation(c, tty) && + MASK(head) != MASK(ldata->canon_head)); /* do not partially erase */ if (is_continuation(c, tty)) @@ -1029,7 +1047,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) * This info is used to go back the correct * number of columns. */ - while (tail != ldata->canon_head) { + while (MASK(tail) != MASK(ldata->canon_head)) { tail--; c = read_buf(ldata, tail); if (c == '\t') { @@ -1304,7 +1322,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) finish_erasing(ldata); echo_char(c, tty); echo_char_raw('\n', ldata); - while (tail != ldata->read_head) { + while (MASK(tail) != MASK(ldata->read_head)) { echo_char(read_buf(ldata, tail), tty); tail++; } @@ -1880,30 +1898,21 @@ static int n_tty_open(struct tty_struct *tty) struct n_tty_data *ldata; /* Currently a malloc failure here can panic */ - ldata = vmalloc(sizeof(*ldata)); + ldata = vzalloc(sizeof(*ldata)); if (!ldata) - goto err; + return -ENOMEM; ldata->overrun_time = jiffies; mutex_init(&ldata->atomic_read_lock); mutex_init(&ldata->output_lock); tty->disc_data = ldata; - reset_buffer_flags(tty->disc_data); - ldata->column = 0; - ldata->canon_column = 0; - ldata->num_overrun = 0; - ldata->no_room = 0; - ldata->lnext = 0; tty->closing = 0; /* indicate buffer work may resume */ clear_bit(TTY_LDISC_HALTED, &tty->flags); n_tty_set_termios(tty, NULL); tty_unthrottle(tty); - return 0; -err: - return -ENOMEM; } static inline int input_available_p(struct tty_struct *tty, int poll) @@ -2413,7 +2422,7 @@ static unsigned long inq_canon(struct n_tty_data *ldata) tail = ldata->read_tail; nr = head - tail; /* Skip EOF-chars.. */ - while (head != tail) { + while (MASK(head) != MASK(tail)) { if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) && read_buf(ldata, tail) == __DISABLED_CHAR) nr--; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index e8b34f16ba2c95fc7420a20a1eca181ca62c4901..a3adf21f9dcec4e310981f5afb0c35e08f57cd6e 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1078,13 +1078,14 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE; static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,omap4-uart", .data = &omap4_habit, }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am3352_habit, }, { .compatible = "ti,dra742-uart", .data = &dra742_habit, }, @@ -1326,6 +1327,19 @@ static int omap8250_soft_reset(struct device *dev) int sysc; int syss; + /* + * At least on omap4, unused uarts may not idle after reset without + * a basic scr dma configuration even with no dma in use. The + * module clkctrl status bits will be 1 instead of 3 blocking idle + * for the whole clockdomain. The softreset below will clear scr, + * and we restore it on resume so this is safe to do on all SoCs + * needing omap8250_soft_reset() quirk. Do it in two writes as + * recommended in the comment for omap8250_update_scr(). + */ + serial_out(up, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1); + serial_out(up, UART_OMAP_SCR, + OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL); + sysc = serial_in(up, UART_OMAP_SYSC); /* softreset the UART */ diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index b42d7f1c9089bd6b3a1c6d96d56d823b78694d64..41b0dd67fcce2ad24f5e72107e111bbacd5ef0dc 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1726,10 +1726,26 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) */ static void pl011_enable_interrupts(struct uart_amba_port *uap) { + unsigned int i; + spin_lock_irq(&uap->port.lock); /* Clear out any spuriously appearing RX interrupts */ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); + + /* + * RXIS is asserted only when the RX FIFO transitions from below + * to above the trigger threshold. If the RX FIFO is already + * full to the threshold this can't happen and RXIS will now be + * stuck off. Drain the RX FIFO explicitly to fix this: + */ + for (i = 0; i < uap->fifosize * 2; ++i) { + if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE) + break; + + pl011_read(uap, REG_DR); + } + uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; @@ -2320,12 +2336,67 @@ static int __init pl011_console_setup(struct console *co, char *options) return uart_set_options(&uap->port, co, baud, parity, bits, flow); } +/** + * pl011_console_match - non-standard console matching + * @co: registering console + * @name: name from console command line + * @idx: index from console command line + * @options: ptr to option string from console command line + * + * Only attempts to match console command lines of the form: + * console=pl011,mmio|mmio32,[,] + * console=pl011,0x[,] + * This form is used to register an initial earlycon boot console and + * replace it with the amba_console at pl011 driver init. + * + * Performs console setup for a match (as required by interface) + * If no are specified, then assume the h/w is already setup. + * + * Returns 0 if console matches; otherwise non-zero to use default matching + */ +static int __init pl011_console_match(struct console *co, char *name, int idx, + char *options) +{ + unsigned char iotype; + resource_size_t addr; + int i; + + if (strcmp(name, "pl011") != 0) + return -ENODEV; + + if (uart_parse_earlycon(options, &iotype, &addr, &options)) + return -ENODEV; + + if (iotype != UPIO_MEM && iotype != UPIO_MEM32) + return -ENODEV; + + /* try to match the port specified on the command line */ + for (i = 0; i < ARRAY_SIZE(amba_ports); i++) { + struct uart_port *port; + + if (!amba_ports[i]) + continue; + + port = &amba_ports[i]->port; + + if (port->mapbase != addr) + continue; + + co->index = i; + port->cons = co; + return pl011_console_setup(co, options); + } + + return -ENODEV; +} + static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAMA", .write = pl011_console_write, .device = uart_console_device, .setup = pl011_console_setup, + .match = pl011_console_match, .flags = CON_PRINTBUFFER, .index = -1, .data = &amba_reg, diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index addb287cacea9910708f9abf76464c53f85f0d75..5a341b1c65c30050d4e4d7a86fd7be2e1572ff9a 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1803,7 +1803,6 @@ static int atmel_startup(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; int retval; /* @@ -1818,8 +1817,8 @@ static int atmel_startup(struct uart_port *port) * Allocate the IRQ */ retval = request_irq(port->irq, atmel_interrupt, - IRQF_SHARED | IRQF_COND_SUSPEND, - tty ? tty->name : "atmel_serial", port); + IRQF_SHARED | IRQF_COND_SUSPEND, + dev_name(&pdev->dev), port); if (retval) { dev_err(port->dev, "atmel_startup - Can't get irq\n"); return retval; diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f2ab6d8aab4127ff86e172afa61e89238b93c093..5609305b3676da175043f67bd13a5622fcadb429 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -866,15 +866,12 @@ static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p) dma->rx_conf.direction = DMA_DEV_TO_MEM; dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH; - dma->rx_conf.src_maxburst = 16; + dma->rx_conf.src_maxburst = 1; dma->tx_conf.direction = DMA_MEM_TO_DEV; dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH; - if (dma_get_cache_alignment() >= 16) - dma->tx_conf.dst_maxburst = 16; - else - dma->tx_conf.dst_maxburst = 1; + dma->tx_conf.dst_maxburst = 1; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 107f0d194ac5fcfd8fd34d0feae0a6cd46941051..6ff53b604ff6df40a47426ea9225494d35a6a61c 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2626,8 +2626,8 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) dev_dbg(dev, "failed to get %s (%ld)\n", clk_names[i], PTR_ERR(clk)); else - dev_dbg(dev, "clk %s is %pC rate %pCr\n", clk_names[i], - clk, clk); + dev_dbg(dev, "clk %s is %pC rate %lu\n", clk_names[i], + clk, clk_get_rate(clk)); sci_port->clks[i] = IS_ERR(clk) ? NULL : clk; } return 0; @@ -2807,16 +2807,15 @@ static void serial_console_write(struct console *co, const char *s, unsigned long flags; int locked = 1; - local_irq_save(flags); #if defined(SUPPORT_SYSRQ) if (port->sysrq) locked = 0; else #endif if (oops_in_progress) - locked = spin_trylock(&port->lock); + locked = spin_trylock_irqsave(&port->lock, flags); else - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); /* first save SCSCR then disable interrupts, keep clock source */ ctrl = serial_port_in(port, SCSCR); @@ -2835,8 +2834,7 @@ static void serial_console_write(struct console *co, const char *s, serial_port_out(port, SCSCR, ctrl); if (locked) - spin_unlock(&port->lock); - local_irq_restore(flags); + spin_unlock_irqrestore(&port->lock, flags); } static int serial_console_setup(struct console *co, char *options) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 9e1ac58e269e138a3e258e216c2f10830137c0aa..9d3e413f48c6a2e4d63963ff8cde75efd256d0c6 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -785,7 +785,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ if (!*vc->vc_uni_pagedir_loc) con_set_default_unimap(vc); - vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); + vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL); if (!vc->vc_screenbuf) goto err_free; @@ -872,7 +872,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, if (new_screen_size > (4 << 20)) return -EINVAL; - newscreen = kmalloc(new_screen_size, GFP_USER); + newscreen = kzalloc(new_screen_size, GFP_USER); if (!newscreen) return -ENOMEM; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index fe22ac7c760a684caf537c0690ffa205d0188c70..08bef18372eadd550eb294e75b003f1b7e3b082b 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1712,6 +1712,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x11ca, 0x0201), /* VeriFone Mx870 Gadget Serial */ .driver_info = SINGLE_RX_URB, }, + { USB_DEVICE(0x1965, 0x0018), /* Uniden UBC125XLT */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x22b8, 0x7000), /* Motorola Q Phone */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 876679a84f507573f526105d62141fd8052549be..f794741b476a9c9eb0da3607eb324989f8275505 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -763,18 +763,21 @@ void usb_destroy_configuration(struct usb_device *dev) return; if (dev->rawdescriptors) { - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + for (i = 0; i < dev->descriptor.bNumConfigurations && + i < USB_MAXCONFIG; i++) kfree(dev->rawdescriptors[i]); kfree(dev->rawdescriptors); dev->rawdescriptors = NULL; } - for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { + for (c = 0; c < dev->descriptor.bNumConfigurations && + c < USB_MAXCONFIG; c++) { struct usb_host_config *cf = &dev->config[c]; kfree(cf->string); - for (i = 0; i < cf->desc.bNumInterfaces; i++) { + for (i = 0; i < cf->desc.bNumInterfaces && + i < USB_MAXINTERFACES; i++) { if (cf->intf_cache[i]) kref_put(&cf->intf_cache[i]->ref, usb_release_interface_cache); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a9b3bbd816f6eb692dc2b3126ed8389ed67455e2..771efc909d79eca1cafc68f5cd83fe0588c89ba7 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4522,7 +4522,9 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, * reset. But only on the first attempt, * lest we get into a time out/reset loop */ - if (r == 0 || (r == -ETIMEDOUT && retries == 0)) + if (r == 0 || (r == -ETIMEDOUT && + retries == 0 && + udev->speed > USB_SPEED_FULL)) break; } udev->descriptor.bMaxPacketSize0 = diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 13754353251f1a2252a1cf743d6c19523859c478..9669184fb1fe974d66fb742c84402dbcc27d731e 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -479,7 +479,7 @@ static unsigned long *dwc2_get_ls_map(struct dwc2_hsotg *hsotg, /* Get the map and adjust if this is a multi_tt hub */ map = qh->dwc_tt->periodic_bitmaps; if (qh->dwc_tt->usb_tt->multi) - map += DWC2_ELEMENTS_PER_LS_BITMAP * qh->ttport; + map += DWC2_ELEMENTS_PER_LS_BITMAP * (qh->ttport - 1); return map; } diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 2c306603c838d658368981b60e7299da1c37b7af..f99b2bdd64ffd366033d6cac78e755c56d92972e 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -255,6 +255,7 @@ struct dwc3_msm { struct notifier_block id_nb; struct notifier_block eud_event_nb; struct notifier_block host_restart_nb; + struct notifier_block self_power_nb; struct notifier_block host_nb; bool xhci_ss_compliance_enable; @@ -296,6 +297,8 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned int event, unsigned int value); static int dwc3_restart_usb_host_mode(struct notifier_block *nb, unsigned long event, void *ptr); +static int dwc3_notify_pd_status(struct notifier_block *nb, + unsigned long event, void *ptr); /** * @@ -3041,12 +3044,19 @@ static int dwc3_msm_extcon_register(struct dwc3_msm *mdwc, int start_idx) if (!IS_ERR(edev)) { mdwc->extcon_vbus = edev; mdwc->vbus_nb.notifier_call = dwc3_msm_vbus_notifier; + mdwc->self_power_nb.notifier_call = dwc3_notify_pd_status; ret = extcon_register_notifier(edev, EXTCON_USB, &mdwc->vbus_nb); if (ret < 0) { dev_err(mdwc->dev, "failed to register notifier for USB\n"); return ret; } + ret = extcon_register_blocking_notifier(edev, EXTCON_USB, + &mdwc->self_power_nb); + if (ret < 0) { + dev_err(mdwc->dev, "failed to register blocking notifier\n"); + goto err1; + } } /* @@ -4148,6 +4158,28 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) return 0; } +static int dwc3_notify_pd_status(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct dwc3_msm *mdwc; + struct dwc3 *dwc; + int ret = 0; + union extcon_property_value val; + + mdwc = container_of(nb, struct dwc3_msm, self_power_nb); + dwc = platform_get_drvdata(mdwc->dwc3); + + ret = extcon_get_property(mdwc->extcon_vbus, EXTCON_USB, + EXTCON_PROP_USB_PD_CONTRACT, &val); + + if (!ret) + dwc->gadget.self_powered = val.intval; + else + dwc->gadget.self_powered = 0; + + return ret; +} + /* speed: 0 - USB_SPEED_HIGH, 1 - USB_SPEED_SUPER */ static int dwc3_restart_usb_host_mode(struct notifier_block *nb, unsigned long event, void *ptr) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 6f8a04e0c36323ca8b769215db36351772324ba3..32729c6db6153bd43fec31b1d8f2ffb4478c0897 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -594,6 +594,10 @@ static int config_buf(struct usb_configuration *config, c->iConfiguration = config->iConfiguration; c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; c->bMaxPower = encode_bMaxPower(speed, config); + if (config->cdev->gadget->self_powered) { + c->bmAttributes |= USB_CONFIG_ATT_SELFPOWER; + c->bMaxPower = 0; + } /* There may be e.g. OTG descriptors */ if (config->descriptors) { diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 2197a50ed2ab814967df57acc73af438f760dda9..b1ae944c83a939a380e9785db4666924056c5bbd 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -521,6 +521,13 @@ static void usb3_disconnect(struct renesas_usb3 *usb3) usb3_usb2_pullup(usb3, 0); usb3_clear_bit(usb3, USB30_CON_B3_CONNECT, USB3_USB30_CON); usb3_reset_epc(usb3); + usb3_disable_irq_1(usb3, USB_INT_1_B2_RSUM | USB_INT_1_B3_PLLWKUP | + USB_INT_1_B3_LUPSUCS | USB_INT_1_B3_DISABLE | + USB_INT_1_SPEED | USB_INT_1_B3_WRMRST | + USB_INT_1_B3_HOTRST | USB_INT_1_B2_SPND | + USB_INT_1_B2_L1SPND | USB_INT_1_B2_USBRST); + usb3_clear_bit(usb3, USB_COM_CON_SPD_MODE, USB3_USB_COM_CON); + usb3_init_epc_registers(usb3); if (usb3->driver) usb3->driver->disconnect(&usb3->gadget); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index e2bc91585b4fd4ca4fc43a403798156baf955235..19b5f08cb423d3a7160b346075780d91491e28c8 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2554,8 +2554,11 @@ static int musb_bus_suspend(struct usb_hcd *hcd) { struct musb *musb = hcd_to_musb(hcd); u8 devctl; + int ret; - musb_port_suspend(musb, true); + ret = musb_port_suspend(musb, true); + if (ret) + return ret; if (!is_host_active(musb)) return 0; diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 7bbf01bf4bb0b51a42104e7302a5d01012ee551f..54d02ed032df013c94e913a5a45b29bf2b8aa21b 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -92,7 +92,7 @@ extern void musb_host_rx(struct musb *, u8); extern void musb_root_disconnect(struct musb *musb); extern void musb_host_resume_root_hub(struct musb *musb); extern void musb_host_poke_root_hub(struct musb *musb); -extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern int musb_port_suspend(struct musb *musb, bool do_suspend); extern void musb_port_reset(struct musb *musb, bool do_reset); extern void musb_host_finish_resume(struct work_struct *work); #else @@ -124,7 +124,10 @@ static inline void musb_root_disconnect(struct musb *musb) {} static inline void musb_host_resume_root_hub(struct musb *musb) {} static inline void musb_host_poll_rh_status(struct musb *musb) {} static inline void musb_host_poke_root_hub(struct musb *musb) {} -static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline int musb_port_suspend(struct musb *musb, bool do_suspend) +{ + return 0; +} static inline void musb_port_reset(struct musb *musb, bool do_reset) {} static inline void musb_host_finish_resume(struct work_struct *work) {} #endif diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 61b5f1c3c5bcd12e53364e074b5a77ba60362ed5..71678a487be20822515d613deb0c90b2debfb253 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -73,14 +73,14 @@ void musb_host_finish_resume(struct work_struct *work) spin_unlock_irqrestore(&musb->lock, flags); } -void musb_port_suspend(struct musb *musb, bool do_suspend) +int musb_port_suspend(struct musb *musb, bool do_suspend) { struct usb_otg *otg = musb->xceiv->otg; u8 power; void __iomem *mbase = musb->mregs; if (!is_host_active(musb)) - return; + return 0; /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and @@ -91,16 +91,20 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) if (do_suspend) { int retries = 10000; - power &= ~MUSB_POWER_RESUME; - power |= MUSB_POWER_SUSPENDM; - musb_writeb(mbase, MUSB_POWER, power); + if (power & MUSB_POWER_RESUME) + return -EBUSY; - /* Needed for OPT A tests */ - power = musb_readb(mbase, MUSB_POWER); - while (power & MUSB_POWER_SUSPENDM) { + if (!(power & MUSB_POWER_SUSPENDM)) { + power |= MUSB_POWER_SUSPENDM; + musb_writeb(mbase, MUSB_POWER, power); + + /* Needed for OPT A tests */ power = musb_readb(mbase, MUSB_POWER); - if (retries-- < 1) - break; + while (power & MUSB_POWER_SUSPENDM) { + power = musb_readb(mbase, MUSB_POWER); + if (retries-- < 1) + break; + } } musb_dbg(musb, "Root port suspended, power %02x", power); @@ -137,6 +141,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) schedule_delayed_work(&musb->finish_resume_work, msecs_to_jiffies(USB_RESUME_TIMEOUT)); } + return 0; } void musb_port_reset(struct musb *musb, bool do_reset) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6685f05bab57434bcea63cd3809413c1771b6116..a9adf0b5257c1ec509fb5e9431ffbf311526cf73 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -374,7 +374,6 @@ struct usbpd { struct rx_msg *rx_ext_msg; u32 received_pdos[PD_MAX_DATA_OBJ]; - u32 received_ado; u16 src_cap_id; u8 selected_pdo; u8 requested_pdo; @@ -443,6 +442,7 @@ struct usbpd { u8 src_cap_ext_db[PD_SRC_CAP_EXT_DB_LEN]; bool send_get_pps_status; u32 pps_status_db; + bool send_get_status; u8 status_db[PD_STATUS_DB_LEN]; bool send_get_battery_cap; u8 get_battery_cap_db; @@ -533,6 +533,22 @@ static inline void start_usb_peripheral(struct usbpd *pd) extcon_set_state_sync(pd->extcon, EXTCON_USB, 1); } +static void notify_pd_contract_status(struct usbpd *pd) +{ + int ret = 0; + union extcon_property_value val; + + if (!pd) + return; + + val.intval = pd->in_explicit_contract; + extcon_set_property(pd->extcon, EXTCON_USB, + EXTCON_PROP_USB_PD_CONTRACT, val); + ret = extcon_blocking_sync(pd->extcon, EXTCON_USB, 0); + if (ret) + usbpd_err(&pd->dev, "err(%d) while notifying pd status", ret); +} + /** * This API allows client driver to request for releasing SS lanes. It should * not be called from atomic context. @@ -1252,6 +1268,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SRC_READY: pd->in_explicit_contract = true; + notify_pd_contract_status(pd); if (pd->vdm_tx) kick_sm(pd, 0); @@ -1398,6 +1415,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) case PE_SNK_READY: pd->in_explicit_contract = true; + notify_pd_contract_status(pd); if (pd->vdm_tx) kick_sm(pd, 0); @@ -1433,6 +1451,7 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) POWER_SUPPLY_PROP_PD_CURRENT_MAX, &val); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); /* * need to update PR bit in message header so that @@ -1929,6 +1948,22 @@ static int enable_vbus(struct usbpd *pd) else pd->vbus_enabled = true; + count = 10; + /* + * Check to make sure VBUS voltage reaches above Vsafe5Vmin (4.75v) + * before proceeding. + */ + while (count--) { + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + if (ret || val.intval >= 4750000) /*vsafe5Vmin*/ + break; + usleep_range(10000, 12000); /* Delay between two reads */ + } + + if (ret) + msleep(100); /* Delay to wait for VBUS ramp up if read fails */ + return ret; } @@ -1996,6 +2031,7 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = false; pd->pd_connected = false; pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->hard_reset_recvd = false; pd->caps_count = 0; pd->hard_reset_count = 0; @@ -2079,6 +2115,7 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PR_SWAP, &val); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->selected_pdo = pd->requested_pdo = 0; pd->rdo = 0; rx_msg_cleanup(pd); @@ -2252,7 +2289,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_pr_swap = false; ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending PR Swap\n"); + usbpd_err(&pd->dev, "Error sending PR Swap\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } @@ -2263,7 +2300,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_dr_swap = false; ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending DR Swap\n"); + usbpd_err(&pd->dev, "Error sending DR Swap\n"); usbpd_set_state(pd, PE_SRC_SEND_SOFT_RESET); break; } @@ -2302,6 +2339,7 @@ static void usbpd_sm(struct work_struct *w) pd_send_hard_reset(pd); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->rdo = 0; rx_msg_cleanup(pd); reset_vdm_state(pd); @@ -2552,8 +2590,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_msg(pd, MSG_GET_SOURCE_CAP_EXTENDED, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_src_cap_ext\n"); + usbpd_err(&pd->dev, "Error sending get_src_cap_ext\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2572,8 +2609,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_msg(pd, MSG_GET_PPS_STATUS, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_pps_status\n"); + usbpd_err(&pd->dev, "Error sending get_pps_status\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2588,23 +2624,32 @@ static void usbpd_sm(struct work_struct *w) sizeof(pd->pps_status_db)); complete(&pd->is_ready); } else if (IS_DATA(rx_msg, MSG_ALERT)) { - if (rx_msg->data_len != sizeof(pd->received_ado)) { + u32 ado; + + if (rx_msg->data_len != sizeof(ado)) { usbpd_err(&pd->dev, "Invalid ado\n"); break; } - memcpy(&pd->received_ado, rx_msg->payload, - sizeof(pd->received_ado)); - ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, - 0, SOP_MSG); + memcpy(&ado, rx_msg->payload, sizeof(ado)); + usbpd_dbg(&pd->dev, "Received Alert 0x%08x\n", ado); + + /* + * Don't send Get_Status right away so we can coalesce + * multiple Alerts. 150ms should be enough to not get + * in the way of any other AMS that might happen. + */ + pd->send_get_status = true; + kick_sm(pd, 150); + } else if (pd->send_get_status && is_sink_tx_ok(pd)) { + pd->send_get_status = false; + ret = pd_send_msg(pd, MSG_GET_STATUS, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_status\n"); + usbpd_err(&pd->dev, "Error sending get_status\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } kick_sm(pd, SENDER_RESPONSE_TIME); - } else if (rx_msg && - IS_EXT(rx_msg, MSG_STATUS)) { + } else if (rx_msg && IS_EXT(rx_msg, MSG_STATUS)) { if (rx_msg->data_len != PD_STATUS_DB_LEN) { usbpd_err(&pd->dev, "Invalid status db\n"); break; @@ -2617,8 +2662,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_CAP, &pd->get_battery_cap_db, 1, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_battery_cap\n"); + usbpd_err(&pd->dev, "Error sending get_battery_cap\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2637,8 +2681,7 @@ static void usbpd_sm(struct work_struct *w) ret = pd_send_ext_msg(pd, MSG_GET_BATTERY_STATUS, &pd->get_battery_status_db, 1, SOP_MSG); if (ret) { - dev_err(&pd->dev, - "Error sending get_battery_status\n"); + usbpd_err(&pd->dev, "Error sending get_battery_status\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2668,7 +2711,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_pr_swap = false; ret = pd_send_msg(pd, MSG_PR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending PR Swap\n"); + usbpd_err(&pd->dev, "Error sending PR Swap\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2679,7 +2722,7 @@ static void usbpd_sm(struct work_struct *w) pd->send_dr_swap = false; ret = pd_send_msg(pd, MSG_DR_SWAP, NULL, 0, SOP_MSG); if (ret) { - dev_err(&pd->dev, "Error sending DR Swap\n"); + usbpd_err(&pd->dev, "Error sending DR Swap\n"); usbpd_set_state(pd, PE_SNK_SEND_SOFT_RESET); break; } @@ -2747,6 +2790,7 @@ static void usbpd_sm(struct work_struct *w) pd_send_hard_reset(pd); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); pd->selected_pdo = pd->requested_pdo = 0; pd->rdo = 0; reset_vdm_state(pd); @@ -2778,6 +2822,7 @@ static void usbpd_sm(struct work_struct *w) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PR_SWAP, &val); pd->in_explicit_contract = false; + notify_pd_contract_status(pd); if (pd->vbus_enabled) { regulator_disable(pd->vbus); @@ -2838,7 +2883,6 @@ static void usbpd_sm(struct work_struct *w) case PE_PRS_SNK_SRC_SOURCE_ON: enable_vbus(pd); - msleep(200); /* allow time VBUS ramp-up, must be < tNewSrc */ ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { @@ -3297,9 +3341,9 @@ static int usbpd_uevent(struct device *dev, struct kobj_uevent_env *env) "explicit" : "implicit"); add_uevent_var(env, "ALT_MODE=%d", pd->vdm_state == MODE_ENTERED); - add_uevent_var(env, "ADO=%08x", pd->received_ado); - for (i = 0; i < PD_STATUS_DB_LEN; i++) - add_uevent_var(env, "SDB%d=%08x", i, pd->status_db[i]); + add_uevent_var(env, "SDB=%02x %02x %02x %02x %02x", pd->status_db[0], + pd->status_db[1], pd->status_db[2], pd->status_db[3], + pd->status_db[4]); return 0; } @@ -3690,38 +3734,56 @@ static ssize_t get_src_cap_ext_show(struct device *dev, return ret; for (i = 0; i < PD_SRC_CAP_EXT_DB_LEN; i++) - len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", - pd->src_cap_ext_db[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x", + i ? " " : "", pd->src_cap_ext_db[i]); + + buf[len++] = '\n'; + buf[len] = '\0'; + return len; } static DEVICE_ATTR_RO(get_src_cap_ext); -static ssize_t get_pps_status_show(struct device *dev, +static ssize_t get_status_show(struct device *dev, struct device_attribute *attr, char *buf) { - int ret; + int i, ret, len = 0; struct usbpd *pd = dev_get_drvdata(dev); if (pd->spec_rev == USBPD_REV_20) return -EINVAL; - ret = trigger_tx_msg(pd, &pd->send_get_pps_status); + ret = trigger_tx_msg(pd, &pd->send_get_status); if (ret) return ret; - return snprintf(buf, PAGE_SIZE, "%d\n", pd->pps_status_db); + for (i = 0; i < PD_STATUS_DB_LEN; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x", + i ? " " : "", pd->status_db[i]); + + buf[len++] = '\n'; + buf[len] = '\0'; + + return len; } -static DEVICE_ATTR_RO(get_pps_status); +static DEVICE_ATTR_RO(get_status); -static ssize_t rx_ado_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t get_pps_status_show(struct device *dev, + struct device_attribute *attr, char *buf) { + int ret; struct usbpd *pd = dev_get_drvdata(dev); - /* dump the ADO as a hex string */ - return snprintf(buf, PAGE_SIZE, "%08x\n", pd->received_ado); + if (pd->spec_rev == USBPD_REV_20) + return -EINVAL; + + ret = trigger_tx_msg(pd, &pd->send_get_pps_status); + if (ret) + return ret; + + return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->pps_status_db); } -static DEVICE_ATTR_RO(rx_ado); +static DEVICE_ATTR_RO(get_pps_status); static ssize_t get_battery_cap_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -3751,8 +3813,12 @@ static ssize_t get_battery_cap_show(struct device *dev, return -EINVAL; for (i = 0; i < PD_BATTERY_CAP_DB_LEN; i++) - len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", - pd->battery_cap_db[i]); + len += snprintf(buf + len, PAGE_SIZE - len, "%s0x%02x", + i ? " " : "", pd->battery_cap_db[i]); + + buf[len++] = '\n'; + buf[len] = '\0'; + return len; } static DEVICE_ATTR_RW(get_battery_cap); @@ -3783,7 +3849,7 @@ static ssize_t get_battery_status_show(struct device *dev, if (pd->get_battery_status_db == -EINVAL) return -EINVAL; - return snprintf(buf, PAGE_SIZE, "%d\n", pd->battery_sts_dobj); + return snprintf(buf, PAGE_SIZE, "0x%08x\n", pd->battery_sts_dobj); } static DEVICE_ATTR_RW(get_battery_status); @@ -3807,8 +3873,8 @@ static struct attribute *usbpd_attrs[] = { &dev_attr_rdo_h.attr, &dev_attr_hard_reset.attr, &dev_attr_get_src_cap_ext.attr, + &dev_attr_get_status.attr, &dev_attr_get_pps_status.attr, - &dev_attr_rx_ado.attr, &dev_attr_get_battery_cap.attr, &dev_attr_get_battery_status.attr, NULL, @@ -3963,6 +4029,8 @@ struct usbpd *usbpd_create(struct device *parent) /* Support reporting polarity and speed via properties */ extcon_set_property_capability(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(pd->extcon, EXTCON_USB, + EXTCON_PROP_USB_PD_CONTRACT); extcon_set_property_capability(pd->extcon, EXTCON_USB, EXTCON_PROP_USB_SS); extcon_set_property_capability(pd->extcon, EXTCON_USB_HOST, diff --git a/drivers/usb/pd/qpnp-pdphy.c b/drivers/usb/pd/qpnp-pdphy.c index 2997976d1aa05752342b4455f969733f08d3da26..a1b8a3258bba252dee414474644cf080cef16ad1 100644 --- a/drivers/usb/pd/qpnp-pdphy.c +++ b/drivers/usb/pd/qpnp-pdphy.c @@ -50,7 +50,7 @@ #define TX_SIZE_MASK 0xF #define USB_PDPHY_TX_CONTROL 0x44 -#define TX_CONTROL_RETRY_COUNT (BIT(6) | BIT(5)) +#define TX_CONTROL_RETRY_COUNT(n) (((n) & 0x3) << 5) #define TX_CONTROL_FRAME_TYPE (BIT(4) | BIT(3) | BIT(2)) #define TX_CONTROL_FRAME_TYPE_CABLE_RESET (0x1 << 2) #define TX_CONTROL_SEND_SIGNAL BIT(1) @@ -80,6 +80,9 @@ #define VDD_PDPHY_VOL_MAX 3088000 /* uV */ #define VDD_PDPHY_HPM_LOAD 3000 /* uA */ +/* Message Spec Rev field */ +#define PD_MSG_HDR_REV(hdr) (((hdr) >> 6) & 3) + /* timers */ #define RECEIVER_RESPONSE_TIME 15 /* tReceiverResponse */ #define HARD_RESET_COMPLETE_TIME 5 /* tHardResetComplete */ @@ -437,12 +440,12 @@ int pd_phy_signal(enum pd_sig_type sig) if (ret) return ret; - ret = wait_event_interruptible_timeout(pdphy->tx_waitq, + ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq, pdphy->tx_status != -EINPROGRESS, - msecs_to_jiffies(HARD_RESET_COMPLETE_TIME)); - if (ret <= 0) { + ms_to_ktime(HARD_RESET_COMPLETE_TIME)); + if (ret) { dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret); - return ret ? ret : -ETIMEDOUT; + return ret; } ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, 0); @@ -520,18 +523,24 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) usleep_range(2, 3); - val = TX_CONTROL_RETRY_COUNT | (sop << 2) | TX_CONTROL_SEND_MSG; + val = (sop << 2) | TX_CONTROL_SEND_MSG; + + /* nRetryCount == 2 for PD 3.0, 3 for PD 2.0 */ + if (PD_MSG_HDR_REV(hdr) == USBPD_REV_30) + val |= TX_CONTROL_RETRY_COUNT(2); + else + val |= TX_CONTROL_RETRY_COUNT(3); ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val); if (ret) return ret; - ret = wait_event_interruptible_timeout(pdphy->tx_waitq, + ret = wait_event_interruptible_hrtimeout(pdphy->tx_waitq, pdphy->tx_status != -EINPROGRESS, - msecs_to_jiffies(RECEIVER_RESPONSE_TIME)); - if (ret <= 0) { + ms_to_ktime(RECEIVER_RESPONSE_TIME)); + if (ret) { dev_err(pdphy->dev, "%s: failed ret %d", __func__, ret); - return ret ? ret : -ETIMEDOUT; + return ret; } if (hdr && !pdphy->tx_status) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 90d7c6e921de2c09aff0ec6c68f36f9a2739cf43..71a8ede8efdb0c3029bc5052ed99546aaa6d54fe 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -33,7 +33,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *); static void cp210x_close(struct usb_serial_port *); static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *); static void cp210x_get_termios_port(struct usb_serial_port *port, - unsigned int *cflagp, unsigned int *baudp); + tcflag_t *cflagp, unsigned int *baudp); static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, struct ktermios *); static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, @@ -92,6 +92,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8156) }, /* B&G H3000 link cable */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ { USB_DEVICE(0x10C4, 0x815F) }, /* Timewave HamLinkUSB */ + { USB_DEVICE(0x10C4, 0x817C) }, /* CESINEL MEDCAL N Power Quality Monitor */ + { USB_DEVICE(0x10C4, 0x817D) }, /* CESINEL MEDCAL NT Power Quality Monitor */ + { USB_DEVICE(0x10C4, 0x817E) }, /* CESINEL MEDCAL S Power Quality Monitor */ { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ @@ -109,6 +112,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ + { USB_DEVICE(0x10C4, 0x82EF) }, /* CESINEL FALCO 6105 AC Power Supply */ + { USB_DEVICE(0x10C4, 0x82F1) }, /* CESINEL MEDCAL EFD Earth Fault Detector */ + { USB_DEVICE(0x10C4, 0x82F2) }, /* CESINEL MEDCAL ST Network Analyzer */ { USB_DEVICE(0x10C4, 0x82F4) }, /* Starizona MicroTouch */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ @@ -121,7 +127,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8470) }, /* Juniper Networks BX Series System Console */ { USB_DEVICE(0x10C4, 0x8477) }, /* Balluff RFID */ { USB_DEVICE(0x10C4, 0x84B6) }, /* Starizona Hyperion */ + { USB_DEVICE(0x10C4, 0x851E) }, /* CESINEL MEDCAL PT Network Analyzer */ { USB_DEVICE(0x10C4, 0x85A7) }, /* LifeScan OneTouch Verio IQ */ + { USB_DEVICE(0x10C4, 0x85B8) }, /* CESINEL ReCon T Energy Logger */ { USB_DEVICE(0x10C4, 0x85EA) }, /* AC-Services IBUS-IF */ { USB_DEVICE(0x10C4, 0x85EB) }, /* AC-Services CIS-IBUS */ { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ @@ -131,17 +139,23 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8857) }, /* CEL EM357 ZigBee USB Stick */ { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ + { USB_DEVICE(0x10C4, 0x88FB) }, /* CESINEL MEDCAL STII Network Analyzer */ + { USB_DEVICE(0x10C4, 0x8938) }, /* CESINEL MEDCAL S II Network Analyzer */ { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */ { USB_DEVICE(0x10C4, 0x8962) }, /* Brim Brothers charging dock */ { USB_DEVICE(0x10C4, 0x8977) }, /* CEL MeshWorks DevKit Device */ { USB_DEVICE(0x10C4, 0x8998) }, /* KCF Technologies PRN */ + { USB_DEVICE(0x10C4, 0x89A4) }, /* CESINEL FTBC Flexible Thyristor Bridge Controller */ { USB_DEVICE(0x10C4, 0x8A2A) }, /* HubZ dual ZigBee and Z-Wave dongle */ { USB_DEVICE(0x10C4, 0x8A5E) }, /* CEL EM3588 ZigBee USB Stick Long Range */ { USB_DEVICE(0x10C4, 0x8B34) }, /* Qivicon ZigBee USB Radio Stick */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA63) }, /* Silicon Labs Windows Update (CP2101-4/CP2102N) */ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */ { USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */ + { USB_DEVICE(0x10C4, 0xEA7A) }, /* Silicon Labs Windows Update (CP2105) */ + { USB_DEVICE(0x10C4, 0xEA7B) }, /* Silicon Labs Windows Update (CP2108) */ { USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */ { USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */ { USB_DEVICE(0x10C4, 0xF003) }, /* Elan Digital Systems USBpulse100 */ @@ -728,7 +742,7 @@ static void cp210x_get_termios(struct tty_struct *tty, &tty->termios.c_cflag, &baud); tty_encode_baud_rate(tty, baud, baud); } else { - unsigned int cflag; + tcflag_t cflag; cflag = 0; cp210x_get_termios_port(port, &cflag, &baud); } @@ -739,10 +753,10 @@ static void cp210x_get_termios(struct tty_struct *tty, * This is the heart of cp210x_get_termios which always uses a &usb_serial_port. */ static void cp210x_get_termios_port(struct usb_serial_port *port, - unsigned int *cflagp, unsigned int *baudp) + tcflag_t *cflagp, unsigned int *baudp) { struct device *dev = &port->dev; - unsigned int cflag; + tcflag_t cflag; struct cp210x_flow_ctl flow_ctl; u32 baud; u16 bits = 0; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index a96dcc660d0f07c49cb58e297ef9d999d9caa3ae..8dd200f920200a0f84de9f2f7ba93e9519ce2408 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -836,6 +836,12 @@ static int uas_slave_configure(struct scsi_device *sdev) if (devinfo->flags & US_FL_BROKEN_FUA) sdev->broken_fua = 1; + /* UAS also needs to support FL_ALWAYS_SYNC */ + if (devinfo->flags & US_FL_ALWAYS_SYNC) { + sdev->skip_ms_page_3f = 1; + sdev->skip_ms_page_8 = 1; + sdev->wce_default_on = 1; + } scsi_change_queue_depth(sdev, devinfo->qdepth - 2); return 0; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index ca3a5d430ae1c45cf344129e254fe91ccb60336c..fc5ed351defbf5e6834bfe65c758d1f550ac41cc 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2340,6 +2340,15 @@ UNUSUAL_DEV( 0x4146, 0xba01, 0x0100, 0x0100, "Micro Mini 1GB", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), +/* "G-DRIVE" external HDD hangs on write without these. + * Patch submitted by Alexander Kappner + */ +UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), + /* * Nick Bowler * SCSI stack spams (otherwise harmless) error messages. diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 719ec68ae3099e78b1c11554884f87e43b5c1cde..f15aa47c54a9dccc6238faed23d6de6b8f43cfb5 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -183,3 +183,12 @@ UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999, "External HDD", USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NO_REPORT_OPCODES), + +/* "G-DRIVE" external HDD hangs on write without these. + * Patch submitted by Alexander Kappner + */ +UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999, + "SimpleTech", + "External HDD", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_ALWAYS_SYNC), diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index c287ccc78fde811c26a2bea60ade1fe2c39c507f..e8a008de8dbc8baebfc0d4b99eb9f97e741aad4b 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -24,6 +24,9 @@ #include #include +/* Hardening for Spectre-v1 */ +#include + #include "usbip_common.h" #include "vhci.h" @@ -181,16 +184,20 @@ static int vhci_port_disconnect(struct vhci_hcd *vhci, __u32 rhport) return 0; } -static int valid_port(__u32 pdev_nr, __u32 rhport) +static int valid_port(__u32 *pdev_nr, __u32 *rhport) { - if (pdev_nr >= vhci_num_controllers) { - pr_err("pdev %u\n", pdev_nr); + if (*pdev_nr >= vhci_num_controllers) { + pr_err("pdev %u\n", *pdev_nr); return 0; } - if (rhport >= VHCI_HC_PORTS) { - pr_err("rhport %u\n", rhport); + *pdev_nr = array_index_nospec(*pdev_nr, vhci_num_controllers); + + if (*rhport >= VHCI_HC_PORTS) { + pr_err("rhport %u\n", *rhport); return 0; } + *rhport = array_index_nospec(*rhport, VHCI_HC_PORTS); + return 1; } @@ -207,7 +214,7 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, pdev_nr = port_to_pdev_nr(port); rhport = port_to_rhport(port); - if (!valid_port(pdev_nr, rhport)) + if (!valid_port(&pdev_nr, &rhport)) return -EINVAL; hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); @@ -226,7 +233,8 @@ static ssize_t store_detach(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(detach, S_IWUSR, NULL, store_detach); -static int valid_args(__u32 pdev_nr, __u32 rhport, enum usb_device_speed speed) +static int valid_args(__u32 *pdev_nr, __u32 *rhport, + enum usb_device_speed speed) { if (!valid_port(pdev_nr, rhport)) { return 0; @@ -288,7 +296,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, sockfd, devid, speed); /* check received parameters */ - if (!valid_args(pdev_nr, rhport, speed)) + if (!valid_args(&pdev_nr, &rhport, speed)) return -EINVAL; hcd = platform_get_drvdata(*(vhci_pdevs + pdev_nr)); diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index fce49ebc575dd143eb69129c314f8458ad3eca3b..8b6489ae74ebbf397157a909d82237beeed6b7d2 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -938,6 +938,7 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, { int ret = 0; + mutex_lock(&dev->mutex); vhost_dev_lock_vqs(dev); switch (msg->type) { case VHOST_IOTLB_UPDATE: @@ -967,6 +968,8 @@ int vhost_process_iotlb_msg(struct vhost_dev *dev, } vhost_dev_unlock_vqs(dev); + mutex_unlock(&dev->mutex); + return ret; } ssize_t vhost_chr_write_iter(struct vhost_dev *dev, @@ -2292,6 +2295,9 @@ struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type) struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL); if (!node) return NULL; + + /* Make sure all padding within the structure is initialized. */ + memset(&node->msg, 0, sizeof node->msg); node->vq = vq; node->msg.type = type; return node; diff --git a/drivers/video/backlight/as3711_bl.c b/drivers/video/backlight/as3711_bl.c index 734a9158946b1f805a3738d9e9c31f25cf8b3314..e55304d5cf0716a231c5674e856a9ae205b78c65 100644 --- a/drivers/video/backlight/as3711_bl.c +++ b/drivers/video/backlight/as3711_bl.c @@ -262,10 +262,10 @@ static int as3711_bl_register(struct platform_device *pdev, static int as3711_backlight_parse_dt(struct device *dev) { struct as3711_bl_pdata *pdata = dev_get_platdata(dev); - struct device_node *bl = - of_find_node_by_name(dev->parent->of_node, "backlight"), *fb; + struct device_node *bl, *fb; int ret; + bl = of_get_child_by_name(dev->parent->of_node, "backlight"); if (!bl) { dev_dbg(dev, "backlight node not found\n"); return -ENODEV; @@ -279,7 +279,7 @@ static int as3711_backlight_parse_dt(struct device *dev) if (pdata->su1_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; } fb = of_parse_phandle(bl, "su2-dev", 0); @@ -292,7 +292,7 @@ static int as3711_backlight_parse_dt(struct device *dev) if (pdata->su2_max_uA <= 0) ret = -EINVAL; if (ret < 0) - return ret; + goto err_put_bl; if (of_find_property(bl, "su2-feedback-voltage", NULL)) { pdata->su2_feedback = AS3711_SU2_VOLTAGE; @@ -314,8 +314,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_feedback = AS3711_SU2_CURR_AUTO; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-fbprot-lx-sd4", NULL)) { @@ -334,8 +336,10 @@ static int as3711_backlight_parse_dt(struct device *dev) pdata->su2_fbprot = AS3711_SU2_GPIO4; count++; } - if (count != 1) - return -EINVAL; + if (count != 1) { + ret = -EINVAL; + goto err_put_bl; + } count = 0; if (of_find_property(bl, "su2-auto-curr1", NULL)) { @@ -355,11 +359,20 @@ static int as3711_backlight_parse_dt(struct device *dev) * At least one su2-auto-curr* must be specified iff * AS3711_SU2_CURR_AUTO is used */ - if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) - return -EINVAL; + if (!count ^ (pdata->su2_feedback != AS3711_SU2_CURR_AUTO)) { + ret = -EINVAL; + goto err_put_bl; + } } + of_node_put(bl); + return 0; + +err_put_bl: + of_node_put(bl); + + return ret; } static int as3711_backlight_probe(struct platform_device *pdev) diff --git a/drivers/video/backlight/max8925_bl.c b/drivers/video/backlight/max8925_bl.c index 7b738d60ecc22e27560e42c9cef0669628e4aa28..f3aa6088f1d97805f23b9780a1db893cf1a46b00 100644 --- a/drivers/video/backlight/max8925_bl.c +++ b/drivers/video/backlight/max8925_bl.c @@ -116,7 +116,7 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!pdata) return; - np = of_find_node_by_name(nproot, "backlight"); + np = of_get_child_by_name(nproot, "backlight"); if (!np) { dev_err(&pdev->dev, "failed to find backlight node\n"); return; @@ -125,6 +125,8 @@ static void max8925_backlight_dt_init(struct platform_device *pdev) if (!of_property_read_u32(np, "maxim,max8925-dual-string", &val)) pdata->dual_string = val; + of_node_put(np); + pdev->dev.platform_data = pdata; } diff --git a/drivers/video/backlight/tps65217_bl.c b/drivers/video/backlight/tps65217_bl.c index fd524ad860a57bd4ac11166eeef278ef306358a4..f45d0c9467dbf1d909d59db5ead8ada41a225b60 100644 --- a/drivers/video/backlight/tps65217_bl.c +++ b/drivers/video/backlight/tps65217_bl.c @@ -184,11 +184,11 @@ static struct tps65217_bl_pdata * tps65217_bl_parse_dt(struct platform_device *pdev) { struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); - struct device_node *node = of_node_get(tps->dev->of_node); + struct device_node *node; struct tps65217_bl_pdata *pdata, *err; u32 val; - node = of_find_node_by_name(node, "backlight"); + node = of_get_child_by_name(tps->dev->of_node, "backlight"); if (!node) return ERR_PTR(-ENODEV); diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 2ef33d45b0b656d09acb6b33e2d59dbc2094fcd2..52bbbc47e9370cf611595b124ef3e58060ae46c1 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1219,8 +1219,6 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, console_unlock(); break; default: - if (!lock_fb_info(info)) - return -ENODEV; fb = info->fbops; if (fb->fb_ioctl_v2) ret = fb->fb_ioctl_v2(info, cmd, arg, file); @@ -1228,7 +1226,6 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = fb->fb_ioctl(info, cmd, arg); else ret = -ENOTTY; - unlock_fb_info(info); } return ret; } diff --git a/drivers/video/fbdev/msm/mdss_compat_utils.c b/drivers/video/fbdev/msm/mdss_compat_utils.c index a81f149f59ce9f97d95f4a0dc2ef135590eac9a4..23d4a27233d133f7baf2232573f3afb7cec91135 100644 --- a/drivers/video/fbdev/msm/mdss_compat_utils.c +++ b/drivers/video/fbdev/msm/mdss_compat_utils.c @@ -2879,26 +2879,28 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, *pp = compat_alloc_user_space(alloc_size); if (*pp == NULL) return -ENOMEM; - memset(*pp, 0, alloc_size); - - (*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data = - (struct mdp_ar_gc_lut_data *) - ((unsigned long) *pp + - sizeof(struct msmfb_mdp_pp)); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data = - (struct mdp_ar_gc_lut_data *) + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((struct mdp_ar_gc_lut_data *) + ((unsigned long) *pp + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.r_data) || + put_user((struct mdp_ar_gc_lut_data *) ((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - pgc_size); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data = - (struct mdp_ar_gc_lut_data *) + pgc_size), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.g_data) || + put_user((struct mdp_ar_gc_lut_data *) ((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - (2 * pgc_size)); - (*pp)->data.lut_cfg_data.data.pgc_lut_data.cfg_payload - = (void *)((unsigned long) *pp + + (2 * pgc_size)), + &(*pp)->data.lut_cfg_data.data.pgc_lut_data.b_data) || + put_user((void *)((unsigned long) *pp + sizeof(struct msmfb_mdp_pp) + - (3 * pgc_size)); + (3 * pgc_size)), + &(*pp)->data.lut_cfg_data.data. + pgc_lut_data.cfg_payload)) + return -EFAULT; break; case mdp_lut_igc: alloc_size += __pp_compat_size_igc(); @@ -2908,10 +2910,13 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.lut_cfg_data.data.igc_lut_data.cfg_payload - = (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data. + igc_lut_data.cfg_payload)) + return -EFAULT; break; case mdp_lut_hist: alloc_size += __pp_compat_size_hist_lut(); @@ -2921,10 +2926,13 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.lut_cfg_data.data.hist_lut_data.cfg_payload - = (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.lut_cfg_data.data. + hist_lut_data.cfg_payload)) + return -EFAULT; break; default: *pp = compat_alloc_user_space(alloc_size); @@ -2933,7 +2941,8 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size, lut_type); return -ENOMEM; } - memset(*pp, 0, alloc_size); + if (clear_user(*pp, alloc_size)) + return -EFAULT; break; } break; @@ -2945,10 +2954,12 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.pcc_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.pcc_cfg_data.cfg_payload)) + return -EFAULT; break; case mdp_op_gamut_cfg: alloc_size += __pp_compat_size_gamut(); @@ -2958,10 +2969,12 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.gamut_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.gamut_cfg_data.cfg_payload)) + return -EFAULT; break; case mdp_op_pa_v2_cfg: alloc_size += __pp_compat_size_pa(); @@ -2971,16 +2984,19 @@ static int __pp_compat_alloc(struct msmfb_mdp_pp32 __user *pp32, alloc_size); return -ENOMEM; } - memset(*pp, 0, alloc_size); - (*pp)->data.pa_v2_cfg_data.cfg_payload = - (void *)((unsigned long)(*pp) + - sizeof(struct msmfb_mdp_pp)); + if (clear_user(*pp, alloc_size)) + return -EFAULT; + if (put_user((void *)((unsigned long)(*pp) + + sizeof(struct msmfb_mdp_pp)), + &(*pp)->data.pa_v2_cfg_data.cfg_payload)) + return -EFAULT; break; default: *pp = compat_alloc_user_space(alloc_size); if (*pp == NULL) return -ENOMEM; - memset(*pp, 0, alloc_size); + if (clear_user(*pp, alloc_size)) + return -EFAULT; break; } return 0; @@ -3398,7 +3414,9 @@ static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, sizeof(struct mdp_histogram_start_req)); return -EINVAL; } - memset(hist_req, 0, sizeof(struct mdp_histogram_start_req)); + if (clear_user(hist_req, + sizeof(struct mdp_histogram_start_req))) + return -EFAULT; ret = __from_user_hist_start_req(hist_req32, hist_req); if (ret) goto histo_compat_err; @@ -3418,7 +3436,8 @@ static int mdss_histo_compat_ioctl(struct fb_info *info, unsigned int cmd, sizeof(struct mdp_histogram_data)); return -EINVAL; } - memset(hist, 0, sizeof(struct mdp_histogram_data)); + if (clear_user(hist, sizeof(struct mdp_histogram_data))) + return -EFAULT; ret = __from_user_hist_data(hist32, hist); if (ret) goto histo_compat_err; @@ -3921,7 +3940,7 @@ static int __to_user_mdp_overlay(struct mdp_overlay32 __user *ov32, } -static int __from_user_mdp_overlay(struct mdp_overlay *ov, +static int __from_user_mdp_overlay(struct mdp_overlay __user *ov, struct mdp_overlay32 __user *ov32) { __u32 data; @@ -3980,12 +3999,12 @@ static int __from_user_mdp_overlay(struct mdp_overlay *ov, return 0; } -static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, - struct mdp_overlay_list32 *ovlist32, +static int __from_user_mdp_overlaylist(struct mdp_overlay_list __user *ovlist, + struct mdp_overlay_list32 __user *ovlist32, struct mdp_overlay **to_list_head) { __u32 i, ret; - unsigned long data, from_list_head; + unsigned long data, from_list_head, num_overlays; struct mdp_overlay32 *iter; if (!to_list_head || !ovlist32 || !ovlist) { @@ -4006,11 +4025,13 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, sizeof(ovlist32->processed_overlays))) return -EFAULT; - if (get_user(data, &ovlist32->overlay_list)) { + if (get_user(data, &ovlist32->overlay_list) || + get_user(num_overlays, &ovlist32->num_overlays)) { ret = -EFAULT; goto validate_exit; } - for (i = 0; i < ovlist32->num_overlays; i++) { + + for (i = 0; i < num_overlays; i++) { if (get_user(from_list_head, (__u32 *)data + i)) { ret = -EFAULT; goto validate_exit; @@ -4023,7 +4044,8 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, goto validate_exit; } } - ovlist->overlay_list = to_list_head; + if (put_user(to_list_head, &ovlist->overlay_list)) + return -EFAULT; return 0; @@ -4032,8 +4054,8 @@ static int __from_user_mdp_overlaylist(struct mdp_overlay_list *ovlist, return -EFAULT; } -static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 *ovlist32, - struct mdp_overlay_list *ovlist, +static int __to_user_mdp_overlaylist(struct mdp_overlay_list32 __user *ovlist32, + struct mdp_overlay_list __user *ovlist, struct mdp_overlay **l_ptr) { __u32 i, ret; @@ -4106,31 +4128,33 @@ static u32 __pp_sspp_size(void) return size; } -static int __pp_sspp_set_offsets(struct mdp_overlay *ov) +static int __pp_sspp_set_offsets(struct mdp_overlay __user *ov) { if (!ov) { pr_err("invalid overlay pointer\n"); return -EFAULT; } - ov->overlay_pp_cfg.igc_cfg.cfg_payload = (void *)((unsigned long)ov + - sizeof(struct mdp_overlay)); - ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload = - ov->overlay_pp_cfg.igc_cfg.cfg_payload + - sizeof(struct mdp_igc_lut_data_v1_7); - ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload = - ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + - sizeof(struct mdp_pa_data_v1_7); - ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload = - ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + - sizeof(struct mdp_pcc_data_v1_7); + if (put_user((void *)((unsigned long)ov + sizeof(struct mdp_overlay)), + &(ov->overlay_pp_cfg.igc_cfg.cfg_payload)) || + put_user(ov->overlay_pp_cfg.igc_cfg.cfg_payload + + sizeof(struct mdp_igc_lut_data_v1_7), + &(ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload)) || + put_user(ov->overlay_pp_cfg.pa_v2_cfg_data.cfg_payload + + sizeof(struct mdp_pa_data_v1_7), + &(ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload)) || + put_user(ov->overlay_pp_cfg.pcc_cfg_data.cfg_payload + + sizeof(struct mdp_pcc_data_v1_7), + &(ov->overlay_pp_cfg.hist_lut_cfg.cfg_payload))) + return -EFAULT; return 0; } int mdss_compat_overlay_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg, struct file *file) { - struct mdp_overlay *ov, **layers_head; - struct mdp_overlay32 *ov32; + struct mdp_overlay **layers_head; + struct mdp_overlay __user *ov; + struct mdp_overlay32 __user *ov32; struct mdp_overlay_list __user *ovlist; struct mdp_overlay_list32 __user *ovlist32; size_t layers_refs_sz, layers_sz, prepare_sz; diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 751a463edb60bc4a6cc41c2fb89f7718f03b00c0..a470656ea182e4979b91a681e5025a5b1439a601 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -2218,7 +2218,7 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, /* clear CMD DMA and BTA_DONE isr only */ reg_val |= (DSI_INTR_CMD_DMA_DONE | DSI_INTR_BTA_DONE); MIPI_OUTP(ctrl->ctrl_base + 0x0110, reg_val); - mdss_dsi_disable_irq_nosync(ctrl, DSI_CMD_TERM); + mdss_dsi_disable_irq(ctrl, DSI_CMD_TERM); complete(&ctrl->dma_comp); pr_warn("%s: dma tx done but irq not triggered\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 78ee489c28b2983f4449e5871905b73158c35491..e72a315f73f53d39e3bdca9057f1bd09574e1a4e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1713,7 +1713,7 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl, int panel_power_mode); int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg, u32 flags); -int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo); +int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo, bool is_fixed); int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl, struct mdss_mdp_pipe **left_plist, int left_cnt, struct mdss_mdp_pipe **right_plist, int right_cnt); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 4cfb48d6a99b69dc6523b34be90ef1252d2b68c6..4683c7158dcc7c7ab98c18d4a1bddd8230c13547 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -1506,7 +1506,7 @@ static bool is_mdp_prefetch_needed(struct mdss_panel_info *pinfo) * the mdp fetch lines as the last (25 - vbp - vpw) lines of vertical * front porch. */ -int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo) +int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo, bool is_fixed) { int prefetch_avail = 0; int v_total, vfp_start; @@ -1515,7 +1515,11 @@ int mdss_mdp_get_prefetch_lines(struct mdss_panel_info *pinfo) if (!is_mdp_prefetch_needed(pinfo)) return 0; - v_total = mdss_panel_get_vtotal(pinfo); + if (is_fixed) + v_total = mdss_panel_get_vtotal_fixed(pinfo); + else + v_total = mdss_panel_get_vtotal(pinfo); + vfp_start = (pinfo->lcdc.v_back_porch + pinfo->lcdc.v_pulse_width + pinfo->yres); @@ -2559,7 +2563,7 @@ struct mdss_mdp_mixer *mdss_mdp_mixer_alloc( mixer_pool += ctl->mdata->ndspp; nmixers -= ctl->mdata->ndspp; } else if ((ctl->panel_data->panel_info.is_pluggable) && - nmixers_active) { + nmixers_active > 1) { mixer_pool += ctl->mdata->ndspp; nmixers -= ctl->mdata->ndspp; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_debug.c b/drivers/video/fbdev/msm/mdss_mdp_debug.c index bd4ee23ab23c6b178d61343a4b82eed3678ef5ef..e7bd94a616aa46a10dcef6f278c9fcc2806373fb 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_debug.c +++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c @@ -1140,7 +1140,7 @@ static void __dump_mixer(struct seq_file *s, struct mdss_mdp_mixer *mixer, struct mdss_mdp_pipe *pipe; int i, cnt = 0; - if (!mixer) + if (!mixer || !mfd) return; seq_printf(s, "\n%s Mixer #%d res=%dx%d roi[%d, %d, %d, %d] %s\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 947a3fe650eeb9bbeae53033b80e846d14244b29..0ffe89c724c4f1792e7b9fd4a6ac97bd16352d41 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1677,6 +1677,11 @@ static void clk_ctrl_delayed_off_work(struct work_struct *work) /* re-assign to have the correct order in the context */ ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; + if (!sctl) { + pr_err("invalid sctl\n"); + goto exit; + } + sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX]; if (!ctx || !sctx) { pr_err("invalid %s %s\n", @@ -1784,6 +1789,11 @@ static void clk_ctrl_gate_work(struct work_struct *work) /* re-assign to have the correct order in the context */ ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; + if (!sctl) { + pr_err("invalid sctl\n"); + goto exit; + } + sctx = (struct mdss_mdp_cmd_ctx *) sctl->intf_ctx[MASTER_CTX]; if (!ctx || !sctx) { pr_err("%s ERROR invalid %s %s\n", __func__, diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index dba3b0dbc37e87f427f50112daf83193d5f727f5..783755995e3c91644731e84b29fe76d07ed57b9a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -959,6 +959,7 @@ static void mdss_mdp_video_vsync_intr_done(void *arg) struct mdss_mdp_video_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; struct mdss_mdp_vsync_handler *tmp; ktime_t vsync_time; + u32 ctl_flush_bits = 0; if (!ctx) { pr_err("invalid ctx\n"); @@ -970,10 +971,13 @@ static void mdss_mdp_video_vsync_intr_done(void *arg) mdss_debug_frc_add_vsync_sample(ctl, vsync_time); - MDSS_XLOG(ctl->num, ctl->vsync_cnt, ctl->vsync_cnt); + ctl_flush_bits = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH); - pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d\n", - ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time)); + MDSS_XLOG(ctl->num, ctl->vsync_cnt, ctl_flush_bits); + + pr_debug("intr ctl=%d vsync cnt=%u vsync_time=%d ctl_flush=%d\n", + ctl->num, ctl->vsync_cnt, (int)ktime_to_ms(vsync_time), + ctl_flush_bits); ctx->polling_en = false; complete_all(&ctx->vsync_comp); @@ -1716,7 +1720,7 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx, mdata = ctl->mdata; - pinfo->prg_fet = mdss_mdp_get_prefetch_lines(pinfo); + pinfo->prg_fet = mdss_mdp_get_prefetch_lines(pinfo, true); if (!pinfo->prg_fet) { pr_debug("programmable fetch is not needed/supported\n"); @@ -1735,7 +1739,7 @@ static void mdss_mdp_fetch_start_config(struct mdss_mdp_video_ctx *ctx, * Fetch should always be outside the active lines. If the fetching * is programmed within active region, hardware behavior is unknown. */ - v_total = mdss_panel_get_vtotal(pinfo); + v_total = mdss_panel_get_vtotal_fixed(pinfo); h_total = mdss_panel_get_htotal(pinfo, true); fetch_start = (v_total - pinfo->prg_fet) * h_total + 1; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index af6e4ce3e7b266cff96e96d0428320d39566cb80..3de390608179a40f9260ba6067339c6817b156d5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -3760,8 +3760,7 @@ static void dfps_update_panel_params(struct mdss_panel_data *pdata, dfps_update_fps(&pdata->panel_info, new_fps); pdata->panel_info.prg_fet = - mdss_mdp_get_prefetch_lines(&pdata->panel_info); - + mdss_mdp_get_prefetch_lines(&pdata->panel_info, false); } else if (pdata->panel_info.dfps_update == DFPS_IMMEDIATE_PORCH_UPDATE_MODE_HFP) { int add_h_pixels; @@ -6011,6 +6010,7 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) struct mdss_overlay_private *mdp5_data; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_mdp_mixer *mixer; + struct mdss_mdp_pipe *pipe, *tmp; int need_cleanup; int retire_cnt; bool destroy_ctl = false; @@ -6054,6 +6054,13 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) mixer->cursor_enabled = 0; mutex_lock(&mdp5_data->list_lock); + if (!list_empty(&mdp5_data->pipes_used)) { + list_for_each_entry_safe( + pipe, tmp, &mdp5_data->pipes_used, list) { + pipe->file = NULL; + list_move(&pipe->list, &mdp5_data->pipes_cleanup); + } + } need_cleanup = !list_empty(&mdp5_data->pipes_cleanup); mutex_unlock(&mdp5_data->list_lock); mutex_unlock(&mdp5_data->ov_lock); diff --git a/drivers/video/fbdev/msm/mdss_panel.c b/drivers/video/fbdev/msm/mdss_panel.c index de69d632b6b0d8238405abce5255cfc73b4c80dd..4e61fd85b7a013e63f1ab3e543fda73e8103ed51 100644 --- a/drivers/video/fbdev/msm/mdss_panel.c +++ b/drivers/video/fbdev/msm/mdss_panel.c @@ -633,6 +633,7 @@ void mdss_panel_info_from_timing(struct mdss_panel_timing *pt, pinfo->yres = pt->yres; pinfo->lcdc.v_front_porch = pt->v_front_porch; + pinfo->lcdc.v_front_porch_fixed = pt->v_front_porch; pinfo->lcdc.v_back_porch = pt->v_back_porch; pinfo->lcdc.v_pulse_width = pt->v_pulse_width; diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index c66d5aba790a84c41aa1506e460d638ec4cde736..be6d44f0196aab5d2c629867a39f735c96dedabd 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -289,6 +289,7 @@ struct lcd_panel_info { u32 h_pulse_width; u32 v_back_porch; u32 v_front_porch; + u32 v_front_porch_fixed; u32 v_pulse_width; u32 border_clr; u32 underflow_clr; @@ -926,6 +927,23 @@ static inline u32 mdss_panel_get_framerate(struct mdss_panel_info *panel_info, return frame_rate; } +/* + * mdss_panel_get_vtotal_fixed() - return panel device tree vertical height + * @pinfo: Pointer to panel info containing all panel information + * + * Returns the total height as defined in panel device tree including any + * blanking regions which are not visible to user but used to calculate + * panel clock. + */ +static inline int mdss_panel_get_vtotal_fixed(struct mdss_panel_info *pinfo) +{ + return pinfo->yres + pinfo->lcdc.v_back_porch + + pinfo->lcdc.v_front_porch_fixed + + pinfo->lcdc.v_pulse_width+ + pinfo->lcdc.border_top + + pinfo->lcdc.border_bottom; +} + /* * mdss_panel_get_vtotal() - return panel vertical height * @pinfo: Pointer to panel info containing all panel information diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c index 98af9e02959b43d87758903dfd72a81641261785..9fe0d0bcdf624a7d62b7d08cf1bce03e8d23cc13 100644 --- a/drivers/video/fbdev/uvesafb.c +++ b/drivers/video/fbdev/uvesafb.c @@ -1059,7 +1059,8 @@ static int uvesafb_setcmap(struct fb_cmap *cmap, struct fb_info *info) info->cmap.len || cmap->start < info->cmap.start) return -EINVAL; - entries = kmalloc(sizeof(*entries) * cmap->len, GFP_KERNEL); + entries = kmalloc_array(cmap->len, sizeof(*entries), + GFP_KERNEL); if (!entries) return -ENOMEM; diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c index a4621757a47f5184d96b99fda56c20f11562425d..dacb5919970c5346492afc90e21bd8621737ecab 100644 --- a/drivers/w1/masters/mxc_w1.c +++ b/drivers/w1/masters/mxc_w1.c @@ -113,6 +113,10 @@ static int mxc_w1_probe(struct platform_device *pdev) if (IS_ERR(mdev->clk)) return PTR_ERR(mdev->clk); + err = clk_prepare_enable(mdev->clk); + if (err) + return err; + clkrate = clk_get_rate(mdev->clk); if (clkrate < 10000000) dev_warn(&pdev->dev, @@ -126,12 +130,10 @@ static int mxc_w1_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdev->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mdev->regs)) - return PTR_ERR(mdev->regs); - - err = clk_prepare_enable(mdev->clk); - if (err) - return err; + if (IS_ERR(mdev->regs)) { + err = PTR_ERR(mdev->regs); + goto out_disable_clk; + } /* Software reset 1-Wire module */ writeb(MXC_W1_RESET_RST, mdev->regs + MXC_W1_RESET); @@ -147,8 +149,12 @@ static int mxc_w1_probe(struct platform_device *pdev) err = w1_add_master_device(&mdev->bus_master); if (err) - clk_disable_unprepare(mdev->clk); + goto out_disable_clk; + return 0; + +out_disable_clk: + clk_disable_unprepare(mdev->clk); return err; } diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index ab0931e7a9bb1ded5d9d3d9d019ff4a2e76b5042..aa458f2fced1ac9c6b79067e9f379084b80d6a0d 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -741,7 +741,7 @@ int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) /* slave modules need to be loaded in a context with unlocked mutex */ mutex_unlock(&dev->mutex); - request_module("w1-family-0x%02x", rn->family); + request_module("w1-family-0x%02X", rn->family); mutex_lock(&dev->mutex); spin_lock(&w1_flock); diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 6d3b32ccc2c42243cc4111bf5f91c337b1e5a331..1435d8c58ea0bea708e2e05f61666caa3d14fe9a 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -637,8 +637,6 @@ static void __unbind_from_irq(unsigned int irq) xen_irq_info_cleanup(info); } - BUG_ON(info_for_irq(irq)->type == IRQT_UNBOUND); - xen_free_irq(irq); } diff --git a/fs/aio.c b/fs/aio.c index 42d8c09311d1879bf7c6501ed9398008a6938a78..b1170a7affe2a163ac1fefa5f2e8576d7c3d1479 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -636,9 +636,8 @@ static void free_ioctx_users(struct percpu_ref *ref) while (!list_empty(&ctx->active_reqs)) { req = list_first_entry(&ctx->active_reqs, struct aio_kiocb, ki_list); - - list_del_init(&req->ki_list); kiocb_cancel(req); + list_del_init(&req->ki_list); } spin_unlock_irq(&ctx->ctx_lock); diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 9b4688ab1d8e0f1e00b118912ec7a78def04818f..f842261ce97388536104b36e80da6a25016c7f1a 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -384,8 +384,13 @@ static Node *create_entry(const char __user *buffer, size_t count) s = strchr(p, del); if (!s) goto einval; - *s++ = '\0'; - e->offset = simple_strtoul(p, &p, 10); + *s = '\0'; + if (p != s) { + int r = kstrtoint(p, 10, &e->offset); + if (r != 0 || e->offset < 0) + goto einval; + } + p = s; if (*p++) goto einval; pr_debug("register: offset: %#x\n", e->offset); @@ -425,7 +430,8 @@ static Node *create_entry(const char __user *buffer, size_t count) if (e->mask && string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size) goto einval; - if (e->size + e->offset > BINPRM_BUF_SIZE) + if (e->size > BINPRM_BUF_SIZE || + BINPRM_BUF_SIZE - e->size < e->offset) goto einval; pr_debug("register: magic/mask length: %i\n", e->size); if (USE_DEBUG) { diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 9557a313b831f450e35d43397a889888d980d26d..8dc70340670f7800eae9b9864b2f3dc0924340b5 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -59,7 +59,8 @@ BTRFS_HEADER_FLAG_RELOC |\ BTRFS_SUPER_FLAG_ERROR |\ BTRFS_SUPER_FLAG_SEEDING |\ - BTRFS_SUPER_FLAG_METADUMP) + BTRFS_SUPER_FLAG_METADUMP |\ + BTRFS_SUPER_FLAG_METADUMP_V2) static const struct extent_io_ops btree_extent_io_ops; static void end_workqueue_fn(struct btrfs_work *work); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f073de65e8188389362f3bdb238b533a3511e7ac..bd036557c6bc49bb8e75e26936e493594d24456a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1230,6 +1230,8 @@ static noinline int csum_exist_in_range(struct btrfs_root *root, list_del(&sums->list); kfree(sums); } + if (ret < 0) + return ret; return 1; } @@ -1381,10 +1383,23 @@ static noinline int run_delalloc_nocow(struct inode *inode, goto out_check; if (btrfs_extent_readonly(root, disk_bytenr)) goto out_check; - if (btrfs_cross_ref_exist(trans, root, ino, + ret = btrfs_cross_ref_exist(trans, root, ino, found_key.offset - - extent_offset, disk_bytenr)) + extent_offset, disk_bytenr); + if (ret) { + /* + * ret could be -EIO if the above fails to read + * metadata. + */ + if (ret < 0) { + if (cow_start != (u64)-1) + cur_offset = cow_start; + goto error; + } + + WARN_ON_ONCE(nolock); goto out_check; + } disk_bytenr += extent_offset; disk_bytenr += cur_offset - found_key.offset; num_bytes = min(end + 1, extent_end) - cur_offset; @@ -1402,8 +1417,20 @@ static noinline int run_delalloc_nocow(struct inode *inode, * this ensure that csum for a given extent are * either valid or do not exist. */ - if (csum_exist_in_range(root, disk_bytenr, num_bytes)) + ret = csum_exist_in_range(root, disk_bytenr, num_bytes); + if (ret) { + /* + * ret could be -EIO if the above fails to read + * metadata. + */ + if (ret < 0) { + if (cow_start != (u64)-1) + cur_offset = cow_start; + goto error; + } + WARN_ON_ONCE(nolock); goto out_check; + } if (!btrfs_inc_nocow_writers(root->fs_info, disk_bytenr)) goto out_check; @@ -9561,6 +9588,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, u64 new_idx = 0; u64 root_objectid; int ret; + int ret2; bool root_log_pinned = false; bool dest_log_pinned = false; @@ -9751,7 +9779,8 @@ static int btrfs_rename_exchange(struct inode *old_dir, dest_log_pinned = false; } } - ret = btrfs_end_transaction(trans, root); + ret2 = btrfs_end_transaction(trans, root); + ret = ret ? ret : ret2; out_notrans: if (new_ino == BTRFS_FIRST_FREE_OBJECTID) up_read(&dest->fs_info->subvol_sem); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index d3dd631432eb7fbafb73466ca5558209b232f226..cbf512b64597fe64eb11dcefa334f6cf73364d80 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -2708,8 +2708,10 @@ static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) } /* Check for compatibility reject unknown flags */ - if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) - return -EOPNOTSUPP; + if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) { + ret = -EOPNOTSUPP; + goto out; + } if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, 1)) { @@ -3887,11 +3889,6 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, src->i_sb != inode->i_sb) return -EXDEV; - /* don't make the dst file partly checksummed */ - if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != - (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) - return -EINVAL; - if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) return -EISDIR; @@ -3901,6 +3898,13 @@ static noinline int btrfs_clone_files(struct file *file, struct file *file_src, inode_lock(src); } + /* don't make the dst file partly checksummed */ + if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != + (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { + ret = -EINVAL; + goto out_unlock; + } + /* determine range to clone */ ret = -EINVAL; if (off + len > src->i_size || off + len < off) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index fffb9ab8526eb43f662ba0e943112742798c841d..16c0585cd81c8162144b2cff5c25e2d73062a9f7 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -2519,7 +2519,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, have_csum = scrub_find_csum(sctx, logical, csum); if (have_csum == 0) ++sctx->stat.no_csum; - if (sctx->is_dev_replace && !have_csum) { + if (0 && sctx->is_dev_replace && !have_csum) { ret = copy_nocow_pages(sctx, logical, l, mirror_num, physical_for_dev_replace); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d5722289489298e3e04d9519d975639202d5625b..8407b07428a69833e0cfad1fe02a28542a0e2ef5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -150,8 +150,14 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command) * greater than cifs socket timeout which is 7 seconds */ while (server->tcpStatus == CifsNeedReconnect) { - wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus != CifsNeedReconnect), 10 * HZ); + rc = wait_event_interruptible_timeout(server->response_q, + (server->tcpStatus != CifsNeedReconnect), + 10 * HZ); + if (rc < 0) { + cifs_dbg(FYI, "%s: aborting reconnect due to a received" + " signal by the process\n", __func__); + return -ERESTARTSYS; + } /* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 44b7ccbe4b082f82f0d800555e8b890f6114cc05..4ded64b8b43b5f65bba2e75d08c58d56693732da 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -155,7 +155,7 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ , static int smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) { - int rc = 0; + int rc; struct nls_table *nls_codepage; struct cifs_ses *ses; struct TCP_Server_Info *server; @@ -166,10 +166,10 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) * for those three - in the calling routine. */ if (tcon == NULL) - return rc; + return 0; if (smb2_command == SMB2_TREE_CONNECT) - return rc; + return 0; if (tcon->tidStatus == CifsExiting) { /* @@ -212,8 +212,14 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) return -EAGAIN; } - wait_event_interruptible_timeout(server->response_q, - (server->tcpStatus != CifsNeedReconnect), 10 * HZ); + rc = wait_event_interruptible_timeout(server->response_q, + (server->tcpStatus != CifsNeedReconnect), + 10 * HZ); + if (rc < 0) { + cifs_dbg(FYI, "%s: aborting reconnect due to a received" + " signal by the process\n", __func__); + return -ERESTARTSYS; + } /* are we still trying to reconnect? */ if (server->tcpStatus != CifsNeedReconnect) @@ -231,7 +237,7 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon) } if (!tcon->ses->need_reconnect && !tcon->need_reconnect) - return rc; + return 0; nls_codepage = load_nls_default(); @@ -1004,6 +1010,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses, sess_data->ses = ses; sess_data->buf0_type = CIFS_NO_BUFFER; sess_data->nls_cp = (struct nls_table *) nls_cp; + sess_data->previous_session = ses->Suid; while (sess_data->func) sess_data->func(sess_data); diff --git a/fs/dcache.c b/fs/dcache.c index 5ff9b417f836f67d286fc1164c6bdeff1fb5cc1b..3c8c1a1b7d552810a7a607140922010215b051c7 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1412,7 +1412,7 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) goto out; if (dentry->d_flags & DCACHE_SHRINK_LIST) { - data->found++; + goto out; } else { if (dentry->d_flags & DCACHE_LRU_LIST) d_lru_del(dentry); diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 6776f4aa3d12e756e03f8e6ddb3e727ffd724639..ad13f07cf0d371ae4a3af76741ca88ea505aff82 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -183,7 +183,6 @@ static int ext4_init_block_bitmap(struct super_block *sb, unsigned int bit, bit_max; struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t start, tmp; - int flex_bg = 0; struct ext4_group_info *grp; J_ASSERT_BH(bh, buffer_locked(bh)); @@ -216,22 +215,19 @@ static int ext4_init_block_bitmap(struct super_block *sb, start = ext4_group_first_block_no(sb, block_group); - if (ext4_has_feature_flex_bg(sb)) - flex_bg = 1; - /* Set bits for block and inode bitmaps, and inode table */ tmp = ext4_block_bitmap(sb, gdp); - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + if (ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); tmp = ext4_inode_bitmap(sb, gdp); - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + if (ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); tmp = ext4_inode_table(sb, gdp); for (; tmp < ext4_inode_table(sb, gdp) + sbi->s_itb_per_group; tmp++) { - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) + if (ext4_block_in_group(sb, tmp, block_group)) ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); } @@ -454,7 +450,16 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) goto verify; } ext4_lock_group(sb, block_group); - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { + if (block_group == 0) { + ext4_unlock_group(sb, block_group); + unlock_buffer(bh); + ext4_error(sb, "Block bitmap for bg 0 marked " + "uninitialized"); + err = -EFSCORRUPTED; + goto out; + } err = ext4_init_block_bitmap(sb, bh, block_group, desc); set_bitmap_uptodate(bh); set_buffer_uptodate(bh); diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index c17539153099b090385412acaaaa10b6103590ba..064753880e995c1312baa77c0bff02422e4967bd 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1533,11 +1533,6 @@ static inline struct timespec ext4_current_time(struct inode *inode) static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) { return ino == EXT4_ROOT_INO || - ino == EXT4_USR_QUOTA_INO || - ino == EXT4_GRP_QUOTA_INO || - ino == EXT4_BOOT_LOADER_INO || - ino == EXT4_JOURNAL_INO || - ino == EXT4_RESIZE_INO || (ino >= EXT4_FIRST_INO(sb) && ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)); } diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 8ecf84b8f5a14a9159a53c69a0f170ec406e1bd7..a284fb28944b5d9f2699378d14cdad4a1c477932 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h @@ -103,6 +103,7 @@ struct ext4_extent_header { }; #define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) +#define EXT4_MAX_EXTENT_DEPTH 5 #define EXT4_EXTENT_TAIL_OFFSET(hdr) \ (sizeof(struct ext4_extent_header) + \ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index fb9ae76d927a10cc9246a7a1bd32947cb0001df9..054c38569e0d3a21d40f12ffaac5d13e1d8ad58e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -881,6 +881,12 @@ ext4_find_extent(struct inode *inode, ext4_lblk_t block, eh = ext_inode_hdr(inode); depth = ext_depth(inode); + if (depth < 0 || depth > EXT4_MAX_EXTENT_DEPTH) { + EXT4_ERROR_INODE(inode, "inode has invalid extent depth: %d", + depth); + ret = -EFSCORRUPTED; + goto err; + } if (path) { ext4_ext_drop_refs(path); diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 1ee26da314f2914b8f1d8cbc2e93521b08b834d2..fec1eaa611edec427171fc62238c2a5ba67bbd54 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -152,7 +152,16 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) } ext4_lock_group(sb, block_group); - if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) { + if (block_group == 0) { + ext4_unlock_group(sb, block_group); + unlock_buffer(bh); + ext4_error(sb, "Inode bitmap for bg 0 marked " + "uninitialized"); + err = -EFSCORRUPTED; + goto out; + } memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, bh->b_data); @@ -926,7 +935,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, /* recheck and clear flag under lock if we still need to */ ext4_lock_group(sb, group); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_group_clusters_set(sb, gdp, ext4_free_clusters_after_init(sb, group, gdp)); diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index bc15c2c17633079a54de855baf1272b0124f19eb..58229c1b4a3d752c26139621c9538db9ef9613d8 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -560,10 +560,16 @@ int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, unsigned epb = inode->i_sb->s_blocksize / sizeof(u32); int i; - /* Count number blocks in a subtree under 'partial' */ - count = 1; - for (i = 0; partial + i != chain + depth - 1; i++) - count *= epb; + /* + * Count number blocks in a subtree under 'partial'. At each + * level we count number of complete empty subtrees beyond + * current offset and then descend into the subtree only + * partially beyond current offset. + */ + count = 0; + for (i = partial - chain + 1; i < depth; i++) + count = count * epb + (epb - offsets[i] - 1); + count++; /* Fill in size of a hole we found */ map->m_pblk = 0; map->m_len = min_t(unsigned int, map->m_len, count); diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 4d78b932c320a2e7254ceeb9efe1fe24b604199e..6fde3218d894432b439c14125e342a96d6b3e23c 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c @@ -435,6 +435,7 @@ static int ext4_destroy_inline_data_nolock(handle_t *handle, memset((void *)ext4_raw_inode(&is.iloc)->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + memset(ei->i_data, 0, EXT4_MIN_INLINE_DATA_SIZE); if (ext4_has_feature_extents(inode->i_sb)) { if (S_ISDIR(inode->i_mode) || diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ecee29a3cf8248652758806f4b603491c664ceb0..af9b5f60f93002b238354b0735303282bb344e21 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -379,9 +379,9 @@ static int __check_block_validity(struct inode *inode, const char *func, if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk, map->m_len)) { ext4_error_inode(inode, func, line, map->m_pblk, - "lblock %lu mapped to illegal pblock " + "lblock %lu mapped to illegal pblock %llu " "(length %d)", (unsigned long) map->m_lblk, - map->m_len); + map->m_pblk, map->m_len); return -EFSCORRUPTED; } return 0; @@ -4101,28 +4101,28 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) EXT4_BLOCK_SIZE_BITS(sb); stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); - /* If there are no blocks to remove, return now */ - if (first_block >= stop_block) - goto out_stop; + /* If there are blocks to remove, do it */ + if (stop_block > first_block) { - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); + down_write(&EXT4_I(inode)->i_data_sem); + ext4_discard_preallocations(inode); - ret = ext4_es_remove_extent(inode, first_block, - stop_block - first_block); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } + ret = ext4_es_remove_extent(inode, first_block, + stop_block - first_block); + if (ret) { + up_write(&EXT4_I(inode)->i_data_sem); + goto out_stop; + } - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ret = ext4_ext_remove_space(inode, first_block, - stop_block - 1); - else - ret = ext4_ind_remove_space(handle, inode, first_block, - stop_block); + if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) + ret = ext4_ext_remove_space(inode, first_block, + stop_block - 1); + else + ret = ext4_ind_remove_space(handle, inode, first_block, + stop_block); - up_write(&EXT4_I(inode)->i_data_sem); + up_write(&EXT4_I(inode)->i_data_sem); + } if (IS_SYNC(inode)) ext4_handle_sync(handle); @@ -4311,7 +4311,8 @@ static int __ext4_get_inode_loc(struct inode *inode, int inodes_per_block, inode_offset; iloc->bh = NULL; - if (!ext4_valid_inum(sb, inode->i_ino)) + if (inode->i_ino < EXT4_ROOT_INO || + inode->i_ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) return -EFSCORRUPTED; iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb); diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 4beca0683920f9bbd44ecd1052eecb95f09ed6f1..0fcc33622f9adcad758da2849259f1a1c0f54cbb 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2444,7 +2444,8 @@ int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, * initialize bb_free to be able to skip * empty groups without initialization */ - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { meta_group_info[i]->bb_free = ext4_free_clusters_after_init(sb, group, desc); } else { @@ -2970,7 +2971,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, #endif ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, ac->ac_b_ex.fe_len); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { + if (ext4_has_group_desc_csum(sb) && + (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_group_clusters_set(sb, gdp, ext4_free_clusters_after_init(sb, diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index 95bf4665415367730c25fb7e77d4b3edf195ec2d..eb720d9e2953949dbb6526dd9200d419ff2a8983 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -1903,7 +1903,7 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) return 0; n_group = ext4_get_group_number(sb, n_blocks_count - 1); - if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { + if (n_group >= (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { ext4_warning(sb, "resize would cause inodes_count overflow"); return -EINVAL; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 23c571662f0837b32b0c417e5b1d85f14424b380..2436c76a36690767935e615e3ab88888e7fb4115 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2247,6 +2247,7 @@ static int ext4_check_descriptors(struct super_block *sb, struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext4_fsblk_t last_block; + ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0) + 1; ext4_fsblk_t block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; @@ -2279,6 +2280,14 @@ static int ext4_check_descriptors(struct super_block *sb, if (!(sb->s_flags & MS_RDONLY)) return 0; } + if (block_bitmap >= sb_block + 1 && + block_bitmap <= last_bg_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Block bitmap for group %u overlaps " + "block group descriptors", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } if (block_bitmap < first_block || block_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Block bitmap for group %u not in group " @@ -2293,6 +2302,14 @@ static int ext4_check_descriptors(struct super_block *sb, if (!(sb->s_flags & MS_RDONLY)) return 0; } + if (inode_bitmap >= sb_block + 1 && + inode_bitmap <= last_bg_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Inode bitmap for group %u overlaps " + "block group descriptors", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } if (inode_bitmap < first_block || inode_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Inode bitmap for group %u not in group " @@ -2307,6 +2324,14 @@ static int ext4_check_descriptors(struct super_block *sb, if (!(sb->s_flags & MS_RDONLY)) return 0; } + if (inode_table >= sb_block + 1 && + inode_table <= last_bg_block) { + ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " + "Inode table for group %u overlaps " + "block group descriptors", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; + } if (inode_table < first_block || inode_table + sbi->s_itb_per_group - 1 > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " @@ -3014,13 +3039,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb) ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count; struct ext4_group_desc *gdp = NULL; + if (!ext4_has_group_desc_csum(sb)) + return ngroups; + for (group = 0; group < ngroups; group++) { gdp = ext4_get_group_desc(sb, group, NULL); if (!gdp) continue; - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)) + continue; + if (group != 0) break; + ext4_error(sb, "Inode table for bg 0 marked as " + "needing zeroing"); + if (sb->s_flags & MS_RDONLY) + return ngroups; } return group; @@ -3638,6 +3672,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) le32_to_cpu(es->s_log_block_size)); goto failed_mount; } + if (le32_to_cpu(es->s_log_cluster_size) > + (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { + ext4_msg(sb, KERN_ERR, + "Invalid log cluster size: %u", + le32_to_cpu(es->s_log_cluster_size)); + goto failed_mount; + } if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { ext4_msg(sb, KERN_ERR, @@ -3695,6 +3736,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } else { sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); + if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) { + ext4_msg(sb, KERN_ERR, "invalid first ino: %u", + sbi->s_first_ino); + goto failed_mount; + } if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || (!is_power_of_2(sbi->s_inode_size)) || (sbi->s_inode_size > blocksize)) { @@ -3771,13 +3817,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) "block size (%d)", clustersize, blocksize); goto failed_mount; } - if (le32_to_cpu(es->s_log_cluster_size) > - (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { - ext4_msg(sb, KERN_ERR, - "Invalid log cluster size: %u", - le32_to_cpu(es->s_log_cluster_size)); - goto failed_mount; - } sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - le32_to_cpu(es->s_log_block_size); sbi->s_clusters_per_group = @@ -3798,10 +3837,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } } else { if (clustersize != blocksize) { - ext4_warning(sb, "fragment/cluster size (%d) != " - "block size (%d)", clustersize, - blocksize); - clustersize = blocksize; + ext4_msg(sb, KERN_ERR, + "fragment/cluster size (%d) != " + "block size (%d)", clustersize, blocksize); + goto failed_mount; } if (sbi->s_blocks_per_group > blocksize * 8) { ext4_msg(sb, KERN_ERR, @@ -3855,6 +3894,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ext4_blocks_count(es)); goto failed_mount; } + if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) && + (sbi->s_cluster_ratio == 1)) { + ext4_msg(sb, KERN_WARNING, "bad geometry: first data " + "block is 0 with a 1k block and cluster size"); + goto failed_mount; + } + blocks_count = (ext4_blocks_count(es) - le32_to_cpu(es->s_first_data_block) + EXT4_BLOCKS_PER_GROUP(sb) - 1); @@ -3890,6 +3936,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) ret = -ENOMEM; goto failed_mount; } + if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) != + le32_to_cpu(es->s_inodes_count)) { + ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu", + le32_to_cpu(es->s_inodes_count), + ((u64)sbi->s_groups_count * sbi->s_inodes_per_group)); + ret = -EINVAL; + goto failed_mount; + } bgl_lock_init(sbi->s_blockgroup_lock); @@ -4588,6 +4642,14 @@ static int ext4_commit_super(struct super_block *sb, int sync) if (!sbh || block_device_ejected(sb)) return error; + + /* + * The superblock bh should be mapped, but it might not be if the + * device was hot-removed. Not much we can do but fail the I/O. + */ + if (!buffer_mapped(sbh)) + return error; + /* * If the file system is mounted read-only, don't update the * superblock write time. This avoids updating the superblock diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 98fe1edb0e6d281f88e8077bc1ab0bb80b93d77a..f04781b45985f2160bbef0a7b80b40bbb897fff2 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2439,9 +2439,18 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) __init_discard_policy(sbi, &dpolicy, DPOLICY_FSTRIM, cpc.trim_minlen); __issue_discard_cmd_range(sbi, &dpolicy, start_block, end_block); - trimmed = __wait_discard_cmd_range(sbi, &dpolicy, + + /* + * We filed discard candidates, but actually we don't need to wait for + * all of them, since they'll be issued in idle time along with runtime + * discard option. User configuration looks like using runtime discard + * or periodic fstrim instead of it. + */ + if (!test_opt(sbi, DISCARD)) { + trimmed = __wait_discard_cmd_range(sbi, &dpolicy, start_block, end_block); - range->len = F2FS_BLK_TO_BYTES(trimmed); + range->len = F2FS_BLK_TO_BYTES(trimmed); + } out: return err; } diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 6e22748b0704c509edad6a0e93d0a6626601137b..e25c40c10f4fa8483093c14f7d47260bf244bef5 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -211,10 +211,11 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, if (!dentry) return NULL; - fc->ctl_dentry[fc->ctl_ndents++] = dentry; inode = new_inode(fuse_control_sb); - if (!inode) + if (!inode) { + dput(dentry); return NULL; + } inode->i_ino = get_next_ino(); inode->i_mode = mode; @@ -228,6 +229,9 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, set_nlink(inode, nlink); inode->i_private = fc; d_add(dentry, inode); + + fc->ctl_dentry[fc->ctl_ndents++] = dentry; + return dentry; } @@ -284,7 +288,10 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc) for (i = fc->ctl_ndents - 1; i >= 0; i--) { struct dentry *dentry = fc->ctl_dentry[i]; d_inode(dentry)->i_private = NULL; - d_drop(dentry); + if (!i) { + /* Get rid of submounts: */ + d_invalidate(dentry); + } dput(dentry); } drop_nlink(d_inode(fuse_control_sb->s_root)); diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 169330823c6b687fede2bc37070375561fcdc172..5dcba9ecdd0dbf05ce179633815c645f14e14026 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1682,8 +1682,19 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr, return err; if (attr->ia_valid & ATTR_OPEN) { - if (fc->atomic_o_trunc) + /* This is coming from open(..., ... | O_TRUNC); */ + WARN_ON(!(attr->ia_valid & ATTR_SIZE)); + WARN_ON(attr->ia_size != 0); + if (fc->atomic_o_trunc) { + /* + * No need to send request to userspace, since actual + * truncation has already been done by OPEN. But still + * need to truncate page cache. + */ + i_size_write(inode, 0); + truncate_pagecache(inode, 0); return 0; + } file = NULL; } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 8aa98b185d7ba73c1d4e004424262ee00afd62f8..c506fa91b1dd859c618781c4c1ab63f89e72a1b8 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1190,6 +1190,7 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err_put_conn: fuse_bdi_destroy(fc); fuse_conn_put(fc); + sb->s_fs_info = NULL; err_fput: fput(file); err: diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 9e9e0936138b74b4e4c787cb84aa83079b313810..b320c1ba7fdce8441569e058ce3307e27a46c317 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1353,6 +1353,13 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) if (jh->b_transaction == transaction && jh->b_jlist != BJ_Metadata) { jbd_lock_bh_state(bh); + if (jh->b_transaction == transaction && + jh->b_jlist != BJ_Metadata) + pr_err("JBD2: assertion failure: h_type=%u " + "h_line_no=%u block_no=%llu jlist=%u\n", + handle->h_type, handle->h_line_no, + (unsigned long long) bh->b_blocknr, + jh->b_jlist); J_ASSERT_JH(jh, jh->b_transaction != transaction || jh->b_jlist == BJ_Metadata); jbd_unlock_bh_state(bh); @@ -1372,11 +1379,11 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) * of the transaction. This needs to be done * once a transaction -bzzz */ - jh->b_modified = 1; if (handle->h_buffer_credits <= 0) { ret = -ENOSPC; goto out_unlock_bh; } + jh->b_modified = 1; handle->h_buffer_credits--; } diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index e9aa235e9d10197d8b138f1d0e657dd6449c578f..2e7ebd9d716838e1a91915bc74f67f20cd58c2e8 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -402,11 +402,8 @@ validate_seqid(const struct nfs4_slot_table *tbl, const struct nfs4_slot *slot, return htonl(NFS4ERR_SEQ_FALSE_RETRY); } - /* Wraparound */ - if (unlikely(slot->seq_nr == 0xFFFFFFFFU)) { - if (args->csa_sequenceid == 1) - return htonl(NFS4_OK); - } else if (likely(args->csa_sequenceid == slot->seq_nr + 1)) + /* Note: wraparound relies on seq_nr being of type u32 */ + if (likely(args->csa_sequenceid == slot->seq_nr + 1)) return htonl(NFS4_OK); /* Misordered request */ diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c index eaac878c1463f5a222a091a094d17f232ffc2407..b5f02f1560880271e96f114e845a85dae4c46551 100644 --- a/fs/nfs/nfs4idmap.c +++ b/fs/nfs/nfs4idmap.c @@ -343,7 +343,7 @@ static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, int id_len; ssize_t ret; - id_len = snprintf(id_str, sizeof(id_str), "%u", id); + id_len = nfs_map_numeric_to_string(id, id_str, sizeof(id_str)); ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap); if (ret < 0) return -EINVAL; @@ -626,7 +626,8 @@ static int nfs_idmap_read_and_verify_message(struct idmap_msg *im, if (strcmp(upcall->im_name, im->im_name) != 0) break; /* Note: here we store the NUL terminator too */ - len = sprintf(id_str, "%d", im->im_id) + 1; + len = 1 + nfs_map_numeric_to_string(im->im_id, id_str, + sizeof(id_str)); ret = nfs_idmap_instantiate(key, authkey, id_str, len); break; case IDMAP_CONV_IDTONAME: diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2c4f7a22e128dcd4a6c0f04542575579e0d6edf4..bdbd9e6d1ace337aef182c551245f016cd662459 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3638,7 +3638,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 nfserr = nfserr_resource; goto err_no_verf; } - maxcount = min_t(u32, readdir->rd_maxcount, INT_MAX); + maxcount = svc_max_payload(resp->rqstp); + maxcount = min_t(u32, readdir->rd_maxcount, maxcount); /* * Note the rfc defines rd_maxcount as the size of the * READDIR4resok structure, which includes the verifier above @@ -3652,7 +3653,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 /* RFC 3530 14.2.24 allows us to ignore dircount when it's 0: */ if (!readdir->rd_dircount) - readdir->rd_dircount = INT_MAX; + readdir->rd_dircount = svc_max_payload(resp->rqstp); readdir->xdr = xdr; readdir->rd_maxcount = maxcount; diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c index 561497a7a247fc9307e0ff60b916b30325eb7cb8..5fe458628e00b4ccc9090cd56ca64de87494d88f 100644 --- a/fs/orangefs/namei.c +++ b/fs/orangefs/namei.c @@ -312,6 +312,13 @@ static int orangefs_symlink(struct inode *dir, ret = PTR_ERR(inode); goto out; } + /* + * This is necessary because orangefs_inode_getattr will not + * re-read symlink size as it is impossible for it to change. + * Invalidating the cache does not help. orangefs_new_inode + * does not set the correct size (it does not know symname). + */ + inode->i_size = strlen(symname); gossip_debug(GOSSIP_NAME_DEBUG, "Assigned symlink inode new number of %pU\n", diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c index fafc09c447b4ffb64430504eda59ca402c2744b1..30d4db260a2ee80bc518c9914904f82ef9b8ce3e 100644 --- a/fs/sdcardfs/inode.c +++ b/fs/sdcardfs/inode.c @@ -270,6 +270,7 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct dentry *lower_dentry; struct vfsmount *lower_mnt; struct dentry *lower_parent_dentry = NULL; + struct dentry *parent_dentry = NULL; struct path lower_path; struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb); const struct cred *saved_cred = NULL; @@ -289,11 +290,14 @@ static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred, SDCARDFS_I(dir)); /* check disk space */ - if (!check_min_free_space(dentry, 0, 1)) { + parent_dentry = dget_parent(dentry); + if (!check_min_free_space(parent_dentry, 0, 1)) { pr_err("sdcardfs: No minimum free space.\n"); err = -ENOSPC; + dput(parent_dentry); goto out_revert; } + dput(parent_dentry); /* the lower_dentry is negative here */ sdcardfs_get_lower_path(dentry, &lower_path); diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 7d764e3b6c795d74598cbe531a201474f8bc611a..504658fd0d08ff878f260e5a3a71b477546bb395 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -1265,7 +1265,7 @@ static int recomp_data_node(const struct ubifs_info *c, int err, len, compr_type, out_len; out_len = le32_to_cpu(dn->size); - buf = kmalloc(out_len * WORST_COMPR_FACTOR, GFP_NOFS); + buf = kmalloc_array(out_len, WORST_COMPR_FACTOR, GFP_NOFS); if (!buf) return -ENOMEM; diff --git a/fs/udf/directory.c b/fs/udf/directory.c index 988d5352bdb866e6108a03d3798492c206b034f9..48ef184929ecf8a70b76658bb7a097ad43fa181f 100644 --- a/fs/udf/directory.c +++ b/fs/udf/directory.c @@ -150,6 +150,9 @@ struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos, sizeof(struct fileIdentDesc)); } } + /* Got last entry outside of dir size - fs is corrupted! */ + if (*nf_pos > dir->i_size) + return NULL; return fi; } diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index c3702cda010afd12b77ea2c1cf2f43864594e1e6..e567551402a65785a74967c6945f6db155c23d79 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -2034,6 +2034,93 @@ xfs_alloc_space_available( return true; } +/* + * Check the agfl fields of the agf for inconsistency or corruption. The purpose + * is to detect an agfl header padding mismatch between current and early v5 + * kernels. This problem manifests as a 1-slot size difference between the + * on-disk flcount and the active [first, last] range of a wrapped agfl. This + * may also catch variants of agfl count corruption unrelated to padding. Either + * way, we'll reset the agfl and warn the user. + * + * Return true if a reset is required before the agfl can be used, false + * otherwise. + */ +static bool +xfs_agfl_needs_reset( + struct xfs_mount *mp, + struct xfs_agf *agf) +{ + uint32_t f = be32_to_cpu(agf->agf_flfirst); + uint32_t l = be32_to_cpu(agf->agf_fllast); + uint32_t c = be32_to_cpu(agf->agf_flcount); + int agfl_size = XFS_AGFL_SIZE(mp); + int active; + + /* no agfl header on v4 supers */ + if (!xfs_sb_version_hascrc(&mp->m_sb)) + return false; + + /* + * The agf read verifier catches severe corruption of these fields. + * Repeat some sanity checks to cover a packed -> unpacked mismatch if + * the verifier allows it. + */ + if (f >= agfl_size || l >= agfl_size) + return true; + if (c > agfl_size) + return true; + + /* + * Check consistency between the on-disk count and the active range. An + * agfl padding mismatch manifests as an inconsistent flcount. + */ + if (c && l >= f) + active = l - f + 1; + else if (c) + active = agfl_size - f + l + 1; + else + active = 0; + + return active != c; +} + +/* + * Reset the agfl to an empty state. Ignore/drop any existing blocks since the + * agfl content cannot be trusted. Warn the user that a repair is required to + * recover leaked blocks. + * + * The purpose of this mechanism is to handle filesystems affected by the agfl + * header padding mismatch problem. A reset keeps the filesystem online with a + * relatively minor free space accounting inconsistency rather than suffer the + * inevitable crash from use of an invalid agfl block. + */ +static void +xfs_agfl_reset( + struct xfs_trans *tp, + struct xfs_buf *agbp, + struct xfs_perag *pag) +{ + struct xfs_mount *mp = tp->t_mountp; + struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); + + ASSERT(pag->pagf_agflreset); + trace_xfs_agfl_reset(mp, agf, 0, _RET_IP_); + + xfs_warn(mp, + "WARNING: Reset corrupted AGFL on AG %u. %d blocks leaked. " + "Please unmount and run xfs_repair.", + pag->pag_agno, pag->pagf_flcount); + + agf->agf_flfirst = 0; + agf->agf_fllast = cpu_to_be32(XFS_AGFL_SIZE(mp) - 1); + agf->agf_flcount = 0; + xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLFIRST | XFS_AGF_FLLAST | + XFS_AGF_FLCOUNT); + + pag->pagf_flcount = 0; + pag->pagf_agflreset = false; +} + /* * Decide whether to use this allocation group for this allocation. * If so, fix up the btree freelist's size. @@ -2095,6 +2182,10 @@ xfs_alloc_fix_freelist( } } + /* reset a padding mismatched agfl before final free space check */ + if (pag->pagf_agflreset) + xfs_agfl_reset(tp, agbp, pag); + /* If there isn't enough total space or single-extent, reject it. */ need = xfs_alloc_min_freelist(mp, pag); if (!xfs_alloc_space_available(args, need, flags)) @@ -2251,6 +2342,7 @@ xfs_alloc_get_freelist( agf->agf_flfirst = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); + ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; @@ -2362,6 +2454,7 @@ xfs_alloc_put_freelist( agf->agf_fllast = 0; pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); + ASSERT(!pag->pagf_agflreset); be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; @@ -2568,6 +2661,7 @@ xfs_alloc_read_agf( pag->pagb_count = 0; pag->pagb_tree = RB_ROOT; pag->pagf_init = 1; + pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf); } #ifdef DEBUG else if (!XFS_FORCED_SHUTDOWN(mp)) { diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index 5415f9031ef819052eee0862bda32d52f899c35d..7cb099e1c84c1888b2a871ce8f186d02ab6512b5 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -368,6 +368,7 @@ typedef struct xfs_perag { char pagi_inodeok; /* The agi is ok for inodes */ __uint8_t pagf_levels[XFS_BTNUM_AGF]; /* # of levels in bno & cnt btree */ + bool pagf_agflreset; /* agfl requires reset before use */ __uint32_t pagf_flcount; /* count of blocks in freelist */ xfs_extlen_t pagf_freeblks; /* total free blocks */ xfs_extlen_t pagf_longest; /* longest free space */ diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index bdf69e1c74102610e314a786c638253bcedef201..42a7c0da898f671e3d7482f3c7f1ed1e23c862ec 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -1516,7 +1516,7 @@ TRACE_EVENT(xfs_trans_commit_lsn, __entry->lsn) ); -TRACE_EVENT(xfs_agf, +DECLARE_EVENT_CLASS(xfs_agf_class, TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, unsigned long caller_ip), TP_ARGS(mp, agf, flags, caller_ip), @@ -1572,6 +1572,13 @@ TRACE_EVENT(xfs_agf, __entry->longest, (void *)__entry->caller_ip) ); +#define DEFINE_AGF_EVENT(name) \ +DEFINE_EVENT(xfs_agf_class, name, \ + TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, \ + unsigned long caller_ip), \ + TP_ARGS(mp, agf, flags, caller_ip)) +DEFINE_AGF_EVENT(xfs_agf); +DEFINE_AGF_EVENT(xfs_agfl_reset); TRACE_EVENT(xfs_free_extent, TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 661dcec43adbcb07652df1b9f9498a3625d35da8..211e80b8c4632897b2cfcdfc4ba02e20231532d5 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -910,8 +910,8 @@ static inline unsigned int blk_max_size_offset(struct request_queue *q, if (!q->limits.chunk_sectors) return q->limits.max_sectors; - return q->limits.chunk_sectors - - (offset & (q->limits.chunk_sectors - 1)); + return min(q->limits.max_sectors, (unsigned int)(q->limits.chunk_sectors - + (offset & (q->limits.chunk_sectors - 1)))); } static inline unsigned int blk_rq_get_max_sectors(struct request *rq, diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index eba928571cf28bc611d68b2af78f5183b670f215..a6d1bf2a5b8e858a965542a7e79a9ee6f3cea504 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -210,7 +210,7 @@ #ifdef CONFIG_STACK_VALIDATION #define annotate_unreachable() ({ \ asm("1:\t\n" \ - ".pushsection __unreachable, \"a\"\t\n" \ + ".pushsection .discard.unreachable\t\n" \ ".long 1b\t\n" \ ".popsection\t\n"); \ }) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 81bcdcaaceb3cd6aff8f27391450e388aa3d0466..7385c7f1b60d109904dcd32ba68fee8f7212fb0f 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -113,7 +113,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); #define unlikely_notrace(x) __builtin_expect(!!(x), 0) #define __branch_check__(x, expect) ({ \ - int ______r; \ + long ______r; \ static struct ftrace_branch_data \ __attribute__((__aligned__(4))) \ __attribute__((section("_ftrace_annotated_branch"))) \ diff --git a/include/linux/extcon.h b/include/linux/extcon.h index a9a16f2b019781c3210ffd102adf1f1d7020f09c..94c7be2d8587efad4980fd866c69e2c3dbba473e 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -113,14 +113,19 @@ * @type: integer (intval) * @value: 0 (USB/USB2) or 1 (USB3) * @default: 0 (USB/USB2) + * -EXTCON_PROP_USB_PD_CONTRACT + * @type: integer (intval) + * @value: 0 (bus powered) or 1 (self powered) + * @default: 0 (bus powered) * */ #define EXTCON_PROP_USB_VBUS 0 #define EXTCON_PROP_USB_TYPEC_POLARITY 1 #define EXTCON_PROP_USB_SS 2 +#define EXTCON_PROP_USB_PD_CONTRACT 3 #define EXTCON_PROP_USB_MIN 0 -#define EXTCON_PROP_USB_MAX 2 +#define EXTCON_PROP_USB_MAX 3 #define EXTCON_PROP_USB_CNT (EXTCON_PROP_USB_MAX - EXTCON_PROP_USB_MIN + 1) /* Properties of EXTCON_TYPE_CHG. */ diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 70a5164f4728ea0325fa6a74811c484d30f8ead2..821965c90070a3968efa62f645d5bc5be5c96781 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -61,7 +61,7 @@ struct iio_buffer_access_funcs { int (*request_update)(struct iio_buffer *buffer); int (*set_bytes_per_datum)(struct iio_buffer *buffer, size_t bpd); - int (*set_length)(struct iio_buffer *buffer, int length); + int (*set_length)(struct iio_buffer *buffer, unsigned int length); int (*enable)(struct iio_buffer *buffer, struct iio_dev *indio_dev); int (*disable)(struct iio_buffer *buffer, struct iio_dev *indio_dev); @@ -96,8 +96,8 @@ struct iio_buffer_access_funcs { * @watermark: [INTERN] number of datums to wait for poll/read. */ struct iio_buffer { - int length; - int bytes_per_datum; + unsigned int length; + size_t bytes_per_datum; struct attribute_group *scan_el_attrs; long *scan_mask; bool scan_timestamp; diff --git a/include/linux/kernel_stat.h b/include/linux/kernel_stat.h index 44fda64ad4344c9ea34eac09616a02eba44a479a..d0826f1739ac7aece97dc14bc9e1bbcb1840ceaf 100644 --- a/include/linux/kernel_stat.h +++ b/include/linux/kernel_stat.h @@ -33,6 +33,7 @@ enum cpu_usage_stat { struct kernel_cpustat { u64 cpustat[NR_STATS]; + u64 softirq_no_ksoftirqd; }; struct kernel_stat { diff --git a/include/linux/mm.h b/include/linux/mm.h index 9d5d8087b38df27fc69ed74c9d047935c32d1503..e7b96529374f0c57b67d750dde029a1edffd22c6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -269,6 +269,11 @@ extern unsigned int kobjsize(const void *objp); /* This mask is used to clear all the VMA flags used by mlock */ #define VM_LOCKED_CLEAR_MASK (~(VM_LOCKED | VM_LOCKONFAULT)) +#ifdef CONFIG_ARCH_MSM8953_SOC_SETTINGS +#define MSM8953_TLMM_START_ADDR 0x01000000 +#define MSM8953_TLMM_END_ADDR (0x01300000 - 1) +#endif + /* * mapping from the currently active vm_flags protection bits (the * low four bits) to a page protection mask.. @@ -360,7 +365,7 @@ struct fault_env { /* * These are the virtual MM functions - opening of an area, closing and * unmapping it (needed to keep files on disk up-to-date etc), pointer - * to the functions called when a no-page or a wp-page exception occurs. + * to the functions called when a no-page or a wp-page exception occurs. */ struct vm_operations_struct { void (*open)(struct vm_area_struct * area); diff --git a/include/linux/msm_gpi.h b/include/linux/msm_gpi.h index 6fe4a4e81a511508fa2d6f1d565be7afd08575c8..08e34b60d762eb2914861f18f5901be335af6227 100644 --- a/include/linux/msm_gpi.h +++ b/include/linux/msm_gpi.h @@ -151,6 +151,12 @@ enum msm_gpi_tre_type { #define MSM_GPI_I2C_CONFIG0_TRE_DWORD3(bei, ieot, ieob, ch) ((0x2 << 20) | \ (0x2 << 16) | (bei << 10) | (ieot << 9) | (ieob << 8) | ch) +#ifdef CONFIG_ARM64 +#define MSM_GPI_RING_PHYS_ADDR_UPPER(ring) ((u32)(ring->phys_addr >> 32)) +#else +#define MSM_GPI_RING_PHYS_ADDR_UPPER(ring) 0 +#endif + /* cmds to perform by using dmaengine_slave_config() */ enum msm_gpi_ctrl_cmd { MSM_GPI_INIT, diff --git a/include/linux/msm_mhi_dev.h b/include/linux/msm_mhi_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..b96591b27f6a4677e3cadd71eb7ae5fdabc7ae6d --- /dev/null +++ b/include/linux/msm_mhi_dev.h @@ -0,0 +1,259 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MSM_MHI_DEV_H +#define __MSM_MHI_DEV_H + +#include +#include + +#define IPA_DMA_SYNC 1 +#define IPA_DMA_ASYNC 0 + +enum cb_reason { + MHI_DEV_TRE_AVAILABLE = 0, + MHI_DEV_CTRL_UPDATE, +}; + +struct mhi_dev_client_cb_reason { + uint32_t ch_id; + enum cb_reason reason; +}; + +struct mhi_dev_client { + struct list_head list; + struct mhi_dev_channel *channel; + void (*event_trigger)(struct mhi_dev_client_cb_reason *cb); + + /* mhi_dev calls are fully synchronous -- only one call may be + * active per client at a time for now. + */ + struct mutex write_lock; + wait_queue_head_t wait; + + /* trace logs */ + spinlock_t tr_lock; + unsigned int tr_head; + unsigned int tr_tail; + struct mhi_dev_trace *tr_log; + + /* client buffers */ + struct mhi_dev_iov *iov; + uint32_t nr_iov; +}; + +enum mhi_ctrl_info { + MHI_STATE_CONFIGURED = 0, + MHI_STATE_CONNECTED = 1, + MHI_STATE_DISCONNECTED = 2, + MHI_STATE_INVAL, +}; + +struct mhi_req { + u32 chan; + u32 mode; + u32 chain; + void *buf; + dma_addr_t dma; + u32 snd_cmpl; + void *context; + size_t len; + size_t actual_len; + uint32_t rd_offset; + struct mhi_dev_client *client; + struct list_head list; + union mhi_dev_ring_element_type *el; + void (*client_cb)(void *req); +}; + +/* SW channel client list */ +enum mhi_client_channel { + MHI_CLIENT_LOOPBACK_OUT = 0, + MHI_CLIENT_LOOPBACK_IN = 1, + MHI_CLIENT_SAHARA_OUT = 2, + MHI_CLIENT_SAHARA_IN = 3, + MHI_CLIENT_DIAG_OUT = 4, + MHI_CLIENT_DIAG_IN = 5, + MHI_CLIENT_SSR_OUT = 6, + MHI_CLIENT_SSR_IN = 7, + MHI_CLIENT_QDSS_OUT = 8, + MHI_CLIENT_QDSS_IN = 9, + MHI_CLIENT_EFS_OUT = 10, + MHI_CLIENT_EFS_IN = 11, + MHI_CLIENT_MBIM_OUT = 12, + MHI_CLIENT_MBIM_IN = 13, + MHI_CLIENT_QMI_OUT = 14, + MHI_CLIENT_QMI_IN = 15, + MHI_CLIENT_IP_CTRL_0_OUT = 16, + MHI_CLIENT_IP_CTRL_0_IN = 17, + MHI_CLIENT_IP_CTRL_1_OUT = 18, + MHI_CLIENT_IP_CTRL_1_IN = 19, + MHI_CLIENT_DCI_OUT = 20, + MHI_CLIENT_DCI_IN = 21, + MHI_CLIENT_IP_CTRL_3_OUT = 22, + MHI_CLIENT_IP_CTRL_3_IN = 23, + MHI_CLIENT_IP_CTRL_4_OUT = 24, + MHI_CLIENT_IP_CTRL_4_IN = 25, + MHI_CLIENT_IP_CTRL_5_OUT = 26, + MHI_CLIENT_IP_CTRL_5_IN = 27, + MHI_CLIENT_IP_CTRL_6_OUT = 28, + MHI_CLIENT_IP_CTRL_6_IN = 29, + MHI_CLIENT_IP_CTRL_7_OUT = 30, + MHI_CLIENT_IP_CTRL_7_IN = 31, + MHI_CLIENT_DUN_OUT = 32, + MHI_CLIENT_DUN_IN = 33, + MHI_CLIENT_IP_SW_0_OUT = 34, + MHI_CLIENT_IP_SW_0_IN = 35, + MHI_CLIENT_ADB_OUT = 36, + MHI_CLIENT_ADB_IN = 37, + MHI_CLIENT_IP_SW_2_OUT = 38, + MHI_CLIENT_IP_SW_2_IN = 39, + MHI_CLIENT_IP_SW_3_OUT = 40, + MHI_CLIENT_IP_SW_3_IN = 41, + MHI_CLIENT_CSVT_OUT = 42, + MHI_CLIENT_CSVT_IN = 43, + MHI_CLIENT_SMCT_OUT = 44, + MHI_CLIENT_SMCT_IN = 45, + MHI_CLIENT_IP_SW_4_OUT = 46, + MHI_CLIENT_IP_SW_4_IN = 47, + MHI_MAX_SOFTWARE_CHANNELS, + MHI_CLIENT_TEST_OUT = 60, + MHI_CLIENT_TEST_IN = 61, + MHI_CLIENT_RESERVED_1_LOWER = 62, + MHI_CLIENT_RESERVED_1_UPPER = 99, + MHI_CLIENT_IP_HW_0_OUT = 100, + MHI_CLIENT_IP_HW_0_IN = 101, + MHI_CLIENT_RESERVED_2_LOWER = 102, + MHI_CLIENT_RESERVED_2_UPPER = 127, + MHI_MAX_CHANNELS = 102, + MHI_CLIENT_INVALID = 0xFFFFFFFF +}; + +struct mhi_dev_client_cb_data { + void *user_data; + enum mhi_client_channel channel; + enum mhi_ctrl_info ctrl_info; +}; + +typedef void (*mhi_state_cb)(struct mhi_dev_client_cb_data *cb_dat); + +struct mhi_dev_ready_cb_info { + struct list_head list; + mhi_state_cb cb; + struct mhi_dev_client_cb_data cb_data; +}; + +#if defined(CONFIG_MSM_MHI_DEV) +/** + * mhi_dev_open_channel() - Channel open for a given client done prior + * to read/write. + * @chan_id: Software Channel ID for the assigned client. + * @handle_client: Structure device for client handle. + * @notifier: Client issued callback notification. + */ +int mhi_dev_open_channel(uint32_t chan_id, + struct mhi_dev_client **handle_client, + void (*event_trigger)(struct mhi_dev_client_cb_reason *cb)); + +/** + * mhi_dev_close_channel() - Channel close for a given client. + */ +int mhi_dev_close_channel(struct mhi_dev_client *handle_client); + +/** + * mhi_dev_read_channel() - Channel read for a given client + * @mreq: mreq is the client argument which includes meta info + * like write data location, buffer len, read offset, mode, + * chain and client call back function which will be invoked + * when data read is completed. + */ +int mhi_dev_read_channel(struct mhi_req *mreq); + +/** + * mhi_dev_write_channel() - Channel write for a given software client. + * @wreq wreq is the client argument which includes meta info like + * client handle, read data location, buffer length, mode, + * and client call back function which will free the packet. + * when data write is completed. + */ +int mhi_dev_write_channel(struct mhi_req *wreq); + +/** + * mhi_dev_channel_isempty() - Checks if there is any pending TRE's to process. + * @handle_client: Client Handle issued during mhi_dev_open_channel + */ +int mhi_dev_channel_isempty(struct mhi_dev_client *handle); + +/** + * mhi_ctrl_state_info() - Provide MHI state info + * @idx: Channel number idx. Look at channel_state_info and + * pass the index for the corresponding channel. + * @info: Return the control info. + * MHI_STATE=CONFIGURED - MHI device is present but not ready + * for data traffic. + * MHI_STATE=CONNECTED - MHI device is ready for data transfer. + * MHI_STATE=DISCONNECTED - MHI device has its pipes suspended. + * exposes device nodes for the supported MHI software + * channels. + */ +int mhi_ctrl_state_info(uint32_t idx, uint32_t *info); + +/** + * mhi_register_state_cb() - Clients can register and receive callback after + * MHI channel is connected or disconnected. + */ +int mhi_register_state_cb(void (*mhi_state_cb) + (struct mhi_dev_client_cb_data *cb_data), void *data, + enum mhi_client_channel channel); + +#else +static inline int mhi_dev_open_channel(uint32_t chan_id, + struct mhi_dev_client **handle_client, + void (*event_trigger)(struct mhi_dev_client_cb_reason *cb)) +{ + return -EINVAL; +}; + +static inline int mhi_dev_close_channel(struct mhi_dev_client *handle_client) +{ + return -EINVAL; +}; + +static inline int mhi_dev_read_channel(struct mhi_req *mreq) +{ + return -EINVAL; +}; + +static inline int mhi_dev_write_channel(struct mhi_req *wreq) +{ + return -EINVAL; +}; + +static inline int mhi_dev_channel_isempty(struct mhi_dev_client *handle) +{ + return -EINVAL; +}; + +static inline int mhi_ctrl_state_info(uint32_t idx, uint32_t *info) +{ + return -EINVAL; +}; + +static inline int mhi_register_state_cb(void (*mhi_state_cb) + (struct mhi_dev_client_cb_data *cb_data), void *data, + enum mhi_client_channel channel) +{ + return -EINVAL; +}; +#endif + +#endif /* _MSM_MHI_DEV_H*/ diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 94124807b2b129e844aff1116f3f1c00ac601151..4c0778848426c888541bef13e12c6541317d2b01 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -302,6 +302,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_ESR_NOMINAL, POWER_SUPPLY_PROP_SOH, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, + POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, /* Local extensions of type int64_t */ POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT, /* Properties of type `const char *' */ diff --git a/include/linux/tcp.h b/include/linux/tcp.h index fc1164181d69f116fcc1eab7d117e2fdd3034c74..b8ea15ad379074efb1d6581b4374606cf909eaba 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -338,7 +338,7 @@ struct tcp_sock { /* Receiver queue space */ struct { - int space; + u32 space; u32 seq; u32 time; } rcvq_space; diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 3f3a7e45c1d2733a14c4da8cc921b1ad8da2c7b7..0267bed4bcf9acc38822f34d061299ae1770a097 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -539,6 +539,7 @@ struct usb_gadget { u32 extra_buf_alloc; bool l1_supported; bool is_chipidea; + bool self_powered; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) diff --git a/include/net/bonding.h b/include/net/bonding.h index 7734cc9c7d29eb7b3d8a7f709e59c87938fbb8d4..714428c54c68a094b5bdc94639ac5496bc467dee 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -277,6 +277,11 @@ static inline bool bond_is_lb(const struct bonding *bond) BOND_MODE(bond) == BOND_MODE_ALB; } +static inline bool bond_needs_speed_duplex(const struct bonding *bond) +{ + return BOND_MODE(bond) == BOND_MODE_8023AD || bond_is_lb(bond); +} + static inline bool bond_is_nondyn_tlb(const struct bonding *bond) { return (BOND_MODE(bond) == BOND_MODE_TLB) && diff --git a/include/net/cnss.h b/include/net/cnss.h index 368d01ecc879a0469d54dc53dc9578714d8ed1bd..3b864fc738861dab1c82d586f7fa594f51a3dd95 100644 --- a/include/net/cnss.h +++ b/include/net/cnss.h @@ -102,11 +102,14 @@ struct cnss_platform_cap { u32 cap_flag; }; -/* WLAN driver status */ +/* WLAN driver status, keep it aligned with cnss2 */ enum cnss_driver_status { CNSS_UNINITIALIZED, CNSS_INITIALIZED, - CNSS_LOAD_UNLOAD + CNSS_LOAD_UNLOAD, + CNSS_RECOVERY, + CNSS_FW_DOWN, + CNSS_SSR_FAIL, }; enum cnss_runtime_request { @@ -120,6 +123,8 @@ enum cnss_runtime_request { CNSS_PM_GET_NORESUME, }; +extern struct dma_iommu_mapping *cnss_smmu_get_mapping(void); +extern int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size); extern int cnss_get_fw_image(struct image_desc_info *image_desc_info); extern void cnss_runtime_init(struct device *dev, int auto_delay); extern void cnss_runtime_exit(struct device *dev); diff --git a/include/net/cnss2.h b/include/net/cnss2.h index 342907d3a68d47e0ace6395bf523f29f2ad602c3..c5ccee4db262fb73eebe65b3138a61040b62ee49 100644 --- a/include/net/cnss2.h +++ b/include/net/cnss2.h @@ -159,6 +159,9 @@ extern int cnss_get_fw_files_for_target(struct device *dev, u32 target_type, u32 target_version); extern int cnss_get_platform_cap(struct device *dev, struct cnss_platform_cap *cap); +extern struct dma_iommu_mapping *cnss_smmu_get_mapping(struct device *dev); +extern int cnss_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size); extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info); extern int cnss_request_bus_bandwidth(struct device *dev, int bandwidth); extern int cnss_power_up(struct device *dev); diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 31b4cceec198dbff224a0e3defd97ce6270667f1..7ef3db418100e481c6fcc5a0629dfe7f6a41fe13 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -142,5 +142,6 @@ extern unsigned int icnss_socinfo_get_serial_number(struct device *dev); extern bool icnss_is_qmi_disable(struct device *dev); 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); #endif /* _ICNSS_WLAN_H_ */ diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index b355ebfd76973052aadeb54acb392a817b01cc8c..b3ec962785f88ce7a6f9c3b1fd3882a086425664 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -657,6 +657,10 @@ TRACE_EVENT(sched_cpu_util, __field(unsigned int, capacity_orig ) __field(int, idle_state ) __field(u64, irqload ) + __field(int, online ) + __field(int, isolated ) + __field(int, reserved ) + __field(int, high_irq_load ) ), TP_fast_assign( @@ -669,10 +673,14 @@ TRACE_EVENT(sched_cpu_util, __entry->capacity_orig = capacity_orig_of(cpu); __entry->idle_state = idle_get_state_idx(cpu_rq(cpu)); __entry->irqload = sched_irqload(cpu); + __entry->online = cpu_online(cpu); + __entry->isolated = cpu_isolated(cpu); + __entry->reserved = is_reserved(cpu); + __entry->high_irq_load = sched_cpu_high_irqload(cpu); ), - TP_printk("cpu=%d nr_running=%d cpu_util=%ld cpu_util_cum=%ld capacity_curr=%u capacity=%u capacity_orig=%u idle_state=%d irqload=%llu", - __entry->cpu, __entry->nr_running, __entry->cpu_util, __entry->cpu_util_cum, __entry->capacity_curr, __entry->capacity, __entry->capacity_orig, __entry->idle_state, __entry->irqload) + TP_printk("cpu=%d nr_running=%d cpu_util=%ld cpu_util_cum=%ld capacity_curr=%u capacity=%u capacity_orig=%u idle_state=%d irqload=%llu online=%u isolated=%u reserved=%u high_irq_load=%u", + __entry->cpu, __entry->nr_running, __entry->cpu_util, __entry->cpu_util_cum, __entry->capacity_curr, __entry->capacity, __entry->capacity_orig, __entry->idle_state, __entry->irqload, __entry->online, __entry->isolated, __entry->reserved, __entry->high_irq_load) ); TRACE_EVENT(sched_energy_diff, @@ -1637,10 +1645,11 @@ TRACE_EVENT(sched_find_best_target, TP_PROTO(struct task_struct *tsk, bool prefer_idle, unsigned long min_util, int start_cpu, - int best_idle, int best_active, int target), + int best_idle, int best_active, int target, + int backup_cpu), TP_ARGS(tsk, prefer_idle, min_util, start_cpu, - best_idle, best_active, target), + best_idle, best_active, target, backup_cpu), TP_STRUCT__entry( __array( char, comm, TASK_COMM_LEN ) @@ -1651,6 +1660,7 @@ TRACE_EVENT(sched_find_best_target, __field( int, best_idle ) __field( int, best_active ) __field( int, target ) + __field( int, backup_cpu ) ), TP_fast_assign( @@ -1662,14 +1672,16 @@ TRACE_EVENT(sched_find_best_target, __entry->best_idle = best_idle; __entry->best_active = best_active; __entry->target = target; + __entry->backup_cpu = backup_cpu; ), TP_printk("pid=%d comm=%s prefer_idle=%d start_cpu=%d " - "best_idle=%d best_active=%d target=%d", + "best_idle=%d best_active=%d target=%d backup=%d", __entry->pid, __entry->comm, __entry->prefer_idle, __entry->start_cpu, __entry->best_idle, __entry->best_active, - __entry->target) + __entry->target, + __entry->backup_cpu) ); TRACE_EVENT(sched_group_energy, diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index d5ad15a106a707c13fa77c5733ea96b8e750a5c8..c794c9af6c0fd1c80546dc9f685a330f1a4a3c46 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -452,6 +452,7 @@ struct btrfs_free_space_header { #define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) #define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) +#define BTRFS_SUPER_FLAG_METADUMP_V2 (1ULL << 34) /* diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index be4cb02f7e34708d263c227ec5a1ad6e34286a88..34ecd82ec7f0243560ef290035c147517d8ed0dd 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -520,7 +520,13 @@ enum ipa_vlan_bridge_event { BRIDGE_VLAN_MAPPING_MAX }; -#define IPA_EVENT_MAX_NUM (BRIDGE_VLAN_MAPPING_MAX) +enum ipa_wlan_fw_ssr_event { + WLAN_FWR_SSR_BEFORE_SHUTDOWN = BRIDGE_VLAN_MAPPING_MAX, + IPA_WLAN_FW_SSR_EVENT_MAX +#define IPA_WLAN_FW_SSR_EVENT_MAX IPA_WLAN_FW_SSR_EVENT_MAX +}; + +#define IPA_EVENT_MAX_NUM (IPA_WLAN_FW_SSR_EVENT_MAX) #define IPA_EVENT_MAX ((int)IPA_EVENT_MAX_NUM) /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h index 20a01ca72c665a5a5a60c6a3e940de3cce2bec01..8143af6c0e1f6e5f154f06f778e5bc36bef26e46 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h @@ -2603,7 +2603,7 @@ enum nl80211_attrs { #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS #define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS -#define NL80211_WIPHY_NAME_MAXLEN 128 +#define NL80211_WIPHY_NAME_MAXLEN 64 #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_HT_RATES 77 diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h index 40882a7ae8c49a10e196fcae20bb7781b697a65d..54aa36261980ef99a29076a31974230215d70343 100644 --- a/include/uapi/linux/qg.h +++ b/include/uapi/linux/qg.h @@ -20,7 +20,7 @@ enum qg { QG_ESR_DISCHARGE_SF, QG_FULL_SOC, QG_CLEAR_LEARNT_DATA, - QG_RESERVED_9, + QG_SYS_SOC, QG_RESERVED_10, QG_MAX, }; @@ -33,6 +33,7 @@ enum qg { #define QG_ESR_DISCHARGE_SF QG_ESR_DISCHARGE_SF #define QG_FULL_SOC QG_FULL_SOC #define QG_CLEAR_LEARNT_DATA QG_CLEAR_LEARNT_DATA +#define QG_SYS_SOC QG_SYS_SOC struct fifo_data { unsigned int v; diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild index 1aa2a1962ca2ae8d958edd1597aae76456e2f279..7f93c1c25b9905fa973360e31f6a0806ba21e4f1 100644 --- a/include/uapi/media/Kbuild +++ b/include/uapi/media/Kbuild @@ -26,5 +26,6 @@ header-y += msm_media_info.h header-y += msmb_camera.h header-y += msmb_generic_buf_mgr.h header-y += msmb_isp.h +header-y += msmb_qca.h header-y += msmb_ispif.h header-y += msmb_pproc.h \ No newline at end of file diff --git a/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h index cd2d2d29700372aff50f114350fc8dc1312fecc1..680d05b630a67e3d1e2cdee3860f55a074a6dae4 100644 --- a/include/uapi/media/cam_icp.h +++ b/include/uapi/media/cam_icp.h @@ -59,8 +59,9 @@ /* Command meta types */ #define CAM_ICP_CMD_META_GENERIC_BLOB 0x1 -/* Generic blon types */ +/* Generic blob types */ #define CAM_ICP_CMD_GENERIC_BLOB_CLK 0x1 +#define CAM_ICP_CMD_GENERIC_BLOB_CFG_IO 0x2 /** * struct cam_icp_clk_bw_request diff --git a/include/uapi/media/msmb_qca.h b/include/uapi/media/msmb_qca.h new file mode 100644 index 0000000000000000000000000000000000000000..02a6b1f6d380196a9b4452a5f3b8ae9bb44de96d --- /dev/null +++ b/include/uapi/media/msmb_qca.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2018, The Linux Foundation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __UAPI_LINUX_MSMB_QCA402X_H +#define __UAPI_LINUX_MSMB_QCA402X_H + +#include +#include +#define QCA402X_HTC + +#define MSM_QCA_EVENT_ENQ_BUF 0 +#define MSM_QCA_EVENT_SEND_MSG 1 +#define MSM_QCA_EVENT_RECV_MSG 2 + +struct msm_qca_message_type { + __u64 header; + __u64 buff_addr; + int fd; + __u32 header_size; + __u32 data_size; + __u8 cmd; + __u8 channel_id; + __u8 is_ion_data; + __u8 last_data; +}; + +struct msm_qca_event_type { + __u8 cmd; + __u8 channel_id; +}; + +struct msm_qca_event_list_type { + __u64 events; + __u32 num_events; +}; + +#define MSM_QCA402X_ENQUEUE_BUFFER \ + _IOWR(0xdd, 1, struct msm_qca_message_type) +#define MSM_QCA402X_SEND_MESSAGE \ + _IOWR(0xdd, 2, struct msm_qca_message_type) +#define MSM_QCA402X_RECEIVE_MESSAGE \ + _IOWR(0xdd, 3, struct msm_qca_message_type) +#define MSM_QCA402X_FLUSH_BUFFERS \ + _IOWR(0xdd, 4, struct msm_qca_event_list_type) +#define MSM_QCA402X_ABORT_MESSAGE \ + _IOWR(0xdd, 5, struct msm_qca_event_list_type) +#define MSM_QCA402X_REGISTER_EVENT \ + _IOWR(0xdd, 6, struct msm_qca_event_list_type) +#define MSM_QCA402X_UNREGISTER_EVENT \ + _IOWR(0xdd, 7, struct msm_qca_event_list_type) +#endif /*__UAPI_LINUX_MSMB_QCA402X_H*/ + diff --git a/kernel/module.c b/kernel/module.c index 13ad2f8c44f9b936b445abae246106b1c67c2750..8a840312efd06ce045d463bab053b8674d3b03bf 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2156,6 +2156,11 @@ static void free_module(struct module *mod) /* Finally, free the core (containing the module structure) */ disable_ro_nx(&mod->core_layout); +#ifdef CONFIG_DEBUG_MODULE_LOAD_INFO + pr_info("Unloaded %s: module core layout address range: 0x%lx-0x%lx\n", + mod->name, (long)mod->core_layout.base, + (long)(mod->core_layout.base + mod->core_layout.size - 1)); +#endif module_memfree(mod->core_layout.base); #ifdef CONFIG_MPU @@ -3469,6 +3474,14 @@ static noinline int do_init_module(struct module *mod) mod_tree_remove_init(mod); disable_ro_nx(&mod->init_layout); module_arch_freeing_init(mod); +#ifdef CONFIG_DEBUG_MODULE_LOAD_INFO + pr_info("Loaded %s: module init layout addresses range: 0x%lx-0x%lx\n", + mod->name, (long)mod->init_layout.base, + (long)(mod->init_layout.base + mod->init_layout.size - 1)); + pr_info("%s: core layout addresses range: 0x%lx-0x%lx\n", mod->name, + (long)mod->core_layout.base, + (long)(mod->core_layout.base + mod->core_layout.size - 1)); +#endif mod->init_layout.base = NULL; mod->init_layout.size = 0; mod->init_layout.ro_size = 0; diff --git a/kernel/printk/nmi.c b/kernel/printk/nmi.c index 16bab471c7e23d8099eebca1c897ccb6a09f6bdf..5fa65aa904d31ea55ab640ee3f87849380179371 100644 --- a/kernel/printk/nmi.c +++ b/kernel/printk/nmi.c @@ -63,6 +63,7 @@ static int vprintk_nmi(const char *fmt, va_list args) struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq); int add = 0; size_t len; + va_list ap; again: len = atomic_read(&s->len); @@ -79,7 +80,9 @@ static int vprintk_nmi(const char *fmt, va_list args) if (!len) smp_rmb(); - add = vsnprintf(s->buffer + len, sizeof(s->buffer) - len, fmt, args); + va_copy(ap, args); + add = vsnprintf(s->buffer + len, sizeof(s->buffer) - len, fmt, ap); + va_end(ap); /* * Do it once again if the buffer has been flushed in the meantime. diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index b71f116a2cec3624dfeb233c25fcaffada058c48..dc9518b545362cfa429eab667a45101757aabc86 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -365,11 +365,10 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, raw_spin_unlock(&sg_policy->update_lock); } -static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) +static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time) { struct sugov_policy *sg_policy = sg_cpu->sg_policy; struct cpufreq_policy *policy = sg_policy->policy; - u64 last_freq_update_time = sg_policy->last_freq_update_time; unsigned long util = 0, max = 1; unsigned int j; @@ -385,7 +384,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu) * enough, don't take the CPU into account as it probably is * idle now (and clear iowait_boost for it). */ - delta_ns = last_freq_update_time - j_sg_cpu->last_update; + delta_ns = time - j_sg_cpu->last_update; if (delta_ns > stale_ns) { j_sg_cpu->iowait_boost = 0; continue; @@ -450,7 +449,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time, if (flags & SCHED_CPUFREQ_RT_DL) next_f = sg_policy->policy->cpuinfo.max_freq; else - next_f = sugov_next_freq_shared(sg_cpu); + next_f = sugov_next_freq_shared(sg_cpu, time); sugov_update_commit(sg_policy, time, next_f); } diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 50f2ea890b6a63ea04b461cfd9d2c579ccb86100..a7c4b4caf1083d6712cd77a3bdff39b43c21e499 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -84,12 +84,19 @@ EXPORT_SYMBOL_GPL(irqtime_account_irq); static cputime_t irqtime_account_update(u64 irqtime, int idx, cputime_t maxtime) { u64 *cpustat = kcpustat_this_cpu->cpustat; + u64 base = cpustat[idx]; cputime_t irq_cputime; - irq_cputime = nsecs_to_cputime64(irqtime) - cpustat[idx]; + if (idx == CPUTIME_SOFTIRQ) + base = kcpustat_this_cpu->softirq_no_ksoftirqd; + + irq_cputime = nsecs_to_cputime64(irqtime) - base; irq_cputime = min(irq_cputime, maxtime); cpustat[idx] += irq_cputime; + if (idx == CPUTIME_SOFTIRQ) + kcpustat_this_cpu->softirq_no_ksoftirqd += irq_cputime; + return irq_cputime; } diff --git a/kernel/sched/energy.c b/kernel/sched/energy.c index 77d8361a7c2150a095a5852dce0d04c0c9cd700e..01daf82926cedf08b4c0d36f845b4323785ed001 100644 --- a/kernel/sched/energy.c +++ b/kernel/sched/energy.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -49,6 +50,17 @@ static void free_resources(void) } } +static int update_topology; + +/* + * Ideally this should be arch specific implementation, + * let's define here to help rebuild sched_domain with new capacities. + */ +int arch_update_cpu_topology(void) +{ + return update_topology; +} + void init_sched_energy_costs(void) { struct device_node *cn, *cp; @@ -273,8 +285,22 @@ static int sched_energy_probe(struct platform_device *pdev) kfree(max_frequencies); - if (is_sge_valid) + if (is_sge_valid) { + /* + * Sched_domains might have built with default cpu capacity + * values on bootup. + * + * Let's rebuild them again with actual cpu capacities. + * And partition_sched_domain() expects update in cpu topology + * to rebuild the domains, so make it satisfied.. + */ + update_topology = 1; + rebuild_sched_domains(); + update_topology = 0; + walt_sched_energy_populated_callback(); + } + dev_info(&pdev->dev, "Sched-energy-costs capacity updated\n"); return 0; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 38fed13db70ffd6446d4638b9c530e989a8fc6f3..91a909f8d6a6cc9e4e25d39a3e7d6841d6bb3199 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6194,13 +6194,14 @@ schedtune_margin(unsigned long signal, long boost) if (boost >= 0) { margin = SCHED_CAPACITY_SCALE - signal; margin *= boost; - } else + } else { margin = -signal * boost; + } margin = reciprocal_divide(margin, schedtune_spc_rdiv); - if (boost < 0) margin *= -1; + return margin; } @@ -6930,6 +6931,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, int cpu, i; unsigned int active_cpus_count = 0; int isolated_candidate = -1; + int prev_cpu = task_cpu(p); *backup_cpu = -1; @@ -6976,19 +6978,18 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, cpumask_clear_cpu(i, &search_cpus); + trace_sched_cpu_util(i); if (!cpu_online(i) || cpu_isolated(i)) continue; isolated_candidate = i; - if (avoid_prev_cpu && i == task_cpu(p)) + if (avoid_prev_cpu && i == prev_cpu) continue; if (walt_cpu_high_irqload(i) || is_reserved(i)) continue; - trace_sched_cpu_util(i); - /* * p's blocked utilization is still accounted for on prev_cpu * so prev_cpu will receive a negative bias due to the double @@ -7057,7 +7058,8 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, trace_sched_find_best_target(p, prefer_idle, min_util, cpu, best_idle_cpu, - best_active_cpu, i); + best_active_cpu, + i, -1); return i; } @@ -7234,7 +7236,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, if (best_idle_cpu != -1 && !is_packing_eligible(p, target_cpu, fbt_env, active_cpus_count, best_idle_cstate)) { - if (target_cpu == task_cpu(p)) + if (target_cpu == prev_cpu) fbt_env->avoid_prev_cpu = true; target_cpu = best_idle_cpu; @@ -7270,15 +7272,31 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, ? best_active_cpu : best_idle_cpu; - if (target_cpu == -1 && cpu_isolated(task_cpu(p)) && + if (target_cpu == -1 && cpu_isolated(prev_cpu) && isolated_candidate != -1) { target_cpu = isolated_candidate; fbt_env->avoid_prev_cpu = true; } + /* + * - It is possible for target and backup + * to select same CPU - if so, drop backup + * + * - The next step of energy evaluation includes + * prev_cpu. Drop target or backup if it is + * same as prev_cpu. + */ + if (*backup_cpu == target_cpu || *backup_cpu == prev_cpu) + *backup_cpu = -1; + + if (target_cpu == prev_cpu) { + target_cpu = *backup_cpu; + *backup_cpu = -1; + } + trace_sched_find_best_target(p, prefer_idle, min_util, cpu, best_idle_cpu, best_active_cpu, - target_cpu); + target_cpu, *backup_cpu); schedstat_inc(p->se.statistics.nr_wakeups_fbt_count); schedstat_inc(this_rq()->eas_stats.fbt_count); @@ -7451,12 +7469,10 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync goto out; } - rcu_read_lock(); - sd = rcu_dereference(per_cpu(sd_ea, prev_cpu)); if (!sd) { target_cpu = prev_cpu; - goto unlock; + goto out; } sync_entity_load_avg(&p->se); @@ -7466,14 +7482,14 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync &fbt_env); if (next_cpu == -1) { target_cpu = prev_cpu; - goto unlock; + goto out; } if (fbt_env.placement_boost || fbt_env.need_idle || fbt_env.avoid_prev_cpu || (rtg_target && !cpumask_test_cpu(prev_cpu, rtg_target))) { target_cpu = next_cpu; - goto unlock; + goto out; } /* Unconditionally prefer IDLE CPUs for boosted/prefer_idle tasks */ @@ -7481,7 +7497,7 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(p->se.statistics.nr_wakeups_secb_idle_bt); schedstat_inc(this_rq()->eas_stats.secb_idle_bt); target_cpu = next_cpu; - goto unlock; + goto out; } target_cpu = prev_cpu; @@ -7515,7 +7531,7 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(p->se.statistics.nr_wakeups_secb_insuff_cap); schedstat_inc(this_rq()->eas_stats.secb_insuff_cap); target_cpu = next_cpu; - goto unlock; + goto out; } /* Check if EAS_CPU_NXT is a more energy efficient CPU */ @@ -7523,20 +7539,18 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(p->se.statistics.nr_wakeups_secb_nrg_sav); schedstat_inc(this_rq()->eas_stats.secb_nrg_sav); target_cpu = eenv.cpu[eenv.next_idx].cpu_id; - goto unlock; + goto out; } schedstat_inc(p->se.statistics.nr_wakeups_secb_no_nrg_sav); schedstat_inc(this_rq()->eas_stats.secb_no_nrg_sav); target_cpu = prev_cpu; - goto unlock; + goto out; } schedstat_inc(p->se.statistics.nr_wakeups_secb_count); schedstat_inc(this_rq()->eas_stats.secb_count); -unlock: - rcu_read_unlock(); out: trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync, fbt_env.need_idle, fastpath, @@ -7572,8 +7586,12 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f cpumask_test_cpu(cpu, tsk_cpus_allowed(p))); } - if (energy_aware()) - return select_energy_cpu_brute(p, prev_cpu, sync); + if (energy_aware()) { + rcu_read_lock(); + new_cpu = select_energy_cpu_brute(p, prev_cpu, sync); + rcu_read_unlock(); + return new_cpu; + } rcu_read_lock(); for_each_domain(cpu, tmp) { diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index 44c767afdb87c3bac2a6d27ac2b0a5bf26a3134d..95b68bdc921536a3972aec3cbf7d0bda0a6040de 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1805,7 +1805,6 @@ static int find_lowest_rq(struct task_struct *task) } } } while (sg = sg->next, sg != sd->groups); - rcu_read_unlock(); if (sg_target) { cpumask_and(&search_cpu, lowest_mask, @@ -1894,6 +1893,7 @@ static int find_lowest_rq(struct task_struct *task) } if (best_cpu != -1 && placement_boost != SCHED_BOOST_ON_ALL) { + rcu_read_unlock(); return best_cpu; } else if (!cpumask_empty(&backup_search_cpu)) { cpumask_copy(&search_cpu, &backup_search_cpu); @@ -1902,6 +1902,7 @@ static int find_lowest_rq(struct task_struct *task) placement_boost = SCHED_BOOST_NONE; goto retry; } + rcu_read_unlock(); } noea: diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 192e8c72a4e1ae3d07d26f92db6dd2a2ebcf5a93..a8fab0cae9e391d7a34504ffdcf865b3132f1a13 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -110,6 +110,64 @@ __schedtune_accept_deltas(int nrg_delta, int cap_delta, /* * EAS scheduler tunables for task groups. + * + * When CGroup support is enabled, we have to synchronize two different + * paths: + * - slow path: where CGroups are created/updated/removed + * - fast path: where tasks in a CGroups are accounted + * + * The slow path tracks (a limited number of) CGroups and maps each on a + * "boost_group" index. The fastpath accounts tasks currently RUNNABLE on each + * "boost_group". + * + * Once a new CGroup is created, a boost group idx is assigned and the + * corresponding "boost_group" marked as valid on each CPU. + * Once a CGroup is release, the corresponding "boost_group" is marked as + * invalid on each CPU. The CPU boost value (boost_max) is aggregated by + * considering only valid boost_groups with a non null tasks counter. + * + * .:: Locking strategy + * + * The fast path uses a spin lock for each CPU boost_group which protects the + * tasks counter. + * + * The "valid" and "boost" values of each CPU boost_group is instead + * protected by the RCU lock provided by the CGroups callbacks. Thus, only the + * slow path can access and modify the boost_group attribtues of each CPU. + * The fast path will catch up the most updated values at the next scheduling + * event (i.e. enqueue/dequeue). + * + * | + * SLOW PATH | FAST PATH + * CGroup add/update/remove | Scheduler enqueue/dequeue events + * | + * | + * | DEFINE_PER_CPU(struct boost_groups) + * | +--------------+----+---+----+----+ + * | | idle | | | | | + * | | boost_max | | | | | + * | +---->lock | | | | | + * struct schedtune allocated_groups | | | group[ ] | | | | | + * +------------------------------+ +-------+ | | +--+---------+-+----+---+----+----+ + * | idx | | | | | | valid | + * | boots / prefer_idle | | | | | | boost | + * | perf_{boost/constraints}_idx | <---------+(*) | | | | tasks | <------------+ + * | css | +-------+ | | +---------+ | + * +-+----------------------------+ | | | | | | | + * ^ | | | | | | | + * | +-------+ | | +---------+ | + * | | | | | | | | + * | | | | | | | | + * | +-------+ | | +---------+ | + * | zmalloc | | | | | | | + * | | | | | | | | + * | +-------+ | | +---------+ | + * + BOOSTGROUPS_COUNT | | BOOSTGROUPS_COUNT | + * schedtune_boostgroup_init() | + | + * | schedtune_{en,de}queue_task() | + * | + + * | schedtune_tasks_update() + * | */ /* SchdTune tunables for a group of tasks */ @@ -259,10 +317,11 @@ static struct schedtune *allocated_group[BOOSTGROUPS_COUNT] = { * maximum per-CPU boosting value. */ struct boost_groups { - bool idle; /* Maximum boost value for all RUNNABLE tasks on a CPU */ int boost_max; struct { + /* True when this boost group maps an actual cgroup */ + bool valid; /* The boost for tasks on that boost group */ int boost; /* Count of RUNNABLE tasks on that boost group */ @@ -358,6 +417,11 @@ schedtune_cpu_update(int cpu) /* The root boost group is always active */ boost_max = bg->group[0].boost; for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx) { + + /* Ignore non boostgroups not mapping a cgroup */ + if (!bg->group[idx].valid) + continue; + /* * A boost group affects a CPU only if it has * RUNNABLE tasks on that CPU @@ -367,6 +431,7 @@ schedtune_cpu_update(int cpu) boost_max = max(boost_max, bg->group[idx].boost); } + /* Ensures boost_max is non-negative when all cgroup boost values * are neagtive. Avoids under-accounting of cpu capacity which may cause * task stacking and frequency spikes.*/ @@ -386,6 +451,9 @@ schedtune_boostgroup_update(int idx, int boost) for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); + /* CGroups are never associated to non active cgroups */ + BUG_ON(!bg->group[idx].valid); + /* * Keep track of current boost values to compute the per CPU * maximum only when it has been affected by the new value of @@ -827,24 +895,22 @@ static struct cftype files[] = { { } /* terminate */ }; - -static int -schedtune_boostgroup_init(struct schedtune *st) +static void +schedtune_boostgroup_init(struct schedtune *st, int idx) { struct boost_groups *bg; int cpu; - /* Keep track of allocated boost groups */ - allocated_group[st->idx] = st; - - /* Initialize the per CPU boost groups */ + /* Initialize per CPUs boost group support */ for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); - bg->group[st->idx].boost = 0; - bg->group[st->idx].tasks = 0; + bg->group[idx].boost = 0; + bg->group[idx].valid = true; } - return 0; + /* Keep track of allocated boost groups */ + allocated_group[idx] = st; + st->idx = idx; } static struct cgroup_subsys_state * @@ -877,15 +943,11 @@ schedtune_css_alloc(struct cgroup_subsys_state *parent_css) goto out; /* Initialize per CPUs boost group support */ - st->idx = idx; init_sched_boost(st); - if (schedtune_boostgroup_init(st)) - goto release; + schedtune_boostgroup_init(st, idx); return &st->css; -release: - kfree(st); out: return ERR_PTR(-ENOMEM); } @@ -893,8 +955,15 @@ schedtune_css_alloc(struct cgroup_subsys_state *parent_css) static void schedtune_boostgroup_release(struct schedtune *st) { - /* Reset this boost group */ - schedtune_boostgroup_update(st->idx, 0); + struct boost_groups *bg; + int cpu; + + /* Reset per CPUs boost group support */ + for_each_possible_cpu(cpu) { + bg = &per_cpu(cpu_boost_groups, cpu); + bg->group[st->idx].valid = false; + bg->group[st->idx].boost = 0; + } /* Keep track of allocated boost groups */ allocated_group[st->idx] = NULL; @@ -905,6 +974,7 @@ schedtune_css_free(struct cgroup_subsys_state *css) { struct schedtune *st = css_st(css); + /* Release per CPUs boost group support */ schedtune_boostgroup_release(st); kfree(st); } @@ -930,6 +1000,7 @@ schedtune_init_cgroups(void) for_each_possible_cpu(cpu) { bg = &per_cpu(cpu_boost_groups, cpu); memset(bg, 0, sizeof(struct boost_groups)); + bg->group[0].valid = true; raw_spin_lock_init(&bg->lock); } diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 4fe11819e5fc1156da284671b0376c04d3c7caae..4afefd629f3951e20313554bed77900c638838c8 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -87,11 +87,16 @@ late_initcall(sched_init_ops); static void acquire_rq_locks_irqsave(const cpumask_t *cpus, unsigned long *flags) { - int cpu; + int cpu, level = 0; local_irq_save(*flags); - for_each_cpu(cpu, cpus) - raw_spin_lock(&cpu_rq(cpu)->lock); + for_each_cpu(cpu, cpus) { + if (level == 0) + raw_spin_lock(&cpu_rq(cpu)->lock); + else + raw_spin_lock_nested(&cpu_rq(cpu)->lock, level); + level++; + } } static void release_rq_locks_irqrestore(const cpumask_t *cpus, @@ -701,14 +706,11 @@ static inline void inter_cluster_migration_fixup BUG_ON((s64)src_rq->nt_curr_runnable_sum < 0); } -static int load_to_index(u32 load) +static u32 load_to_index(u32 load) { - if (load < sched_load_granule) - return 0; - else if (load >= sched_ravg_window) - return NUM_LOAD_INDICES - 1; - else - return load / sched_load_granule; + u32 index = load / sched_load_granule; + + return min(index, (u32)(NUM_LOAD_INDICES - 1)); } static void @@ -3173,13 +3175,19 @@ void walt_irq_work(struct irq_work *irq_work) u64 wc; int flag = SCHED_CPUFREQ_WALT; bool is_migration = false; + int level = 0; /* Am I the window rollover work or the migration work? */ if (irq_work == &walt_migration_irq_work) is_migration = true; - for_each_cpu(cpu, cpu_possible_mask) - raw_spin_lock(&cpu_rq(cpu)->lock); + for_each_cpu(cpu, cpu_possible_mask) { + if (level == 0) + raw_spin_lock(&cpu_rq(cpu)->lock); + else + raw_spin_lock_nested(&cpu_rq(cpu)->lock, level); + level++; + } wc = sched_ktime_clock(); walt_load_reported_window = atomic64_read(&walt_irq_work_lastq_ws); diff --git a/kernel/time/time.c b/kernel/time/time.c index 1b2d2095f64868fd05470fe125623498da5327fe..15f34873fd12802e26e22b5ddf22d31d18b40965 100644 --- a/kernel/time/time.c +++ b/kernel/time/time.c @@ -28,6 +28,7 @@ */ #include +#include #include #include #include @@ -258,9 +259,10 @@ unsigned int jiffies_to_msecs(const unsigned long j) return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); #else # if BITS_PER_LONG == 32 - return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32; + return (HZ_TO_MSEC_MUL32 * j + (1ULL << HZ_TO_MSEC_SHR32) - 1) >> + HZ_TO_MSEC_SHR32; # else - return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN; + return DIV_ROUND_UP(j * HZ_TO_MSEC_NUM, HZ_TO_MSEC_DEN); # endif #endif } diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c index 6721a1e89f39c7ff086acef638dabfcac030c31e..88f398af57fa20ccb2b0fad6dba38ecaf1d294fe 100644 --- a/kernel/trace/trace_events_trigger.c +++ b/kernel/trace/trace_events_trigger.c @@ -481,9 +481,10 @@ clear_event_triggers(struct trace_array *tr) struct trace_event_file *file; list_for_each_entry(file, &tr->events, list) { - struct event_trigger_data *data; - list_for_each_entry_rcu(data, &file->triggers, list) { + struct event_trigger_data *data, *n; + list_for_each_entry_safe(data, n, &file->triggers, list) { trace_event_trigger_enable_disable(file, 0); + list_del_rcu(&data->list); if (data->ops->free) data->ops->free(data->ops, data); } diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 3cb38f1bcd28117be7c80acbc23adef951e5f39b..7461d51342d718bafb4ec3e6e7fd27c7aae57c95 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -835,6 +835,7 @@ print_graph_entry_leaf(struct trace_iterator *iter, struct ftrace_graph_ret *graph_ret; struct ftrace_graph_ent *call; unsigned long long duration; + int cpu = iter->cpu; int i; graph_ret = &ret_entry->ret; @@ -843,7 +844,6 @@ print_graph_entry_leaf(struct trace_iterator *iter, if (data) { struct fgraph_cpu_data *cpu_data; - int cpu = iter->cpu; cpu_data = per_cpu_ptr(data->cpu_data, cpu); @@ -873,6 +873,9 @@ print_graph_entry_leaf(struct trace_iterator *iter, trace_seq_printf(s, "%ps();\n", (void *)call->func); + print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET, + cpu, iter->ent->pid, flags); + return trace_handle_return(s); } diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 59b482f7eba7971545c817cd06b69f3ab28359cc..de63dab4119378bd475b7141d8c20f845b2c6fa3 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -804,10 +804,9 @@ static inline void tracer_preempt_on(unsigned long a0, unsigned long a1) { } static inline void tracer_preempt_off(unsigned long a0, unsigned long a1) { } #endif +#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PROVE_LOCKING) /* Per-cpu variable to prevent redundant calls when IRQs already off */ static DEFINE_PER_CPU(int, tracing_irq_cpu); - -#if defined(CONFIG_TRACE_IRQFLAGS) && !defined(CONFIG_PROVE_LOCKING) void trace_hardirqs_on(void) { if (!this_cpu_read(tracing_irq_cpu)) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 640818c67aa395f698e59e4fb7b6136767c64237..4fc6d8f6deee34c350bd24e7abf8e2eed5e8ef2b 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -113,6 +113,18 @@ config DYNAMIC_DEBUG See Documentation/dynamic-debug-howto.txt for additional information. +config DEBUG_MODULE_LOAD_INFO + bool "Use prints for module info under a debug flag" + help + If you say Y here the resulting kernel image will include + debug prints which was kept under DEBUG_MODULE_LOAD_INFO. + This will be used by developer to debug loadable modules in + the kernel. + Say Y here only if you plan to debug the kernel. + + If unsure, say N. + + endmenu # "printk and dmesg options" menu "Compile-time checks and compiler options" diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0967771d8f7fd725972c74097bd324a8b39b5609..79ba3cc07026c1c01a3b9d465088632c5b3c22ba 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -1391,9 +1391,6 @@ char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, return string(buf, end, NULL, spec); switch (fmt[1]) { - case 'r': - return number(buf, end, clk_get_rate(clk), spec); - case 'n': default: #ifdef CONFIG_COMMON_CLK diff --git a/mm/cma.c b/mm/cma.c index e97ad01ef148c2982b49d92dc342bcc1154b5c67..1ccfaa10e2e2b52f57f77b38bd7a450deebe10d2 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -466,7 +466,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) bitmap_maxno, start, bitmap_count, mask, offset); if (bitmap_no >= bitmap_maxno) { - if (retry_after_sleep < max_retries) { + if ((retry_after_sleep < max_retries) && + (ret == -EBUSY)) { start = 0; /* * update max retries if available free regions diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 6ff65c40524326890bd088fa5ae052061ed16252..f9e735537c377ab011cdb11cc13ccb53913f385b 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2171,6 +2171,7 @@ static void __init gather_bootmem_prealloc(void) */ if (hstate_is_gigantic(h)) adjust_managed_page_count(page, 1 << h->order); + cond_resched(); } } diff --git a/mm/mmap.c b/mm/mmap.c index f54959786573297473755db586e1a270aa29645d..9ba15d8242cc6b784507cef185bf1f2635797314 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1398,6 +1398,35 @@ static inline int mlock_future_check(struct mm_struct *mm, return 0; } +static inline u64 file_mmap_size_max(struct file *file, struct inode *inode) +{ + if (S_ISREG(inode->i_mode)) + return MAX_LFS_FILESIZE; + + if (S_ISBLK(inode->i_mode)) + return MAX_LFS_FILESIZE; + + /* Special "we do even unsigned file positions" case */ + if (file->f_mode & FMODE_UNSIGNED_OFFSET) + return 0; + + /* Yes, random drivers might want more. But I'm tired of buggy drivers */ + return ULONG_MAX; +} + +static inline bool file_mmap_ok(struct file *file, struct inode *inode, + unsigned long pgoff, unsigned long len) +{ + u64 maxsize = file_mmap_size_max(file, inode); + + if (maxsize && len > maxsize) + return false; + maxsize -= len; + if (pgoff > maxsize >> PAGE_SHIFT) + return false; + return true; +} + /* * The caller must hold down_write(¤t->mm->mmap_sem). */ @@ -1470,6 +1499,9 @@ unsigned long do_mmap(struct file *file, unsigned long addr, if (file) { struct inode *inode = file_inode(file); + if (!file_mmap_ok(file, inode, pgoff, len)) + return -EOVERFLOW; + switch (flags & MAP_TYPE) { case MAP_SHARED: if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE)) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 1345072dc0437060f925ffb8f381bf19272c7e20..c9f73d6365c6b841c06b9f340dc453f3c868fd4a 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3778,7 +3778,6 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, * orientated. */ if (!(alloc_flags & ALLOC_CPUSET) || (alloc_flags & ALLOC_NO_WATERMARKS)) { - ac->zonelist = node_zonelist(numa_node_id(), gfp_mask); ac->preferred_zoneref = first_zones_zonelist(ac->zonelist, ac->high_zoneidx, ac->nodemask); } diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 7b3865c18a9bbb5c646d6d441e76a56beb87af76..6b5f0bce0bd2ac40048a998f9f062d59087a0e53 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -543,7 +543,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size, } } - if (printk_ratelimit()) + if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit()) pr_warn("vmap allocation for size %lu failed: use vmalloc= to increase size\n", size); kfree(va); diff --git a/mm/vmscan.c b/mm/vmscan.c index 4daac9a339729769c8c0ee2f7d5912f76adf37c6..abcc8be856d1ecac00b80e63a9d7c38e71faa191 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1455,7 +1455,7 @@ int __isolate_lru_page(struct page *page, isolate_mode_t mode) return ret; mapping = page_mapping(page); - migrate_dirty = mapping && mapping->a_ops->migratepage; + migrate_dirty = !mapping || mapping->a_ops->migratepage; unlock_page(page); if (!migrate_dirty) return ret; diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 0a9222ef904ca410d74a47393e75e9f8c2739727..da3d373eb5bd3e67a8174ead8f12026dc62a3f7a 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -1923,7 +1923,8 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt, int off, pad = 0; unsigned int size_kern, match_size = mwt->match_size; - strlcpy(name, mwt->u.name, sizeof(name)); + if (strscpy(name, mwt->u.name, sizeof(name)) < 0) + return -EINVAL; if (state->buf_kern_start) dst = state->buf_kern_start + state->buf_kern_offset; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index c2339b865164f20b9ec921b753dd50e88b56fe48..f3a0ad14b454dfeb10b8983184cb9d931885dad6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1914,6 +1914,10 @@ static int do_setlink(const struct sk_buff *skb, const struct net_device_ops *ops = dev->netdev_ops; int err; + err = validate_linkmsg(dev, tb); + if (err < 0) + return err; + if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { struct net *net = rtnl_link_get_net(dev_net(dev), tb); if (IS_ERR(net)) { @@ -2234,10 +2238,6 @@ static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) goto errout; } - err = validate_linkmsg(dev, tb); - if (err < 0) - goto errout; - err = do_setlink(skb, dev, ifm, tb, ifname, 0); errout: return err; diff --git a/net/dccp/proto.c b/net/dccp/proto.c index ff3b058cf58ca5e5d21a8ea620052750bbe8376e..936dab12f99f2edff3d606a070b5b397e75a4651 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -280,9 +280,7 @@ int dccp_disconnect(struct sock *sk, int flags) dccp_clear_xmit_timers(sk); ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); - ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); dp->dccps_hc_rx_ccid = NULL; - dp->dccps_hc_tx_ccid = NULL; __skb_queue_purge(&sk->sk_receive_queue); __skb_queue_purge(&sk->sk_write_queue); diff --git a/net/ipc_router/ipc_router_fifo_xprt.c b/net/ipc_router/ipc_router_fifo_xprt.c index ae85fd1277ae47a6972871771b760e3b25c37aa9..c90534dac92397883bca86b3138605bf88d2ede3 100644 --- a/net/ipc_router/ipc_router_fifo_xprt.c +++ b/net/ipc_router/ipc_router_fifo_xprt.c @@ -255,7 +255,7 @@ static void xprt_read_data(struct work_struct *work) hdr_len = sizeof(struct rr_header_v1); while (1) { rx_avail = fifo_rx_avail(&xprtp->rx_pipe); - if (!rx_avail || (rx_avail < hdr_len)) + if (!rx_avail) break; fifo_rx_peak(&xprtp->rx_pipe, &hdr, 0, hdr_len); diff --git a/net/ipc_router/ipc_router_socket.c b/net/ipc_router/ipc_router_socket.c index a758a0902c174d829ec1f0dd9adefc4372e2967a..4e53861c4acc731d181536b1b014da8cd236657a 100644 --- a/net/ipc_router/ipc_router_socket.c +++ b/net/ipc_router/ipc_router_socket.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-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 @@ -146,6 +146,7 @@ static int msm_ipc_router_extract_msg(struct msghdr *m, return -EINVAL; } ctl_msg = (union rr_control_msg *)(temp->data); + memset(addr, 0x0, sizeof(*addr)); addr->family = AF_MSM_IPC; addr->address.addrtype = MSM_IPC_ADDR_ID; addr->address.addr.port_addr.node_id = ctl_msg->cli.node_id; @@ -154,6 +155,7 @@ static int msm_ipc_router_extract_msg(struct msghdr *m, return offset; } if (addr && (hdr->type == IPC_ROUTER_CTRL_CMD_DATA)) { + memset(addr, 0x0, sizeof(*addr)); addr->family = AF_MSM_IPC; addr->address.addrtype = MSM_IPC_ADDR_ID; addr->address.addr.port_addr.node_id = hdr->src_node_id; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index e1be24416c0e569989927a07e15a58b3c5554b70..a88dab33cdf64661efc32320f84e58c44f5eda00 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -979,6 +979,8 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) if (val == TCP_CA_UNSPEC) return -EINVAL; } else { + if (nla_len(nla) != sizeof(u32)) + return -EINVAL; val = nla_get_u32(nla); } if (type == RTAX_ADVMSS && val > 65535 - 40) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 5ddd64995e7387ebc00a80f6b8f52a354d5bbdaa..dd80276a820545833d9e3ec0f3a3f400d2fcaf4b 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -503,8 +503,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) int err; int copied; - WARN_ON_ONCE(sk->sk_family == AF_INET6); - err = -EAGAIN; skb = sock_dequeue_err_skb(sk); if (!skb) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c2ad59dd4a95f24c00537c12e54d9b63dfa7ba4d..f0fc83593e8fe8f386cc4cd300fcde8dfb71a17a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -582,8 +582,8 @@ static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, void tcp_rcv_space_adjust(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); + u32 copied; int time; - int copied; time = tcp_time_stamp - tp->rcvq_space.time; if (time < (tp->rcv_rtt_est.rtt >> 3) || tp->rcv_rtt_est.rtt == 0) @@ -605,12 +605,13 @@ void tcp_rcv_space_adjust(struct sock *sk) if (sysctl_tcp_moderate_rcvbuf && !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { - int rcvwin, rcvmem, rcvbuf; + int rcvmem, rcvbuf; + u64 rcvwin; /* minimal window to cope with packet losses, assuming * steady state. Add some cushion because of small variations. */ - rcvwin = (copied << 1) + 16 * tp->advmss; + rcvwin = ((u64)copied << 1) + 16 * tp->advmss; /* If rate increased by 25%, * assume slow start, rcvwin = 3 * copied @@ -630,12 +631,13 @@ void tcp_rcv_space_adjust(struct sock *sk) while (tcp_win_from_space(rcvmem) < tp->advmss) rcvmem += 128; - rcvbuf = min(rcvwin / tp->advmss * rcvmem, sysctl_tcp_rmem[2]); + do_div(rcvwin, tp->advmss); + rcvbuf = min_t(u64, rcvwin * rcvmem, sysctl_tcp_rmem[2]); if (rcvbuf > sk->sk_rcvbuf) { sk->sk_rcvbuf = rcvbuf; /* Make the window clamp follow along. */ - tp->window_clamp = rcvwin; + tp->window_clamp = tcp_win_from_space(rcvbuf); } } tp->rcvq_space.space = copied; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 71335ac6364d7679f206c65b538fcf867e6b8fac..0f457beefc099a0f6889e02f86ce8e9079470603 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1669,6 +1669,10 @@ int tcp_v4_rcv(struct sk_buff *skb) reqsk_put(req); goto discard_it; } + if (tcp_checksum_complete(skb)) { + reqsk_put(req); + goto csum_error; + } if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0b5a75bc257bd0f173a577e6488ce647d3f5caa6..ae5e38bf60da9f685763a5eec1da7aa297052aee 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -496,7 +496,8 @@ int ip6_forward(struct sk_buff *skb) send redirects to source routed frames. We don't send redirects to frames decapsulated from IPsec. */ - if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { + if (IP6CB(skb)->iif == dst->dev->ifindex && + opt->srcrt == 0 && !skb_sec_path(skb)) { struct in6_addr *target = NULL; struct inet_peer *peer; struct rt6_info *rt; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index a30e7e925c9b76eb06e5d992f67fcce0bd88d4a7..4b93ad4fe6d8d3a2b4295e3ef6aadf4b2ebe9d09 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1789,7 +1789,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns ret = 0; if (!ip6mr_new_table(net, v)) ret = -ENOMEM; - raw6_sk(sk)->ip6mr_table = v; + else + raw6_sk(sk)->ip6mr_table = v; rtnl_unlock(); return ret; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 52236be017d2b4e0dc51d68b66ff8c50cf6e8f39..984d48bbdd0658958361b51b55d02531d15bcff1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1540,6 +1540,12 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; bool ret; + if (netif_is_l3_master(skb->dev)) { + dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif); + if (!dev) + return; + } + if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n", dev->name); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0fbc5ba9cb197054c7f4718865442bd1a5c6970d..efe939dfafa277ee8e0595312b715e63445058ec 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1364,9 +1364,6 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, { struct rt6_info *rt6 = (struct rt6_info *)dst; - if (rt6->rt6i_flags & RTF_LOCAL) - return; - if (dst_metric_locked(dst, RTAX_MTU)) return; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ae0485d776f4911d943b9398e3a1d9d259ae6b49..fc7ca1e4690813cdfa6d3beb1422bf4ef1cc834d 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -659,7 +659,6 @@ static int ipip6_rcv(struct sk_buff *skb) if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6), !net_eq(tunnel->net, dev_net(tunnel->dev)))) goto out; - iph = ip_hdr(skb); err = IP_ECN_decapsulate(iph, skb); if (unlikely(err)) { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8efeff6b3eac0687afd646da66210806e15a9c84..ed5d6354c8e2ef10db746fb196152c007787edda 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1436,6 +1436,10 @@ static int tcp_v6_rcv(struct sk_buff *skb) reqsk_put(req); goto discard_it; } + if (tcp_checksum_complete(skb)) { + reqsk_put(req); + goto csum_error; + } if (unlikely(sk->sk_state != TCP_LISTEN)) { inet_csk_reqsk_queue_drop_and_put(sk, req); goto lookup; diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 4003b2806a68d5c23fd88ab84c6ae1f495cb6df5..d82f42799da5edaee29803494fbcca6af7475f60 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -124,7 +124,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) struct flowi6 *fl6 = &fl->u.ip6; int onlyproto = 0; const struct ipv6hdr *hdr = ipv6_hdr(skb); - u16 offset = sizeof(*hdr); + u32 offset = sizeof(*hdr); struct ipv6_opt_hdr *exthdr; const unsigned char *nh = skb_network_header(skb); u16 nhoff = IP6CB(skb)->nhoff; diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index cc306defcc1905b2079c9d3091a562e5f6c94b99..553d0ad4a2fac593d9b16e3ebbddeedf367dbe71 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1671,7 +1671,7 @@ static struct file *kcm_clone(struct socket *osock) __module_get(newsock->ops->owner); newsk = sk_alloc(sock_net(osock->sk), PF_KCM, GFP_KERNEL, - &kcm_proto, true); + &kcm_proto, false); if (!newsk) { sock_release(newsock); return ERR_PTR(-ENOMEM); diff --git a/net/key/af_key.c b/net/key/af_key.c index 15150b412930bb1dc1c8614d8aafc851cdd2f97f..3ba903ff2bb083531e93a95d8cfebf43a32a4259 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -437,6 +437,24 @@ static int verify_address_len(const void *p) return 0; } +static inline int sadb_key_len(const struct sadb_key *key) +{ + int key_bytes = DIV_ROUND_UP(key->sadb_key_bits, 8); + + return DIV_ROUND_UP(sizeof(struct sadb_key) + key_bytes, + sizeof(uint64_t)); +} + +static int verify_key_len(const void *p) +{ + const struct sadb_key *key = p; + + if (sadb_key_len(key) > key->sadb_key_len) + return -EINVAL; + + return 0; +} + static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx) { return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + @@ -533,16 +551,25 @@ static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void * return -EINVAL; if (ext_hdrs[ext_type-1] != NULL) return -EINVAL; - if (ext_type == SADB_EXT_ADDRESS_SRC || - ext_type == SADB_EXT_ADDRESS_DST || - ext_type == SADB_EXT_ADDRESS_PROXY || - ext_type == SADB_X_EXT_NAT_T_OA) { + switch (ext_type) { + case SADB_EXT_ADDRESS_SRC: + case SADB_EXT_ADDRESS_DST: + case SADB_EXT_ADDRESS_PROXY: + case SADB_X_EXT_NAT_T_OA: if (verify_address_len(p)) return -EINVAL; - } - if (ext_type == SADB_X_EXT_SEC_CTX) { + break; + case SADB_X_EXT_SEC_CTX: if (verify_sec_ctx_len(p)) return -EINVAL; + break; + case SADB_EXT_KEY_AUTH: + case SADB_EXT_KEY_ENCRYPT: + if (verify_key_len(p)) + return -EINVAL; + break; + default: + break; } ext_hdrs[ext_type-1] = (void *) p; } @@ -1111,14 +1138,12 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, key = ext_hdrs[SADB_EXT_KEY_AUTH - 1]; if (key != NULL && sa->sadb_sa_auth != SADB_X_AALG_NULL && - ((key->sadb_key_bits+7) / 8 == 0 || - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + key->sadb_key_bits == 0) return ERR_PTR(-EINVAL); key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; if (key != NULL && sa->sadb_sa_encrypt != SADB_EALG_NULL && - ((key->sadb_key_bits+7) / 8 == 0 || - (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) + key->sadb_key_bits == 0) return ERR_PTR(-EINVAL); x = xfrm_state_alloc(net); diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c5f2350a2b50e93ffc54ad9b7954023e00b9bb12..079b3c4267203589f9c516ddbcd8ca74c2299c73 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2390,8 +2390,10 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) struct ipvs_sync_daemon_cfg cfg; memset(&cfg, 0, sizeof(cfg)); - strlcpy(cfg.mcast_ifn, dm->mcast_ifn, - sizeof(cfg.mcast_ifn)); + ret = -EINVAL; + if (strscpy(cfg.mcast_ifn, dm->mcast_ifn, + sizeof(cfg.mcast_ifn)) <= 0) + goto out_dec; cfg.syncid = dm->syncid; ret = start_sync_thread(ipvs, &cfg, dm->state); } else { @@ -2429,12 +2431,19 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) } } + if ((cmd == IP_VS_SO_SET_ADD || cmd == IP_VS_SO_SET_EDIT) && + strnlen(usvc.sched_name, IP_VS_SCHEDNAME_MAXLEN) == + IP_VS_SCHEDNAME_MAXLEN) { + ret = -EINVAL; + goto out_unlock; + } + /* Check for valid protocol: TCP or UDP or SCTP, even for fwmark!=0 */ if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP && usvc.protocol != IPPROTO_SCTP) { - pr_err("set_ctl: invalid protocol: %d %pI4:%d %s\n", + pr_err("set_ctl: invalid protocol: %d %pI4:%d\n", usvc.protocol, &usvc.addr.ip, - ntohs(usvc.port), usvc.sched_name); + ntohs(usvc.port)); ret = -EFAULT; goto out_unlock; } @@ -2863,7 +2872,7 @@ static const struct nla_policy ip_vs_cmd_policy[IPVS_CMD_ATTR_MAX + 1] = { static const struct nla_policy ip_vs_daemon_policy[IPVS_DAEMON_ATTR_MAX + 1] = { [IPVS_DAEMON_ATTR_STATE] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_MCAST_IFN] = { .type = NLA_NUL_STRING, - .len = IP_VS_IFNAME_MAXLEN }, + .len = IP_VS_IFNAME_MAXLEN - 1 }, [IPVS_DAEMON_ATTR_SYNC_ID] = { .type = NLA_U32 }, [IPVS_DAEMON_ATTR_SYNC_MAXLEN] = { .type = NLA_U16 }, [IPVS_DAEMON_ATTR_MCAST_GROUP] = { .type = NLA_U32 }, @@ -2881,7 +2890,7 @@ static const struct nla_policy ip_vs_svc_policy[IPVS_SVC_ATTR_MAX + 1] = { [IPVS_SVC_ATTR_PORT] = { .type = NLA_U16 }, [IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 }, [IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING, - .len = IP_VS_SCHEDNAME_MAXLEN }, + .len = IP_VS_SCHEDNAME_MAXLEN - 1 }, [IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING, .len = IP_VS_PENAME_MAXLEN }, [IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY, diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index ffb9e8ada899b770293744ed0da5bebba4b2166e..e02fed784cd0adc0e69f84611dde68d8a32d05cf 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -444,14 +444,17 @@ static int nf_log_proc_dostring(struct ctl_table *table, int write, rcu_assign_pointer(net->nf.nf_loggers[tindex], logger); mutex_unlock(&nf_log_mutex); } else { + struct ctl_table tmp = *table; + + tmp.data = buf; mutex_lock(&nf_log_mutex); logger = nft_log_dereference(net->nf.nf_loggers[tindex]); if (!logger) - table->data = "NONE"; + strlcpy(buf, "NONE", sizeof(buf)); else - table->data = logger->name; - r = proc_dostring(table, write, buffer, lenp, ppos); + strlcpy(buf, logger->name, sizeof(buf)); mutex_unlock(&nf_log_mutex); + r = proc_dostring(&tmp, write, buffer, lenp, ppos); } return r; diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index 0dd5c695482f64b248de0906fcbbd1dcb8df6364..9d593ecd8e8701a004305a88d371d05d4753b192 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -185,7 +185,8 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv) switch (regs.verdict.code) { case NFT_JUMP: - BUG_ON(stackptr >= NFT_JUMP_STACK_SIZE); + if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE)) + return NF_DROP; jumpstack[stackptr].chain = chain; jumpstack[stackptr].rule = rule; jumpstack[stackptr].rulenum = rulenum; diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index d2141a6a268d4d3b1902943ce3495b8d1cf09a48..7f51f6da1ad29efc824553a10a8fe73c6905c613 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -1191,11 +1191,6 @@ static void get_dev_and_dir(const struct sk_buff *skb, par->hooknum, __func__); BUG(); } - if (unlikely(!(*el_dev)->name)) { - pr_err("qtaguid[%d]: %s(): no dev->name?!!\n", - par->hooknum, __func__); - BUG(); - } if (skb->dev && *el_dev != skb->dev) { MT_DEBUG("qtaguid[%d]: skb->dev=%pK %s vs par->%s=%pK %s\n", par->hooknum, skb->dev, skb->dev->name, diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 3ec89bb64a83b9e800167844c5ad0fa019a26130..8ab2b53325c95c7223de9bc1922b91508bdf12ab 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -4299,7 +4299,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, goto out; if (po->tp_version >= TPACKET_V3 && req->tp_block_size <= - BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv)) + BLK_PLUS_PRIV((u64)req_u->req3.tp_sizeof_priv) + sizeof(struct tpacket3_hdr)) goto out; if (unlikely(req->tp_frame_size < po->tp_hdrlen + po->tp_reserve)) diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 289af6f9bb3b2b0712514d6e533d351cce288062..8b2e87e4493e28fb3d138e9ef141fc8d1ee9a804 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -55,22 +55,22 @@ static void tcf_simp_release(struct tc_action *a, int bind) kfree(d->tcfd_defdata); } -static int alloc_defdata(struct tcf_defact *d, char *defdata) +static int alloc_defdata(struct tcf_defact *d, const struct nlattr *defdata) { d->tcfd_defdata = kzalloc(SIMP_MAX_DATA, GFP_KERNEL); if (unlikely(!d->tcfd_defdata)) return -ENOMEM; - strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); return 0; } -static void reset_policy(struct tcf_defact *d, char *defdata, +static void reset_policy(struct tcf_defact *d, const struct nlattr *defdata, struct tc_defact *p) { spin_lock_bh(&d->tcf_lock); d->tcf_action = p->action; memset(d->tcfd_defdata, 0, SIMP_MAX_DATA); - strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); + nla_strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA); spin_unlock_bh(&d->tcf_lock); } @@ -89,7 +89,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, struct tcf_defact *d; bool exists = false; int ret = 0, err; - char *defdata; if (nla == NULL) return -EINVAL; @@ -112,8 +111,6 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return -EINVAL; } - defdata = nla_data(tb[TCA_DEF_DATA]); - if (!exists) { ret = tcf_hash_create(tn, parm->index, est, a, &act_simp_ops, bind, false); @@ -121,7 +118,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, return ret; d = to_defact(*a); - ret = alloc_defdata(d, defdata); + ret = alloc_defdata(d, tb[TCA_DEF_DATA]); if (ret < 0) { tcf_hash_cleanup(*a, est); return ret; @@ -135,7 +132,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, if (!ovr) return -EEXIST; - reset_policy(d, defdata, parm); + reset_policy(d, tb[TCA_DEF_DATA], parm); } if (ret == ACT_P_CREATED) diff --git a/net/sctp/transport.c b/net/sctp/transport.c index ce54dce13ddb2cba959bca080b06f9285f2fe16d..03d71cd97ec08f7c14797485e326476494ce43ce 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -608,7 +608,7 @@ unsigned long sctp_transport_timeout(struct sctp_transport *trans) trans->state != SCTP_PF) timeout += trans->hbinterval; - return timeout; + return max_t(unsigned long, timeout, HZ / 5); } /* Reset transport variables to their initial values */ diff --git a/net/wireless/core.c b/net/wireless/core.c index c88874f2f6b196d6beaac12696f0beea50bc5d67..0a67d80d24709c6892e89ba2c7f4eed741ee3209 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -949,6 +949,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) nl80211_notify_iface(rdev, wdev, NL80211_CMD_DEL_INTERFACE); list_del_rcu(&wdev->list); + synchronize_rcu(); rdev->devlist_generation++; switch (wdev->iftype) { diff --git a/net/wireless/db.txt b/net/wireless/db.txt index d82f8b4c814c3e336026810860d39a73781a1602..94fe1baa1190a5d97e7d10f332cd9e8ae13de09e 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -653,7 +653,7 @@ country LB: DFS-FCC country LC: DFS-FCC (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), AUTO-BW + (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (30), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS (5735 - 5815 @ 80), (30) @@ -1138,10 +1138,11 @@ country TR: DFS-ETSI (5490 - 5730 @ 160), (30), DFS (5735 - 5875 @ 80), (14) -country TT: +country TT: DFS-FCC (2402 - 2482 @ 40), (20) - (5170 - 5330 @ 160), (24) - (5490 - 5730 @ 160), (24) + (5170 - 5250 @ 80), (24) + (5250 - 5330 @ 80), (24), DFS + (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) # 60 gHz band channels 1-3, FCC (57240 - 63720 @ 2160), (40) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 0f101f73cf09bb940af1ed908f93f091aa1d270b..b1cdd50a5d801ee8d15fbeb77227235f1b86363c 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -8,6 +8,7 @@ squote := ' empty := space := $(empty) $(empty) space_escape := _-_SPACE_-_ +pound := \# ### # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o @@ -298,11 +299,11 @@ endif # Replace >$< with >$$< to preserve $ when reloading the .cmd file # (needed for make) -# Replace >#< with >\#< to avoid starting a comment in the .cmd file +# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file # (needed for make) # Replace >'< with >'\''< to be able to enclose the whole string in '...' # (needed for the shell) -make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) +make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) # Find any prerequisites that is newer than target or that does not exist. # PHONY targets skipped in both cases. diff --git a/scripts/Makefile.build b/scripts/Makefile.build index a9c1da505f0226e0020704ba0c632fbd2e934d8a..fcffce43983487173fed5c36f8ee9d7120a04ade 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -296,6 +296,9 @@ objtool_args = check ifndef CONFIG_FRAME_POINTER objtool_args += --no-fp endif +ifdef CONFIG_GCOV_KERNEL +objtool_args += --no-unreachable +endif # 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory # 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 297b079ae4d9f0decbabc76d0f7e833e20aadadb..27aac273205bacf5456680a914a024bbf36960e0 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -745,7 +745,7 @@ int conf_write(const char *name) struct menu *menu; const char *basename; const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; + char dirname[PATH_MAX+1], tmpname[PATH_MAX+22], newname[PATH_MAX+8]; char *env; dirname[0] = 0; diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 7bf8b005a178c4529d5e69c1d3e8ed1bf4cedc94..1e6f23f77f155f046b5d33ba1800a6ab9633cafa 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -389,14 +389,10 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, result = ima_protect_xattr(dentry, xattr_name, xattr_value, xattr_value_len); if (result == 1) { - bool digsig; - if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) return -EINVAL; - digsig = (xvalue->type == EVM_IMA_XATTR_DIGSIG); - if (!digsig && (ima_appraise & IMA_APPRAISE_ENFORCE)) - return -EPERM; - ima_reset_appraise_flags(d_backing_inode(dentry), digsig); + ima_reset_appraise_flags(d_backing_inode(dentry), + (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); result = 0; } return result; diff --git a/security/pfe/pfk_ice.c b/security/pfe/pfk_ice.c index e1d01004d50e9c018b782b88e7ad5e8ecd613a80..a86042c98e1f6b171b04d78b8bdba63a8f6583d4 100644 --- a/security/pfe/pfk_ice.c +++ b/security/pfe/pfk_ice.c @@ -138,9 +138,10 @@ int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt, if (ret1) pr_err("%s: Invalidate Key Error: %d\n", __func__, ret1); - goto out; } - ret = qcom_ice_setup_ice_hw((const char *)s_type, false); + ret1 = qcom_ice_setup_ice_hw((const char *)s_type, false); + if (ret1) + pr_err("%s: Error %d disabling clocks\n", __func__, ret1); out: return ret; diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 0af1132a869e843dd931391347923bbf15c15626..56af7308a2fd9a666399c951b1bbfbc338dc8e3f 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -748,8 +748,10 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, return err; strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (apcm == NULL) + if (apcm == NULL) { + snd_device_free(chip->card, pcm); return -ENOMEM; + } apcm->chip = chip; apcm->pcm = pcm; apcm->codec = codec; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index b3851b99112037ab63c25b748cabf0ace1f7b345..6b5804e063a3ae073829c1419e46f163ad265e51 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -851,6 +851,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 39cd35f6a6dfc3c40e3aae6515a1d7751b7667d4..f03a1430a3cbf421d2b571ecca86872dd96e1f3a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -333,6 +333,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) case 0x10ec0236: case 0x10ec0255: case 0x10ec0256: + case 0x10ec0257: case 0x10ec0282: case 0x10ec0283: case 0x10ec0286: @@ -2447,6 +2448,7 @@ static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), + SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), @@ -2663,6 +2665,7 @@ enum { ALC269_TYPE_ALC298, ALC269_TYPE_ALC255, ALC269_TYPE_ALC256, + ALC269_TYPE_ALC257, ALC269_TYPE_ALC225, ALC269_TYPE_ALC294, ALC269_TYPE_ALC700, @@ -2695,6 +2698,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) case ALC269_TYPE_ALC298: case ALC269_TYPE_ALC255: case ALC269_TYPE_ALC256: + case ALC269_TYPE_ALC257: case ALC269_TYPE_ALC225: case ALC269_TYPE_ALC294: case ALC269_TYPE_ALC700: @@ -4470,7 +4474,6 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec, struct alc_spec *spec = codec->spec; if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->shutup = alc_no_shutup; /* reduce click noise */ spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; codec->power_save_node = 0; /* avoid click noises */ @@ -4832,6 +4835,13 @@ static void alc280_fixup_hp_9480m(struct hda_codec *codec, /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" +static void alc_fixup_thinkpad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + alc_fixup_no_shutup(codec, fix, action); /* reduce click noise */ + hda_fixup_thinkpad_acpi(codec, fix, action); +} + /* for dell wmi mic mute led */ #include "dell_wmi_helper.c" @@ -5347,7 +5357,7 @@ static const struct hda_fixup alc269_fixups[] = { }, [ALC269_FIXUP_THINKPAD_ACPI] = { .type = HDA_FIXUP_FUNC, - .v.func = hda_fixup_thinkpad_acpi, + .v.func = alc_fixup_thinkpad_acpi, .chained = true, .chain_id = ALC269_FIXUP_SKU_IGNORE, }, @@ -6375,6 +6385,10 @@ static int patch_alc269(struct hda_codec *codec) spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ break; + case 0x10ec0257: + spec->codec_variant = ALC269_TYPE_ALC257; + spec->gen.mixer_nid = 0; + break; case 0x10ec0225: case 0x10ec0295: case 0x10ec0299: @@ -7361,6 +7375,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269), HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262), HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268), diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c index 85962657aabe02bc72db1ba50a3f0b195e05da08..517963ef484726676e4a0aa15e715ec6c7cd49f8 100644 --- a/sound/soc/cirrus/edb93xx.c +++ b/sound/soc/cirrus/edb93xx.c @@ -67,7 +67,7 @@ static struct snd_soc_dai_link edb93xx_dai = { .cpu_dai_name = "ep93xx-i2s", .codec_name = "spi0.0", .codec_dai_name = "cs4271-hifi", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &edb93xx_ops, }; diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c index 934f8aefdd90b8f94beda83dc82393d4091e4aec..0dc3852c46219f1aca029a08b7a46681d0b0a389 100644 --- a/sound/soc/cirrus/ep93xx-i2s.c +++ b/sound/soc/cirrus/ep93xx-i2s.c @@ -51,7 +51,9 @@ #define EP93XX_I2S_WRDLEN_24 (1 << 0) #define EP93XX_I2S_WRDLEN_32 (2 << 0) -#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */ +#define EP93XX_I2S_RXLINCTRLDATA_R_JUST BIT(1) /* Right justify */ + +#define EP93XX_I2S_TXLINCTRLDATA_R_JUST BIT(2) /* Right justify */ #define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */ #define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */ @@ -170,25 +172,25 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai); - unsigned int clk_cfg, lin_ctrl; + unsigned int clk_cfg; + unsigned int txlin_ctrl = 0; + unsigned int rxlin_ctrl = 0; clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG); - lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: clk_cfg |= EP93XX_I2S_CLKCFG_REL; - lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; break; case SND_SOC_DAIFMT_LEFT_J: clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; - lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; break; case SND_SOC_DAIFMT_RIGHT_J: clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; - lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST; + rxlin_ctrl |= EP93XX_I2S_RXLINCTRLDATA_R_JUST; + txlin_ctrl |= EP93XX_I2S_TXLINCTRLDATA_R_JUST; break; default: @@ -213,32 +215,32 @@ static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: /* Negative bit clock, lrclk low on left word */ - clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL); + clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS); break; case SND_SOC_DAIFMT_NB_IF: /* Negative bit clock, lrclk low on right word */ clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP; - clk_cfg |= EP93XX_I2S_CLKCFG_REL; + clk_cfg |= EP93XX_I2S_CLKCFG_LRS; break; case SND_SOC_DAIFMT_IB_NF: /* Positive bit clock, lrclk low on left word */ clk_cfg |= EP93XX_I2S_CLKCFG_CKP; - clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; + clk_cfg &= ~EP93XX_I2S_CLKCFG_LRS; break; case SND_SOC_DAIFMT_IB_IF: /* Positive bit clock, lrclk low on right word */ - clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL; + clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_LRS; break; } /* Write new register values */ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg); ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg); - ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl); - ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl); + ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, rxlin_ctrl); + ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, txlin_ctrl); return 0; } diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c index 98089df08df62e6c738f95b08c204be10970598e..c6737a573bc086d948a4595ea6b0ebf7b5b11ca6 100644 --- a/sound/soc/cirrus/snappercl15.c +++ b/sound/soc/cirrus/snappercl15.c @@ -72,7 +72,7 @@ static struct snd_soc_dai_link snappercl15_dai = { .codec_dai_name = "tlv320aic23-hifi", .codec_name = "tlv320aic23-codec.0-001a", .platform_name = "ep93xx-i2s", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, .ops = &snappercl15_ops, }; diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index a086c35f91bb94bfe879ebc743fc81177e787118..79a9fdf94d3840df55b207b2c839e2c8e9af47e5 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -274,7 +274,6 @@ int sst_dma_new(struct sst_dsp *sst) struct sst_pdata *sst_pdata = sst->pdata; struct sst_dma *dma; struct resource mem; - const char *dma_dev_name; int ret = 0; if (sst->pdata->resindex_dma_base == -1) @@ -285,7 +284,6 @@ int sst_dma_new(struct sst_dsp *sst) * is attached to the ADSP IP. */ switch (sst->pdata->dma_engine) { case SST_DMA_TYPE_DW: - dma_dev_name = "dw_dmac"; break; default: dev_err(sst->dev, "error: invalid DMA engine %d\n", diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 172af541cbddc7c209ebf0c9edfa572fe2cca503..682c207628e0392e8dbbd35f06eeda315a2adba5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -427,6 +427,8 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, static void dapm_kcontrol_free(struct snd_kcontrol *kctl) { struct dapm_kcontrol_data *data = snd_kcontrol_chip(kctl); + + list_del(&data->paths); kfree(data->wlist); kfree(data); } diff --git a/sound/usb/usb_audio_qmi_svc.c b/sound/usb/usb_audio_qmi_svc.c index ce1f0ad8e5c076314fee494991957e51c6db8092..fe29aed3766010c1270bc7f33d11534e0b90b6aa 100644 --- a/sound/usb/usb_audio_qmi_svc.c +++ b/sound/usb/usb_audio_qmi_svc.c @@ -110,8 +110,8 @@ struct uaudio_qmi_dev { unsigned long curr_xfer_buf_iova; /* bit fields representing pcm card enabled */ unsigned long card_slot; - /* cache event ring phys addr */ - u64 er_phys_addr; + /* indicate event ring mapped or not */ + bool er_mapped; }; static struct uaudio_qmi_dev *uaudio_qdev; @@ -295,7 +295,7 @@ static unsigned long uaudio_iommu_map(enum mem_type mtype, phys_addr_t pa, case MEM_EVENT_RING: va = IOVA_BASE; /* er already mapped */ - if (uaudio_qdev->er_phys_addr == pa) + if (uaudio_qdev->er_mapped) map = false; break; case MEM_XFER_RING: @@ -407,8 +407,8 @@ static void uaudio_iommu_unmap(enum mem_type mtype, unsigned long va, switch (mtype) { case MEM_EVENT_RING: - if (uaudio_qdev->er_phys_addr) - uaudio_qdev->er_phys_addr = 0; + if (uaudio_qdev->er_mapped) + uaudio_qdev->er_mapped = false; else unmap = false; break; @@ -637,7 +637,7 @@ static int prepare_qmi_response(struct snd_usb_substream *subs, uaudio_qdev->sid); resp->xhci_mem_info.evt_ring.pa = dma; resp->xhci_mem_info.evt_ring.size = PAGE_SIZE; - uaudio_qdev->er_phys_addr = xhci_pa; + uaudio_qdev->er_mapped = true; resp->speed_info = get_speed_info(subs->dev->speed); if (resp->speed_info == USB_AUDIO_DEVICE_SPEED_INVALID_V01) diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index c278f276c9b32b125ed2506aafa0a39ae2716c7f..aea30afeddb8879e081ef81b5b5c2564ba1122be 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -104,7 +104,7 @@ #define X86_FEATURE_EXTD_APICID ( 3*32+26) /* has extended APICID (8 bits) */ #define X86_FEATURE_AMD_DCM ( 3*32+27) /* multi-node processor */ #define X86_FEATURE_APERFMPERF ( 3*32+28) /* APERFMPERF */ -#define X86_FEATURE_EAGER_FPU ( 3*32+29) /* "eagerfpu" Non lazy FPU restore */ +/* free, was #define X86_FEATURE_EAGER_FPU ( 3*32+29) * "eagerfpu" Non lazy FPU restore */ #define X86_FEATURE_NONSTOP_TSC_S3 ( 3*32+30) /* TSC doesn't stop in S3 state */ /* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */ diff --git a/tools/build/Build.include b/tools/build/Build.include index 1dcb95e76f70f7ec30b964d44c1c28586fa739a2..b8165545ddf61c3819a08649f9dc8f8dc9f9da7a 100644 --- a/tools/build/Build.include +++ b/tools/build/Build.include @@ -12,6 +12,7 @@ # Convenient variables comma := , squote := ' +pound := \# ### # Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o @@ -43,11 +44,11 @@ echo-cmd = $(if $($(quiet)cmd_$(1)),\ ### # Replace >$< with >$$< to preserve $ when reloading the .cmd file # (needed for make) -# Replace >#< with >\#< to avoid starting a comment in the .cmd file +# Replace >#< with >$(pound)< to avoid starting a comment in the .cmd file # (needed for make) # Replace >'< with >'\''< to be able to enclose the whole string in '...' # (needed for the shell) -make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) +make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) ### # Find any prerequisites that is newer than target or that does not exist. diff --git a/tools/objtool/.gitignore b/tools/objtool/.gitignore index d3102c865a95e0ea82c6979c9acb72c50a61fce1..914cff12899b655f760b0c5d79d3e029a3d09168 100644 --- a/tools/objtool/.gitignore +++ b/tools/objtool/.gitignore @@ -1,3 +1,3 @@ -arch/x86/insn/inat-tables.c +arch/x86/lib/inat-tables.c objtool fixdep diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index e6acc281dd3757dbd03ba32c69a89b76ed690800..8ae824dbfca3fea24889064aca1fd46d60f0cbf2 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -35,7 +35,7 @@ CFLAGS += -Wall -Werror $(WARNINGS) -fomit-frame-pointer -O2 -g $(INCLUDES) LDFLAGS += -lelf $(LIBSUBCMD) # Allow old libelf to be used: -elfshdr := $(shell echo '\#include ' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) +elfshdr := $(shell echo '$(pound)include ' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr) CFLAGS += $(if $(elfshdr),,-DLIBELF_USE_DEPRECATED) AWK = awk diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d2c6cdd9d42b72a194d913bdc1840d5ff72bb281..8bec05365aaef69f5f16e0a3b78d41476cfd6866 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -253,6 +253,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || (strncmp(name, "[vdso]", 6) == 0) || + (strncmp(name, "[vdso32]", 8) == 0) || + (strncmp(name, "[vdsox32]", 9) == 0) || (strncmp(name, "[vsyscall]", 10) == 0)) { m->kmod = false; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index cac39532c0574ae005ba9620987a2b30b7f73e7a..d27715ff9a5f5a3ef9b3da4ca3fd79188a7bc47a 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -112,6 +112,7 @@ struct intel_pt_decoder { bool have_cyc; bool fixup_last_mtc; bool have_last_ip; + enum intel_pt_param_flags flags; uint64_t pos; uint64_t last_ip; uint64_t ip; @@ -215,6 +216,8 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) decoder->data = params->data; decoder->return_compression = params->return_compression; + decoder->flags = params->flags; + decoder->period = params->period; decoder->period_type = params->period_type; @@ -1012,6 +1015,15 @@ static int intel_pt_walk_insn(struct intel_pt_decoder *decoder, return err; } +static inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder, + struct intel_pt_insn *intel_pt_insn, + uint64_t ip, int err) +{ + return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err && + intel_pt_insn->branch == INTEL_PT_BR_INDIRECT && + ip == decoder->ip + intel_pt_insn->length; +} + static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) { struct intel_pt_insn intel_pt_insn; @@ -1024,7 +1036,8 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); if (err == INTEL_PT_RETURN) return 0; - if (err == -EAGAIN) { + if (err == -EAGAIN || + intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) { if (decoder->set_fup_tx_flags) { decoder->set_fup_tx_flags = false; decoder->tx_flags = decoder->fup_tx_flags; @@ -1034,7 +1047,7 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) decoder->state.flags = decoder->fup_tx_flags; return 0; } - return err; + return -EAGAIN; } decoder->set_fup_tx_flags = false; if (err) @@ -1298,7 +1311,6 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder) { intel_pt_log("ERROR: Buffer overflow\n"); intel_pt_clear_tx_flags(decoder); - decoder->have_tma = false; decoder->cbr = 0; decoder->timestamp_insn_cnt = 0; decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; @@ -1517,7 +1529,6 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) case INTEL_PT_PSB: case INTEL_PT_TSC: case INTEL_PT_TMA: - case INTEL_PT_CBR: case INTEL_PT_MODE_TSX: case INTEL_PT_BAD: case INTEL_PT_PSBEND: @@ -1526,6 +1537,10 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) decoder->pkt_step = 0; return -ENOENT; + case INTEL_PT_CBR: + intel_pt_calc_cbr(decoder); + break; + case INTEL_PT_OVF: return intel_pt_overflow(decoder); diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 9ae4df1dcedcf86323f48358425a4a6020b610b6..2fe8f4c5aeb52e29075db01c588d0ba0f3cbc85c 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -53,6 +53,14 @@ enum { INTEL_PT_ERR_MAX, }; +enum intel_pt_param_flags { + /* + * FUP packet can contain next linear instruction pointer instead of + * current linear instruction pointer. + */ + INTEL_PT_FUP_WITH_NLIP = 1 << 0, +}; + struct intel_pt_state { enum intel_pt_sample_type type; int err; @@ -92,6 +100,7 @@ struct intel_pt_params { unsigned int mtc_period; uint32_t tsc_ctc_ratio_n; uint32_t tsc_ctc_ratio_d; + enum intel_pt_param_flags flags; }; struct intel_pt_decoder; diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index 7528ae4f7e28e1d419c699759125c979e8dc1397..e5c6caf913f3ea9fbcfd5365b56dfa1be21572c2 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c @@ -281,7 +281,7 @@ static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf, if (len < offs) return INTEL_PT_NEED_MORE_BYTES; byte = buf[offs++]; - payload |= (byte >> 1) << shift; + payload |= ((uint64_t)byte >> 1) << shift; } packet->type = INTEL_PT_CYC; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index b1161d725ce998480ac47492087208a05ff200a0..d40ab4cf8932303ed5b2ad2b8375f87dba0c238a 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -752,6 +752,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, unsigned int queue_nr) { struct intel_pt_params params = { .get_trace = 0, }; + struct perf_env *env = pt->machine->env; struct intel_pt_queue *ptq; ptq = zalloc(sizeof(struct intel_pt_queue)); @@ -832,6 +833,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, } } + if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18)) + params.flags |= INTEL_PT_FUP_WITH_NLIP; + ptq->decoder = intel_pt_decoder_new(¶ms); if (!ptq->decoder) goto out_free; @@ -1344,6 +1348,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (intel_pt_is_switch_ip(ptq, state->to_ip)) { switch (ptq->switch_state) { + case INTEL_PT_SS_NOT_TRACING: case INTEL_PT_SS_UNKNOWN: case INTEL_PT_SS_EXPECTING_SWITCH_IP: err = intel_pt_next_tid(pt, ptq); diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index 19edc1a7a232269726a55992200685f77675a9b9..7ea4438b801ddb700f070c3e6d843305434185d0 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -92,3 +92,5 @@ ifneq ($(silent),1) QUIET_INSTALL = @printf ' INSTALL %s\n' $1; endif endif + +pound := \#