Merge "security: pfk: use page_mapping to avoid wrong memory access"
diff --git a/Documentation/devicetree/bindings/arm/msm/msm.txt b/Documentation/devicetree/bindings/arm/msm/msm.txt
index b2640da..74e90e6 100644
--- a/Documentation/devicetree/bindings/arm/msm/msm.txt
+++ b/Documentation/devicetree/bindings/arm/msm/msm.txt
@@ -101,6 +101,9 @@
- SDA670
compatible = "qcom,sda670"
+- SXR1130
+ compatible = "qcom,sxr1130"
+
- MSM8952
compatible = "qcom,msm8952"
@@ -321,6 +324,8 @@
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 90bc368..c4ada7c 100644
--- a/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
+++ b/Documentation/devicetree/bindings/arm/msm/qcom,llcc.txt
@@ -86,7 +86,8 @@
compatible devices:
qcom,sdm845-llcc,
- qcom,sdm670-llcc
+ qcom,sdm670-llcc,
+ qcom,qcs605-llcc
Example:
diff --git a/Documentation/devicetree/bindings/input/qti-haptics.txt b/Documentation/devicetree/bindings/input/qti-haptics.txt
new file mode 100644
index 0000000..2c4f4f0
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qti-haptics.txt
@@ -0,0 +1,202 @@
+Qualcomm Technologies, Inc. Haptics driver
+
+Haptics peripheral in QTI PMICs can support different type of actuators or
+vibrators:
+ 1) Eccentric Rotation Mass (ERM);
+ 2) Linear Resonant Actuator (LRA).
+This binding document describes the properties for this module.
+
+Properties:
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: It can be one of the following:
+ "qcom,haptics",
+ "qcom,pm660-haptics",
+ "qcom,pm8150b-haptics".
+
+- reg
+ Usage: required
+ Value type: <u32>
+ Definition: Base address of haptics peripheral.
+
+- interrupts
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Peripheral interrupt specifier.
+
+- interrupt-names
+ Usage: required
+ Value type: <stringlist>
+ Definition: Interrupt names. This list must match up 1-to-1 with the
+ interrupts specified in the 'interrupts' property. Following
+ interrupts are required: "hap_play_irq", "hap_sc_irq".
+
+- qcom,actuator-type
+ Usage: optional
+ Value type: <string>
+ Definition: Specifies the type of the actuator connected on the output of
+ haptics module. Allowed values: "erm", "lra". If this is
+ not specified, then LRA type will be used by default.
+
+- qcom,vmax-mv
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the maximum allowed output voltage in millivolts
+ for the actuator. Value specified here will be rounded
+ off to the closest multiple of 116 mV. Allowed values:
+ 0 to 3596. If this is not specified, then 1800 mV will be
+ used by default.
+
+- qcom,ilim-ma
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the maximum allowed output current in mA for the
+ actuator. Allowed values: 400 or 800. If this is not
+ specified, 400 mA will be used by default.
+
+- qcom,play-rate-us
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the period at which each sample of the 8-byte waveform
+ registers is played. For ERM, this period is flexible and it
+ can be chosen based on the desired shape of the pattern.
+ For LRA, it should be set equal to the resonance period
+ specified in the LRA actuator datasheet. Allowed values are:
+ 0 to 20475. If this is not specified, 5715us play rate is used.
+
+- qcom,external-waveform-source
+ Usage: optional
+ Value type: <string>
+ Definition: The haptics module supports to play with internal constant
+ Vmax strength or play with patterns specified in its internal
+ 8-bytes waveform buffer. It can also play with the audio
+ LINE-IN signal or PWM waveform coming from LINE-IN/PWM pin.
+ This property specify the kind of the waveform resources
+ on the LINE-IN/PWM pins. Allowed values are: "audio", "pwm".
+ If this is not specified, internal signals (Vmax or buffer)
+ will be selected according to the requriement of the playing
+ waveforms.
+
+- vdd-supply
+ Usage: optional
+ Value type: <phandle>
+ Definition: Specifies the phandle of the regulator device which supplies
+ haptics module through VDD_HAP pin. This is only needed if VDD_HAP
+ is supplied from an external boost regulator instead of VPH_PWR.
+
+Following properties are specific only when LRA actuator is used:
+
+- qcom,lra-resonance-sig-shape
+ Usage: optional
+ Value type: <string>
+ Definition: Specifies the shape of the LRA resonance drive signal. Allowed
+ values: "sine", "square". If this is not specified, sinusoid
+ resonance driver signal is used.
+
+- qcom,lra-allow-variable-play-rate
+ Usage: optional
+ Value type: <empty>
+ Definition: If specified, "qcom,wf-play-rate-us" for LRA defined in each
+ effect could be different with the resonance period of the
+ LRA actuator.
+
+- qcom,lra-auto-resonance-mode
+ Usage: optional
+ Value type: <string>
+ Definition: Specifies the auto resonance technique for LRA. Allowed values are:
+ "zxd": zero crossing based discontinuous method;
+ "qwd": quarter wave drive method;
+
+Following properties could be specified in child nodes for defining vibrating
+waveforms/effects:
+
+- qcom,effect-id
+ Usage: required
+ Value type: <u32>
+ Definition: Specifies the effect ID that the client can request to play the
+ corresponding waveform defined in this child node. The ID is
+ normaly defined and sent from userspace for certain user
+ notification event.
+
+- qcom,wf-pattern
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Specifies the waveform pattern in a byte array that will be
+ played for the effect-id. The bit fields of each byte are:
+ [7]: drive direction, 0 - forward; 1 - reverse
+ [6]: overdrive, 0 -- 1x drive; 1 -- 2x drive
+ [5:1]: waveform amplitude
+ [0]: reserved.
+
+- qcom,wf-play-rate-us
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the play period in microseconds for each byte pattern.
+ Allowed values are: 0 to 20475. For LRA actuator, if
+ "qcom,lra-allow-variable-play-rate" is defined, it could be
+ set to other values not equal to the resonance period of the
+ LRA actuator.
+
+- qcom,wf-repeat-count
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the repeat times for the waveform pattern. Allowed
+ values are: 1, 2, 4, 8, 16, 32, 64, 128.
+
+- qcom,wf-s-repeat-count
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the repeat times for each sample defined in
+ qcom,wf-pattern. Allowed values are: 1, 2, 4, 8.
+
+- qcom,wf-brake-pattern
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition: Specifies the brake pattern with 4 elements used to enable the
+ internal reverse braking. Allowed values for each element are:
+ 0: no brake
+ 1: brake with (Vmax / 2) strength
+ 2: brake with Vmax strength
+ 3: brake with (2 * Vmax) strength
+ If this property is specified with an array of non-zero values,
+ then the brake pattern is applied at the end of the playing
+ waveform.
+
+- qcom,lra-auto-resonance-disable
+ Usage: optional
+ Value type: <empty>
+ Definition: If specified, the hardware feature of LRA auto resonance detection
+ is disabled.
+
+Example:
+ qcom,haptics@c000 {
+ compatible = "qcom,haptics";
+ reg = <0xc000 0x100>;
+ interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>,
+ <0x3 0xc0 0x1 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "hap-sc-irq", "hap-play-irq";
+ qcom,actuator-type = "lra";
+ qcom,vmax-mv = <1800>;
+ qcom,ilim-ma = <400>;
+ qcom,play-rate-us = <8000>;
+ qcom,lra-resonance-sig-shape = "sine";
+ qcom,lra-auto-resonance-mode = "qwd";
+ qcom,lra-allow-variable-play-rate;
+
+ wf_0 {
+ /* CLICK effect */
+ qcom,effect-id = <0>;
+ qcom,wf-play-rate-us = <6250>;
+ qcom,wf-pattern = [3e 3e 3e];
+ qcom,lra-auto-resonance-disable;
+ };
+
+ wf_5 {
+ /* HEAVY_CLICK effect */
+ qcom,effect-id = <5>;
+ qcom,wf-play-rate-us = <6250>;
+ qcom,wf-pattern = [7e 7e 7e];
+ };
+ };
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 0000000..3fcaaad
--- /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/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
deleted file mode 100644
index b54c859..0000000
--- 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 0000000..9889f55
--- /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 0000000..f803b02
--- /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 cd4d222..59651a3 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: <string>
+ 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
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the Hardware index id.
-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.
+- reg
+ Usage: required
+ Value type: <u32>
+ Definition: offset and length of the register set
+ for the device for the cci operating in
+ compatible mode.
+- reg-names
+ Usage: required
+ Value type: <string>
+ Definition: Should specify relevant names to each
+ reg property defined.
+
+- interrupts
+ Usage: required
+ Value type: <u32>
+ Definition: Interrupt associated with CCI HW.
+
+- interrupt-names
+ Usage: required
+ Value type: <string>
+ Definition: Name of the interrupt.
+
+- gpios
+ Usage: required
+ Value type: <phandle>
+ Definition: should specify the gpios to be used for the CCI.
+
+- gpio-req-tbl-num
+ Usage: required
+ Value type: <u32>
+ Definition: should specify the gpio table index.
+
+- gpio-req-tbl-flags
+ Usage: required
+ Value type: <u32>
+ Definition: should specify the gpio functions.
+
+- gpio-req-tbl-label
+ Usage: required
+ Value type: <string>
+ Definition: should specify the gpio labels in
+ gpio-req-tbl-num property (in the same order)
+
+- clock-names
+ Usage: required
+ Value type: <string>
+ Definition: List of clock names required for CCI HW.
+
+- clock-rates
+ Usage: required
+ Value type: <u32>
+ Definition: List of clock rates in Hz for CCI HW.
+
+- clock-cntl-level
+ Usage: required
+ Value type: <string>
+ Definition: All different clock level node can support.
+
+- clocks
+ Usage: required
+ Value type: <phandle>
+ Definition: all clock phandle and source clocks.
+
+- src-clock-name
+ Usage: required
+ Value type: <string>
+ Definition: name for the source clock.
+
+- regulator-names
+ Usage: required
+ Value type: <string>
+ Definition: name of the voltage regulators required for the device.
+
+- gdscr-supply
+ Usage: required
+ Value type: <phandle>
+ Definition: should contain gdsr regulator used for cci clocks.
+
+- mmagic-supply
+ Usage: optional
+ Value type: <phandle>
+ 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
-
-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
-
-* Qualcomm Technologies, Inc. MSM Camera Sensor Resource Manager
-
-MSM 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.
+ - hw-thigh
+ Definition: should contain high period of the SCL clock in terms of CCI clock cycle
+ - hw-tlow
+ Definition: should contain high period of the SCL clock in terms of CCI clock cycle
+ - hw-tsu-sto
+ Definition: should contain setup time for STOP condition
+ - hw-tsu-sta
+ Definition: should contain setup time for Repeated START condition
+ - hw-thd-dat
+ Definition: should contain hold time for the data
+ - hw-thd-sta
+ Definition: should contain hold time for START condition
+ - hw-tbuf
+ Definition: should contain free time between a STOP and a START condition
+ - hw-scl-stretch-en
+ Definition: should contain enable or disable clock stretching
+ - hw-trdhld
+ Definition: should contain internal hold time for SDA
+ - hw-tsp
+ Definition: should contain filtering of glitches
Example:
-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>;
+ 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>;
- status = "ok";
- };
+=======================================
+Second Level Node - CAM SENSOR MODULES
+=======================================
+=======================================
+CAM SENSOR RESOURCE MANAGER
+=======================================
+Camera Sensor Resource manager node contains properties of shared camera
+sensor resource.
+
+- compatible
+ Usage: required
+ Value type: <string>
+ Definition: Should be "qcom,cam-res-mgr".
+
+- shared-gpios
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain the gpios which are used by two or more
+ cameras, and these cameras may be opened together.
+
+- pinctrl-names
+ Usage: optional
+ Value type: <string>
+ Definition: List of names to assign the shared pin state defined in pinctrl device node
+
+- pinctrl-<0..n>
+ Usage: optional
+ Value type: <phandle>
+ 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: <string>
+ Definition: Should be "qcom,cam-sensor".
+
+- cell-index: cci hardware core index
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the Hardware index id.
+
+- reg
+ Usage: required
+ Value type: <u32>
+ Definition: offset and length of the register set
+ for the device for the cci operating in
+ compatible mode.
+
+- cci-device
+ Usage: required
+ Value type: <u32>
+ Definition: should contain i2c device id to be used for this camera
+ sensor
+
+- cci-master
+ Usage: required
+ Value type: <u32>
+ 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: <u32>
+ Definition: should contain csiphy instance that will used to
+ receive sensor data (0, 1, 2, 3).
+
+- cam_vdig-supply
+ Usage: required
+ Value type: <phandle>
+ Definition: should contain regulator from which digital voltage is
+ supplied
+
+- cam_vana-supply
+ Usage: required
+ Value type: <phandle>
+ Definition: should contain regulator from which analog voltage is
+ supplied
+
+- cam_vio-supply
+ Usage: required
+ Value type: <phandle>
+ Definition: should contain regulator from which IO voltage is supplied
+
+- cam_bob-supply
+ Usage: optional
+ Value type: <phandle>
+ Definition: should contain regulator from which BoB voltage is supplied
+
+- regulator-names
+ Usage: required
+ Value type: <string>
+ Definition: should contain names of all regulators needed by this
+ sensor
+
+- rgltr-cntrl-support
+ Usage: required
+ Value type: <boolean>
+ Definition: This property is required if the sw control regulator parameters
+ e.g. rgltr-min-voltage
+
+- rgltr-min-voltage
+ Usage: required
+ Value type: <u32>
+ Definition: should contain minimum voltage level for regulators mentioned
+ in regulator-names property (in the same order)
+
+- rgltr-max-voltage
+ Usage: required
+ Value type: <u32>
+ Definition: should contain maximum voltage level for regulators mentioned
+ in regulator-names property (in the same order)
+
+- rgltr-load-current
+ Usage: required
+ Value type: <u32>
+ Definition: should contain optimum voltage level for regulators mentioned
+ in regulator-names property (in the same order)
+
+- sensor-position-roll
+ Usage: required
+ Value type: <u32>
+ 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: <u32>
+ 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: <u32>
+ Definition: should contain sensor rotational angle with respect to axis of
+ reference. i.e. 0, 90, 180, 360
+
+- qcom,secure
+ Usage: optional
+ Value type: <u32>
+ Definition: should be enabled to operate the camera in secure mode
+
+- gpio-no-mux
+ Usage: optional
+ Value type: <u32>
+ 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: <u32>
+ Definition: should contain regulator from which AF voltage is supplied
+
+- pwm-switch
+ Usage: optional
+ Value type: <boolean>
+ Definition: This property is required for regulator to switch into PWM mode.
+
+- gpios
+ Usage: required
+ Value type: <phandle>
+ Definition: should contain phandle to gpio controller node and array of
+ #gpio-cells specifying specific gpio (controller specific)
+
+- gpio-reset
+ Usage: required
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors reset_n
+
+- gpio-standby
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors standby_n
+
+- gpio-vio
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors io vreg enable
+
+- gpio-vana
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors analog vreg enable
+
+- gpio-vdig
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors digital vreg enable
+
+- gpio-vaf
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors af vreg enable
+
+- gpio-af-pwdm
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpio used by sensors af pwdm_n
+
+- gpio-req-tbl-num
+ Usage: optional
+ Value type: <u32>
+ Definition: should contain index to gpios specific to this sensor
+
+- gpio-req-tbl-flags
+ Usage: optional
+ Value type: <u32>
+ 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: <u32>
+ 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: <u32>
+ Definition: should contain index of gpios that need to be
+ configured by msm
+
+- gpio-set-tbl-flags
+ Usage: optional
+ Value type: <u32>
+ 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: <u32>
+ 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: <phandle>
+ 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: <phandle>
+ 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: <phandle>
+ Definition: should contain regulator from which cx voltage is supplied
+
+- qcom,vdd-cx-name
+ Usage: optional
+ Value type: <string>
+ Definition: should contain names of cx regulator
+
+- eeprom-src
+ Usage: optional
+ Value type: <phandle>
+ Definition: if eeprom memory is supported by this sensor, this
+ property should contain phandle of respective eeprom nodes
+
+- ois-src
+ Usage: optional
+ Value type: <phandle>
+ 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: <phandle>
+ 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: <phandle>
+ 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: <string>
+ Definition: if only some special sensors are supported
+ on this board, add sensor name in this property.
+
+- use-shared-clk
+ Usage: optional
+ Value type: <boolean>
+ 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: <u32>
+ Definition: clock rate in Hz.
+
+- clock-cntl-level
+ Usage: required
+ Value type: <string>
+ Definition: All different clock level node can support.
+
+- clock-cntl-support
+ Usage: optional
+ Value type: <boolean>
+ Definition: Says whether clock control support is present or not
+
+- clocks
+ Usage: required
+ Value type: <phandle>
+ Definition: all clock phandle and source clocks.
+
+- clock-control
+ Usage: optional
+ Value type: <string>
+ 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: <string>
+ Definition: Should be "qcom,actuator".
+
+- cell-index: cci hardware core index
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the Hardware index id.
+
+- reg
+ Usage: required
+ Value type: <u32>
+ Definition: offset and length of the register set
+ for the device for the cci operating in
+ compatible mode.
+
+- cci-device
+ Usage: required
+ Value type: <u32>
+ Definition: should contain i2c device id to be used for this camera
+ sensor
+
+- cci-master
+ Usage: required
+ Value type: <u32>
+ 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: <phandle>
+ Definition: should contain regulator from which AF voltage is supplied
+
+- regulator-names
+ Usage: required
+ Value type: <string>
+ Definition: should contain names of all regulators needed by this
+ actuator. i.e. "cam_vaf"
+
+- rgltr-cntrl-support
+ Usage: optional
+ Value type: <boolean>
+ 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: <u32>
+ 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: <u32>
+ 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: <u32>
+ 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: <string>
+ Definition: Should be "qcom,ois".
+
+- cell-index: cci hardware core index
+ Usage: required
+ Value type: <u32>
+ Definition: Should specify the Hardware index id.
+
+- reg
+ Usage: required
+ Value type: <u32>
+ Definition: offset and length of the register set
+ for the device for the cci operating in
+ compatible mode.
+
+- cci-device
+ Usage: required
+ Value type: <u32>
+ Definition: should contain i2c device id to be used for this camera
+ sensor
+
+- cci-master
+ Usage: required
+ Value type: <u32>
+ 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: <phandle>
+ Definition: should contain regulator from which AF voltage is supplied
+
+- regulator-names
+ Usage: required
+ Value type: <string>
+ Definition: should contain names of all regulators needed by this
+ actuator. i.e. "cam_vaf"
+
+- rgltr-cntrl-support
+ Usage: optional
+ Value type: <boolean>
+ 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: <u32>
+ 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: <u32>
+ 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: <u32>
+ 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: <boolean>
+ 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 @@
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 @@
"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 c47cb34..b968530 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 @@
Value type: <string>
Definition: Source clock name.
+- clock-control-debugfs
+ Usage: optional
+ Value type: <string>
+ Definition: Enable/Disable clk rate control.
+
- clock-cntl-level
Usage: required
Value type: <string>
diff --git a/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt b/Documentation/devicetree/bindings/media/video/msm-cam-icp.txt
index ffc0e96..1495881 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 @@
Value type: <string>
Definition: Source clock name.
+- clock-control-debugfs
+ Usage: optional
+ Value type: <string>
+ Definition: Enable/Disable clk rate control.
+
- clocks
Usage: required
Value type: <phandle>
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 f9a5e0f..29ea987 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 @@
Value type: <string>
Definition: Source clock name.
-
+- clock-control-debugfs
+ Usage: optional
+ Value type: <string>
+ 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 99f2c7a..f156cc6 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 @@
Value type: <u32>
Definition: List of clocks rates for optional clocks.
+- clock-control-debugfs
+ Usage: optional
+ Value type: <string>
+ 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 d6c6e41..6192f02 100644
--- a/Documentation/devicetree/bindings/net/dsa/b53.txt
+++ b/Documentation/devicetree/bindings/net/dsa/b53.txt
@@ -10,6 +10,7 @@
"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 0b6daab..2c26743 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 @@
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 a034acc..e546dc2 100644
--- a/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
+++ b/Documentation/devicetree/bindings/qdsp/msm-fastrpc.txt
@@ -16,6 +16,7 @@
- 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 20cb25b..6c9d8253 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -3290,3 +3290,97 @@
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 a22edb5..ed51a77 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -123,13 +123,13 @@
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 a20b2fa..56af008 100644
--- a/Documentation/networking/netdev-FAQ.txt
+++ b/Documentation/networking/netdev-FAQ.txt
@@ -168,6 +168,15 @@
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 5962949..d2fbeeb 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -279,11 +279,10 @@
%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 6fac39b..98ce41f 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 54e93a0..04b90d3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1412,6 +1412,16 @@
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 e9a5d0b..908b269 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/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 824eefa..b5734c5 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -11,7 +11,9 @@
sdxpoorwills-pcie-ep-cdp-256.dtb \
sdxpoorwills-pcie-ep-mtp-256.dtb \
sdxpoorwills-pcie-ep-cdp.dtb \
- sdxpoorwills-pcie-ep-mtp.dtb
+ sdxpoorwills-pcie-ep-mtp.dtb \
+ sdxpoorwills-v2-mtp.dtb \
+ sdxpoorwills-v2-cdp.dtb
dtb-$(CONFIG_ARCH_MDM9650) += mdm9650-nand-mtp.dtb \
mdm9650-ttp.dtb \
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-cdp.dts
index 99e3faa..eb28282 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 8c506b9..c836f94 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 16f933f..d447724 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 252fb04..b60225a 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-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-mtp.dts
index 3ae5b2c..a383f3e 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 ef1150a..a6d2463 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 cbbf585..d23275e 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 2a2e496..521d948 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 6b6aab5..236ce73 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 8c22348..11c4e62 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 e939bd2..1907209 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 775be96..f0363c0 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-usb.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
index 642a541..0d36f2a 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-usb.dtsi
@@ -33,6 +33,7 @@
qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
qcom,num-gsi-evt-buffs = <0x3>;
qcom,use-pdc-interrupts;
+ qcom,pm-qos-latency = <2 241 271>;
clocks = <&clock_gcc GCC_USB30_MASTER_CLK>,
<&clock_gcc GCC_SYS_NOC_USB3_CLK>,
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-v2-cdp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-v2-cdp.dts
new file mode 100644
index 0000000..4ac0117
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-v2-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 "sdxpoorwills-cdp.dtsi"
+#include "sdxpoorwills-v2.dtsi"
+#include "sdxpoorwills-display.dtsi"
+#include "qpic-panel-ili-hvga.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS CDP V2";
+ compatible = "qcom,sdxpoorwills-cdp",
+ "qcom,sdxpoorwills", "qcom,cdp";
+ qcom,board-id = <1 0x102>;
+};
+
+&blsp1_uart2b_hs {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-v2-mtp.dts b/arch/arm/boot/dts/qcom/sdxpoorwills-v2-mtp.dts
new file mode 100644
index 0000000..29f77de
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-v2-mtp.dts
@@ -0,0 +1,31 @@
+/* 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 "sdxpoorwills-mtp.dtsi"
+#include "sdxpoorwills-v2.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS MTP V2";
+ compatible = "qcom,sdxpoorwills-mtp",
+ "qcom,sdxpoorwills", "qcom,mtp";
+ qcom,board-id = <8 0x102>;
+};
+
+&qcom_seecom {
+ status = "okay";
+};
+
+&blsp1_uart2b_hs {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-v2.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-v2.dtsi
new file mode 100644
index 0000000..eef2ffb
--- /dev/null
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-v2.dtsi
@@ -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.
+ */
+
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDXPOORWILLS V2";
+ compatible = "qcom,sdxpoorwills";
+ qcom,msm-id = <334 0x20000>, <335 0x20000>;
+};
+
+&emac_hw {
+ emac-core-version = <5>;
+};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index ef001fb..61363fe 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -951,24 +951,24 @@
<MSM_BUS_MASTER_IPA_CORE MSM_BUS_SLAVE_IPA_CORE 0 0>,
/* SVS2 */
- <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 240000 480000>,
- <MSM_BUS_MASTER_SNOC_GC_MEM_NOC MSM_BUS_SLAVE_EBI_CH0 900000 1800000>,
- <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_OCIMEM 300000 600000>,
- <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_IPA_CFG 90000 179000>,
+ <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 116000 480000>,
+ <MSM_BUS_MASTER_SNOC_GC_MEM_NOC MSM_BUS_SLAVE_EBI_CH0 116000 1800000>,
+ <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_OCIMEM 60000 600000>,
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_IPA_CFG 17900 179000>,
<MSM_BUS_MASTER_IPA_CORE MSM_BUS_SLAVE_IPA_CORE 0 120>,
/* SVS */
- <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 360000 720000>,
- <MSM_BUS_MASTER_SNOC_GC_MEM_NOC MSM_BUS_SLAVE_EBI_CH0 1530000 3060000>,
- <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_OCIMEM 400000 800000>,
- <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_IPA_CFG 100000 199000>,
+ <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 225000 720000>,
+ <MSM_BUS_MASTER_SNOC_GC_MEM_NOC MSM_BUS_SLAVE_EBI_CH0 225000 3060000>,
+ <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_OCIMEM 80000 800000>,
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_IPA_CFG 19900 199000>,
<MSM_BUS_MASTER_IPA_CORE MSM_BUS_SLAVE_IPA_CORE 0 250>,
/* NOMINAL */
- <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 780000 1560000>,
- <MSM_BUS_MASTER_SNOC_GC_MEM_NOC MSM_BUS_SLAVE_EBI_CH0 2592000 5184000>,
- <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_OCIMEM 800000 1600000>,
- <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_IPA_CFG 200000 399000>,
+ <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_SNOC_MEM_NOC_GC 375000 1560000>,
+ <MSM_BUS_MASTER_SNOC_GC_MEM_NOC MSM_BUS_SLAVE_EBI_CH0 375000 5184000>,
+ <MSM_BUS_MASTER_IPA MSM_BUS_SLAVE_OCIMEM 160000 1600000>,
+ <MSM_BUS_MASTER_AMPSS_M0 MSM_BUS_SLAVE_IPA_CFG 39900 399000>,
<MSM_BUS_MASTER_IPA_CORE MSM_BUS_SLAVE_IPA_CORE 0 440>,
/* 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 d907a0d..b5474db 100644
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -63,6 +63,7 @@
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_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
@@ -256,7 +258,9 @@
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_STMVL53L0X=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,12 +426,18 @@
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_IIO=y
+CONFIG_INV_ICM20602_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=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
@@ -470,4 +480,9 @@
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 a87599f..787b38e 100644
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -308,11 +308,18 @@
CONFIG_QPNP_LINEAR_CHARGER=y
CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
CONFIG_THERMAL=y
+CONFIG_THERMAL_WRITABLE_TRIPS=y
+CONFIG_THERMAL_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
CONFIG_THERMAL_QPNP=y
CONFIG_THERMAL_QPNP_ADC_TM=y
CONFIG_THERMAL_TSENS=y
CONFIG_MSM_BCL_PERIPHERAL_CTL=y
CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_MFD_QCOM_RPM=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_MFD_SYSCON=y
@@ -460,6 +467,9 @@
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
@@ -469,6 +479,7 @@
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_EXT2_FS=y
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
index 3094af9..cb12130 100644
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -122,6 +122,7 @@
CONFIG_NETFILTER_XT_TARGET_TRACE=y
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_BPF=y
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -448,6 +449,7 @@
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 2e545d8..a15ab9c 100644
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -124,6 +124,7 @@
CONFIG_NETFILTER_XT_TARGET_TRACE=y
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_BPF=y
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
@@ -440,6 +441,7 @@
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 +464,7 @@
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 34c9daa..26d0d06 100644
--- a/arch/arm/configs/msm8937-perf_defconfig
+++ b/arch/arm/configs/msm8937-perf_defconfig
@@ -41,6 +41,7 @@
CONFIG_BPF_SYSCALL=y
# CONFIG_MEMBARRIER is not set
CONFIG_EMBEDDED=y
+# CONFIG_SLUB_DEBUG is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_PROFILING=y
CONFIG_CC_STACKPROTECTOR_STRONG=y
@@ -104,6 +105,7 @@
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 +117,7 @@
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 +588,7 @@
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
@@ -592,6 +596,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_FS_ENCRYPTION=y
@@ -635,6 +642,7 @@
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 e4c9eb2..4a85408 100644
--- a/arch/arm/configs/msm8937_defconfig
+++ b/arch/arm/configs/msm8937_defconfig
@@ -108,6 +108,7 @@
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_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
@@ -613,6 +615,9 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_EXT4_FS_ENCRYPTION=y
+CONFIG_EXT4_FS_ICE_ENCRYPTION=y
CONFIG_F2FS_FS=y
CONFIG_F2FS_FS_SECURITY=y
CONFIG_F2FS_FS_ENCRYPTION=y
@@ -702,6 +707,7 @@
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 fca07a10..344ab3d 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -102,6 +102,7 @@
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_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_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_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_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_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 690faf2..ff0a8a2 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -106,6 +106,7 @@
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_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_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_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_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_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_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-perf_defconfig b/arch/arm/configs/sdm670-perf_defconfig
new file mode 100644
index 0000000..33d53db
--- /dev/null
+++ b/arch/arm/configs/sdm670-perf_defconfig
@@ -0,0 +1,566 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_FHANDLE is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IRQ_TIME_ACCOUNTING=y
+CONFIG_SCHED_WALT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_RCU_EXPERT=y
+CONFIG_RCU_FAST_NO_HZ=y
+CONFIG_RCU_NOCB_CPU=y
+CONFIG_RCU_NOCB_CPU_ALL=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CPUSETS=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHEDTUNE=y
+CONFIG_BLK_CGROUP=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_SCHED_CORE_CTL=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_TUNE=y
+CONFIG_DEFAULT_USE_ENERGY_AWARE=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+CONFIG_BPF_SYSCALL=y
+# CONFIG_AIO is not set
+# CONFIG_MEMBARRIER is not set
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=y
+CONFIG_MODULE_SIG_SHA512=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_CFQ_GROUP_IOSCHED=y
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_SDM670=y
+CONFIG_PCI_MSM=y
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_NR_CPUS=8
+CONFIG_ARM_PSCI=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_ARM_MODULE_PLTS=y
+CONFIG_CMA=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_ARM_APPENDED_DTB=y
+CONFIG_CPU_FREQ_GOV_POWERSAVE=y
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
+CONFIG_CPU_BOOST=y
+CONFIG_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
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=y
+CONFIG_XFRM_STATISTICS=y
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+CONFIG_IPV6_MIP6=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_IPV6_SUBTREES=y
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=y
+CONFIG_NF_CONNTRACK_SECMARK=y
+CONFIG_NF_CONNTRACK_EVENTS=y
+CONFIG_NF_CT_PROTO_DCCP=y
+CONFIG_NF_CT_PROTO_SCTP=y
+CONFIG_NF_CT_PROTO_UDPLITE=y
+CONFIG_NF_CONNTRACK_AMANDA=y
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+CONFIG_NF_CONNTRACK_NETBIOS_NS=y
+CONFIG_NF_CONNTRACK_PPTP=y
+CONFIG_NF_CONNTRACK_SANE=y
+CONFIG_NF_CONNTRACK_TFTP=y
+CONFIG_NF_CT_NETLINK=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
+CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
+CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y
+CONFIG_NETFILTER_XT_TARGET_LOG=y
+CONFIG_NETFILTER_XT_TARGET_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=y
+CONFIG_NETFILTER_XT_TARGET_TEE=y
+CONFIG_NETFILTER_XT_TARGET_TPROXY=y
+CONFIG_NETFILTER_XT_TARGET_TRACE=y
+CONFIG_NETFILTER_XT_TARGET_SECMARK=y
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
+CONFIG_NETFILTER_XT_MATCH_COMMENT=y
+CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=y
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
+CONFIG_NETFILTER_XT_MATCH_DSCP=y
+CONFIG_NETFILTER_XT_MATCH_ESP=y
+CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_L2TP is not set
+CONFIG_NETFILTER_XT_MATCH_LENGTH=y
+CONFIG_NETFILTER_XT_MATCH_LIMIT=y
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+CONFIG_NETFILTER_XT_MATCH_MARK=y
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+CONFIG_NETFILTER_XT_MATCH_POLICY=y
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y
+CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_SOCKET=y
+CONFIG_NETFILTER_XT_MATCH_STATE=y
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
+CONFIG_NETFILTER_XT_MATCH_STRING=y
+CONFIG_NETFILTER_XT_MATCH_TIME=y
+CONFIG_NETFILTER_XT_MATCH_U32=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_IP_NF_IPTABLES=y
+CONFIG_IP_NF_MATCH_AH=y
+CONFIG_IP_NF_MATCH_ECN=y
+CONFIG_IP_NF_MATCH_RPFILTER=y
+CONFIG_IP_NF_MATCH_TTL=y
+CONFIG_IP_NF_FILTER=y
+CONFIG_IP_NF_TARGET_REJECT=y
+CONFIG_IP_NF_NAT=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+CONFIG_IP_NF_TARGET_NETMAP=y
+CONFIG_IP_NF_TARGET_REDIRECT=y
+CONFIG_IP_NF_MANGLE=y
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_SECURITY=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
+CONFIG_NF_CONNTRACK_IPV6=y
+CONFIG_IP6_NF_IPTABLES=y
+CONFIG_IP6_NF_MATCH_RPFILTER=y
+CONFIG_IP6_NF_FILTER=y
+CONFIG_IP6_NF_TARGET_REJECT=y
+CONFIG_IP6_NF_MANGLE=y
+CONFIG_IP6_NF_RAW=y
+CONFIG_BRIDGE_NF_EBTABLES=y
+CONFIG_BRIDGE_EBT_BROUTE=y
+CONFIG_L2TP=y
+CONFIG_L2TP_V3=y
+CONFIG_L2TP_IP=y
+CONFIG_L2TP_ETH=y
+CONFIG_BRIDGE=y
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_SCH_PRIO=y
+CONFIG_NET_SCH_MULTIQ=y
+CONFIG_NET_SCH_INGRESS=y
+CONFIG_NET_CLS_FW=y
+CONFIG_NET_CLS_U32=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_FLOW=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_CMP=y
+CONFIG_NET_EMATCH_NBYTE=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_EMATCH_META=y
+CONFIG_NET_EMATCH_TEXT=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_GACT=y
+CONFIG_NET_ACT_MIRRED=y
+CONFIG_NET_ACT_SKBEDIT=y
+CONFIG_RMNET_DATA=y
+CONFIG_RMNET_DATA_FC=y
+CONFIG_RMNET_DATA_DEBUG_PKT=y
+CONFIG_BT=y
+CONFIG_MSM_BT_POWER=y
+CONFIG_CFG80211=y
+CONFIG_CFG80211_INTERNAL_REGDB=y
+# CONFIG_CFG80211_CRDA_SUPPORT is not set
+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
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_QPNP_MISC=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_CHR_DEV_SCH=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_UFSHCD=y
+CONFIG_SCSI_UFSHCD_PLATFORM=y
+CONFIG_SCSI_UFS_QCOM=y
+CONFIG_SCSI_UFS_QCOM_ICE=y
+CONFIG_SCSI_UFSHCD_CMD_LOGGING=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_REQ_CRYPT=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=y
+CONFIG_DUMMY=y
+CONFIG_TUN=y
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=y
+CONFIG_PPPOL2TP=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_PPP_ASYNC=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_USBNET=y
+CONFIG_WCNSS_MEM_PRE_ALLOC=y
+CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS_GENL=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_KEYBOARD_GPIO=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_QPNP_POWER_ON=y
+CONFIG_INPUT_UINPUT=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM_GENI=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_QCOM_GENI=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_QCOM_GENI=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SLIMBUS_MSM_NGD=y
+CONFIG_SPMI=y
+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
+CONFIG_QPNP_SMB2=y
+CONFIG_QPNP_QNOVO=y
+CONFIG_SMB1390_CHARGE_PUMP=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_THERMAL=y
+CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE=y
+CONFIG_THERMAL_GOV_STEP_WISE=y
+CONFIG_THERMAL_GOV_LOW_LIMITS=y
+CONFIG_CPU_THERMAL=y
+CONFIG_DEVFREQ_THERMAL=y
+CONFIG_QCOM_SPMI_TEMP_ALARM=y
+CONFIG_THERMAL_QPNP=y
+CONFIG_THERMAL_QPNP_ADC_TM=y
+CONFIG_THERMAL_TSENS=y
+CONFIG_MSM_BCL_PERIPHERAL_CTL=y
+CONFIG_QTI_THERMAL_LIMITS_DCVS=y
+CONFIG_MFD_I2C_PMIC=y
+CONFIG_MFD_SPMI_PMIC=y
+CONFIG_MFD_SYSCON=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
+CONFIG_REGULATOR_QPNP_OLEDB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_REFGEN=y
+CONFIG_REGULATOR_RPMH=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_VIDEO_ADV_DEBUG=y
+CONFIG_VIDEO_FIXED_MINOR_RANGES=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_GOVERNORS=y
+CONFIG_MSM_SDE_ROTATOR=y
+CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
+CONFIG_QCOM_KGSL=y
+CONFIG_DRM=y
+CONFIG_DRM_SDE_EVTLOG_DEBUG=y
+CONFIG_DRM_SDE_RSC=y
+CONFIG_DRM_LT_LT9611=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# 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
+CONFIG_UHID=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_USB=y
+CONFIG_USB_XHCI_HCD=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_MSM=y
+CONFIG_USB_ISP1760=y
+CONFIG_USB_ISP1760_HOST_ROLE=y
+CONFIG_USB_PD_POLICY=y
+CONFIG_QPNP_USB_PDPHY=y
+CONFIG_USB_EHSET_TEST_FIXTURE=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_DUAL_ROLE_USB_INTF=y
+CONFIG_USB_MSM_SSPHY_QMP=y
+CONFIG_MSM_QUSB_PHY=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_NCM=y
+CONFIG_USB_CONFIGFS_MASS_STORAGE=y
+CONFIG_USB_CONFIGFS_F_FS=y
+CONFIG_USB_CONFIGFS_F_MTP=y
+CONFIG_USB_CONFIGFS_F_PTP=y
+CONFIG_USB_CONFIGFS_F_ACC=y
+CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
+CONFIG_USB_CONFIGFS_UEVENT=y
+CONFIG_USB_CONFIGFS_F_MIDI=y
+CONFIG_USB_CONFIGFS_F_HID=y
+CONFIG_USB_CONFIGFS_F_DIAG=y
+CONFIG_USB_CONFIGFS_F_CDEV=y
+CONFIG_USB_CONFIGFS_F_CCID=y
+CONFIG_USB_CONFIGFS_F_GSI=y
+CONFIG_USB_CONFIGFS_F_QDSS=y
+CONFIG_MMC=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_TEST=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_SDHCI_MSM_ICE=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_UIO=y
+CONFIG_UIO_MSM_SHAREDMEM=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_LOW_MEMORY_KILLER=y
+CONFIG_ION=y
+CONFIG_ION_MSM=y
+CONFIG_GSI=y
+CONFIG_IPA3=y
+CONFIG_RMNET_IPA3=y
+CONFIG_RNDIS_IPA=y
+CONFIG_IPA_UT=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_USB_BAM=y
+CONFIG_QCOM_GENI_SE=y
+CONFIG_MSM_GCC_SDM845=y
+CONFIG_MSM_VIDEOCC_SDM845=y
+CONFIG_MSM_CAMCC_SDM845=y
+CONFIG_MSM_DISPCC_SDM845=y
+CONFIG_CLOCK_QPNP_DIV=y
+CONFIG_MSM_CLK_RPMH=y
+CONFIG_CLOCK_CPU_OSM=y
+CONFIG_MSM_GPUCC_SDM845=y
+CONFIG_MSM_CLK_AOP_QMP=y
+CONFIG_QCOM_MDSS_PLL=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MSM_QMP=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_QCOM_LLCC=y
+CONFIG_QCOM_SDM670_LLCC=y
+CONFIG_QCOM_LLCC_PERFMON=m
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_EUD=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QPNP_PBS=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_BUS_CONFIG_RPMH=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_GLINK=y
+CONFIG_MSM_GLINK_LOOPBACK_SERVER=y
+CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y
+CONFIG_MSM_GLINK_SPI_XPRT=y
+CONFIG_MSM_SPCOM=y
+CONFIG_MSM_SPSS_UTILS=y
+CONFIG_QTI_RPMH_API=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y
+CONFIG_MSM_QMI_INTERFACE=y
+CONFIG_MSM_GLINK_PKT=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_SYSMON_GLINK_COMM=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_MSM_PIL_MSS_QDSP6V5=y
+CONFIG_ICNSS=y
+CONFIG_QCOM_COMMAND_DB=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_CDSP_LOADER=y
+CONFIG_QCOM_SMCINVOKE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_QBT1000=y
+CONFIG_QCOM_DCC_V2=y
+CONFIG_QTI_RPM_STATS_LOG=y
+CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_MSM_REMOTEQDSS=y
+CONFIG_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_EXTCON_USB_GPIO=y
+CONFIG_IIO=y
+CONFIG_QCOM_RRADC=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_ARM_GIC_V3_ACL=y
+CONFIG_RAS=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=y
+CONFIG_MSM_TZ_LOG=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_ECRYPT_FS=y
+CONFIG_ECRYPT_FS_MESSAGING=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_PAGE_EXTENSION=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_SCHEDSTATS=y
+# CONFIG_DEBUG_PREEMPT is not set
+CONFIG_IPC_LOGGING=y
+CONFIG_TRACER_SNAPSHOT=y
+CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y
+CONFIG_CPU_FREQ_SWITCH_PROFILER=y
+CONFIG_CORESIGHT=y
+CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y
+CONFIG_CORESIGHT_QCOM_REPLICATOR=y
+CONFIG_CORESIGHT_STM=y
+CONFIG_CORESIGHT_TPDA=y
+CONFIG_CORESIGHT_TPDM=y
+CONFIG_CORESIGHT_CTI=y
+CONFIG_CORESIGHT_HWEVENT=y
+CONFIG_CORESIGHT_DUMMY=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SMACK=y
+CONFIG_CRYPTO_XCBC=y
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_ANSI_CPRNG=y
+CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
+CONFIG_CRYPTO_DEV_QCEDEV=y
+CONFIG_CRYPTO_DEV_QCOM_ICE=y
diff --git a/arch/arm/configs/sdm670_defconfig b/arch/arm/configs/sdm670_defconfig
index 2fda0e2..51ca98d 100644
--- a/arch/arm/configs/sdm670_defconfig
+++ b/arch/arm/configs/sdm670_defconfig
@@ -63,6 +63,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_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_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_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
@@ -345,9 +352,12 @@
CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_VIDEO_ADV_DEBUG=y
CONFIG_VIDEO_FIXED_MINOR_RANGES=y
CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_V4L2=y
+CONFIG_MSM_VIDC_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y
CONFIG_QCOM_KGSL=y
@@ -363,6 +373,7 @@
# 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 +438,8 @@
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
@@ -542,6 +555,7 @@
CONFIG_PRINTK_TIME=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO=y
+CONFIG_FRAME_WARN=2048
CONFIG_PAGE_OWNER=y
CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index d5930a7..cdbfebd 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_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
@@ -362,6 +366,8 @@
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_WATCHDOG_V2=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index f5abbb4..b3fef2f 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_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
@@ -367,6 +371,8 @@
CONFIG_IOMMU_DEBUG=y
CONFIG_IOMMU_DEBUG_TRACKING=y
CONFIG_IOMMU_TESTS=y
+CONFIG_MSM_SERVICE_LOCATOR=y
+CONFIG_MSM_SERVICE_NOTIFIER=y
CONFIG_QCOM_SCM=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_WATCHDOG_V2=y
diff --git a/arch/arm/include/asm/cputype.h b/arch/arm/include/asm/cputype.h
index b62eaeb..174346b 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 0a9d5dd..6949c7d 100644
--- a/arch/arm/include/asm/kgdb.h
+++ b/arch/arm/include/asm/kgdb.h
@@ -76,7 +76,7 @@
#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 3cc14dd..0c835ee 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 @@
* 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 4f14b5c..c2b440b 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 38ad8b9..b876193 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -150,17 +150,6 @@
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 @@
}
#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 09dd8ff..4f451ce 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -243,6 +243,40 @@
"?(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 @@
* 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 3b2f4ce..0169acb 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -47,6 +47,7 @@
#include <asm/virt.h>
#include <asm/mach/arch.h>
#include <asm/mpu.h>
+#include <asm/cputype.h>
#define CREATE_TRACE_POINTS
#include <trace/events/ipi.h>
@@ -359,6 +360,7 @@
* 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 d96863e..7ca9180 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -64,6 +64,7 @@
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 @@
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 @@
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 c1799dd..1a5acee 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -1068,3 +1068,20 @@
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 c8c8b9e..f187439 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -276,5 +276,6 @@
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 e346cf3..e5a8a57 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1965,6 +1965,8 @@
total_length += s->length;
iova = __alloc_iova(mapping, total_length);
+ if (iova == DMA_ERROR_CODE)
+ return 0;
ret = iommu_map_sg(mapping->domain, iova, sg, nents, prot);
if (ret != total_length) {
__free_iova(mapping, iova, total_length);
@@ -2483,7 +2485,10 @@
{
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 203728d..7fa65aa 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -265,6 +265,7 @@
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 @@
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 @@
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 f72ce30..ac71d39 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -554,6 +554,16 @@
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 a92f511..4c013ad 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -152,6 +152,7 @@
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 @@
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 @@
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 e4d6200..ef0ac4d 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -150,6 +150,7 @@
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 @@
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-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-ipcamera-base.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-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 @@
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 @@
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 @@
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 \
@@ -460,8 +499,11 @@
apq8053-lite-dragon-v2.0.dtb \
apq8053-lite-dragon-v2.1.dtb \
apq8053-lite-dragon-v2.2.dtb \
+ apq8053-lite-dragon-v2.2.1.dtb \
apq8053-lite-dragon-v2.3.dtb \
apq8053-lite-dragon-v2.4.dtb \
+ apq8053-lat-concam-dev.dtb \
+ apq8053-lat-concam-proto.dtb \
msm8953-pmi8940-cdp.dtb \
msm8953-pmi8940-mtp.dtb \
msm8953-pmi8937-cdp.dtb \
@@ -496,11 +538,13 @@
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 0000000..0ac8a31
--- /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 <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+#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 0000000..4677448
--- /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 <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+#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_qc6174 {
+ compatible = "qca,qca6174";
+ 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 = "okay";
+};
+
+/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 d83ae5c..fef9f45 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 6c8bef4..21e47bf 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 055c457..4f07399 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 23bbb0f..0b958ee 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-lat-concam-audio.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-audio.dtsi
new file mode 100644
index 0000000..b0fee57
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-audio.dtsi
@@ -0,0 +1,645 @@
+/*
+ * 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.
+ */
+
+/* picked up from base file msm8953-audio.dtsi, enables internal codec config */
+
+&soc {
+ &i2c_2 {
+ status = "okay";
+ wsa881x_i2c_f: wsa881x-i2c-codec@f {
+ status = "okay";
+
+ compatible = "qcom,wsa881x-i2c-codec";
+ reg = <0x0f>;
+ qcom,msm-gpios = "wsa_clk",
+ "wsa_reset",
+ "wsa_vi";
+ qcom,pinctrl-names = "all_off",
+ "wsa_clk",
+ "wsa_active",
+ "wsa_clk_active",
+ "wsa_vi",
+ "wsa_clk_vi",
+ "wsa_active_vi",
+ "wsa_all";
+ pinctrl-names = "all_off",
+ "wsa_clk",
+ "wsa_active",
+ "wsa_clk_active",
+ "wsa_vi",
+ "wsa_clk_vi",
+ "wsa_active_vi",
+ "wsa_all";
+ pinctrl-0 = <&wsa_clk_off &wsa_reset_off &wsa_vi_off>;
+ pinctrl-1 = <&wsa_clk_on &wsa_reset_off &wsa_vi_off>;
+ pinctrl-2 = <&wsa_clk_off &wsa_reset_on &wsa_vi_off>;
+ pinctrl-3 = <&wsa_clk_on &wsa_reset_on &wsa_vi_off>;
+ pinctrl-4 = <&wsa_clk_off &wsa_reset_off &wsa_vi_on>;
+ pinctrl-5 = <&wsa_clk_on &wsa_reset_off &wsa_vi_on>;
+ pinctrl-6 = <&wsa_clk_off &wsa_reset_on &wsa_vi_on>;
+ pinctrl-7 = <&wsa_clk_on &wsa_reset_on &wsa_vi_on>;
+ };
+
+ wsa881x_i2c_45: wsa881x-i2c-codec@45 {
+ status = "okay";
+
+ compatible = "qcom,wsa881x-i2c-codec";
+ reg = <0x45>;
+ qcom,msm-gpios = "wsa_clk",
+ "wsa_reset",
+ "wsa_vi";
+ qcom,pinctrl-names = "all_off",
+ "wsa_clk",
+ "wsa_active",
+ "wsa_clk_active",
+ "wsa_vi",
+ "wsa_clk_vi",
+ "wsa_active_vi",
+ "wsa_all";
+ pinctrl-names = "all_off",
+ "wsa_clk",
+ "wsa_active",
+ "wsa_clk_active",
+ "wsa_vi",
+ "wsa_clk_vi",
+ "wsa_active_vi",
+ "wsa_all";
+ pinctrl-0 = <&wsa_clk_off &wsa_reset_off &wsa_vi_off>;
+ pinctrl-1 = <&wsa_clk_on &wsa_reset_off &wsa_vi_off>;
+ pinctrl-2 = <&wsa_clk_off &wsa_reset_on &wsa_vi_off>;
+ pinctrl-3 = <&wsa_clk_on &wsa_reset_on &wsa_vi_off>;
+ pinctrl-4 = <&wsa_clk_off &wsa_reset_off &wsa_vi_on>;
+ pinctrl-5 = <&wsa_clk_on &wsa_reset_off &wsa_vi_on>;
+ pinctrl-6 = <&wsa_clk_off &wsa_reset_on &wsa_vi_on>;
+ pinctrl-7 = <&wsa_clk_on &wsa_reset_on &wsa_vi_on>;
+ };
+ };
+
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "regular";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
+ lpa: qcom,msm-pcm-lpa {
+ compatible = "qcom,msm-pcm-lpa";
+ };
+
+ compress: qcom,msm-compress-dsp {
+ compatible = "qcom,msm-compress-dsp";
+ };
+
+ voip: qcom,msm-voip-dsp {
+ compatible = "qcom,msm-voip-dsp";
+ };
+
+ voice: qcom,msm-pcm-voice {
+ compatible = "qcom,msm-pcm-voice";
+ qcom,destroy-cvd;
+ };
+
+ stub_codec: qcom,msm-stub-codec {
+ compatible = "qcom,msm-stub-codec";
+ };
+
+ qcom,msm-dai-fe {
+ compatible = "qcom,msm-dai-fe";
+ };
+
+ afe: qcom,msm-pcm-afe {
+ compatible = "qcom,msm-pcm-afe";
+ };
+
+ loopback: qcom,msm-pcm-loopback {
+ compatible = "qcom,msm-pcm-loopback";
+ };
+
+ qcom,msm-dai-mi2s {
+ compatible = "qcom,msm-dai-mi2s";
+ dai_mi2s0: qcom,msm-dai-q6-mi2s-prim {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <0>;
+ qcom,msm-mi2s-rx-lines = <3>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s1: qcom,msm-dai-q6-mi2s-sec {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <1>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <0>;
+ };
+
+ dai_mi2s3: qcom,msm-dai-q6-mi2s-quat {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <3>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s2: qcom,msm-dai-q6-mi2s-tert {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <2>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+
+ dai_mi2s5: qcom,msm-dai-q6-mi2s-quin {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <5>;
+ qcom,msm-mi2s-rx-lines = <1>;
+ qcom,msm-mi2s-tx-lines = <2>;
+ };
+
+ dai_mi2s6: qcom,msm-dai-q6-mi2s-senary {
+ compatible = "qcom,msm-dai-q6-mi2s";
+ qcom,msm-dai-q6-mi2s-dev-id = <6>;
+ qcom,msm-mi2s-rx-lines = <0>;
+ qcom,msm-mi2s-tx-lines = <3>;
+ };
+ };
+
+ lsm: qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ sb_0_rx: qcom,msm-dai-q6-sb-0-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16384>;
+ };
+
+ sb_0_tx: qcom,msm-dai-q6-sb-0-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16385>;
+ };
+
+ sb_1_rx: qcom,msm-dai-q6-sb-1-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16386>;
+ };
+
+ sb_1_tx: qcom,msm-dai-q6-sb-1-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16387>;
+ };
+
+ sb_2_rx: qcom,msm-dai-q6-sb-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16388>;
+ };
+
+ sb_2_tx: qcom,msm-dai-q6-sb-2-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16389>;
+ };
+
+
+ sb_3_rx: qcom,msm-dai-q6-sb-3-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16390>;
+ };
+
+ sb_3_tx: qcom,msm-dai-q6-sb-3-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16391>;
+ };
+
+ sb_4_rx: qcom,msm-dai-q6-sb-4-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16392>;
+ };
+
+ sb_4_tx: qcom,msm-dai-q6-sb-4-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16393>;
+ };
+
+ sb_5_tx: qcom,msm-dai-q6-sb-5-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16395>;
+ };
+
+ sb_5_rx: qcom,msm-dai-q6-sb-5-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16394>;
+ };
+
+ bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12288>;
+ };
+
+ bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12289>;
+ };
+
+ int_fm_rx: qcom,msm-dai-q6-int-fm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12292>;
+ };
+
+ int_fm_tx: qcom,msm-dai-q6-int-fm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <12293>;
+ };
+
+ afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <224>;
+ };
+
+ afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <225>;
+ };
+
+ afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <241>;
+ };
+
+ afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <240>;
+ };
+
+ incall_record_rx: qcom,msm-dai-q6-incall-record-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32771>;
+ };
+
+ incall_record_tx: qcom,msm-dai-q6-incall-record-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32772>;
+ };
+
+ incall_music_rx: qcom,msm-dai-q6-incall-music-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32773>;
+ };
+
+ incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <32770>;
+ };
+
+ sb_6_rx: qcom,msm-dai-q6-sb-6-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <16396>;
+ };
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+ dai_pri_auxpcm: qcom,msm-pri-auxpcm {
+ compatible = "qcom,msm-auxpcm-dev";
+ qcom,msm-cpudai-auxpcm-mode = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-sync = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-frame = <5>, <4>;
+ qcom,msm-cpudai-auxpcm-quant = <2>, <2>;
+ qcom,msm-cpudai-auxpcm-num-slots = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-slot-mapping = <1>, <1>;
+ qcom,msm-cpudai-auxpcm-data = <0>, <0>;
+ qcom,msm-cpudai-auxpcm-pcm-clk-rate = <2048000>, <2048000>;
+ qcom,msm-auxpcm-interface = "primary";
+ };
+
+ hdmi_dba: qcom,msm-hdmi-dba-codec-rx {
+ compatible = "qcom,msm-hdmi-dba-codec-rx";
+ qcom,dba-bridge-chip = "adv7533";
+ };
+
+ qcom,msm-audio-ion {
+ compatible = "qcom,msm-audio-ion";
+ qcom,smmu-version = <1>;
+ qcom,smmu-enabled;
+ iommus = <&adsp_io 1>;
+ };
+
+ qcom,msm-adsp-loader {
+ compatible = "qcom,adsp-loader";
+ qcom,adsp-state = <0>;
+ };
+
+ qcom,avtimer@c0a300c {
+ compatible = "qcom,avtimer";
+ reg = <0x0c0a300c 0x4>,
+ <0x0c0a3010 0x4>;
+ reg-names = "avtimer_lsb_addr", "avtimer_msb_addr";
+ qcom,clk-div = <27>;
+ };
+
+ int_codec: sound {
+ status = "okay";
+ compatible = "qcom,msm8952-audio-codec";
+ qcom,model = "msm8953-snd-card";
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>,
+ <0xc052000 0x4>;
+ reg-names = "csr_gp_io_mux_mic_ctl",
+ "csr_gp_io_mux_spkr_ctl",
+ "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel",
+ "csr_gp_io_mux_quin_ctl";
+
+ qcom,msm-ext-pa = "primary";
+ qcom,msm-mclk-freq = <9600000>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,msm-hs-micbias-type = "external";
+ qcom,msm-micbias1-ext-cap;
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS External", "Handset Mic",
+ "MIC BIAS External2", "Headset Mic",
+ "MIC BIAS External", "Secondary Mic",
+ "AMIC1", "MIC BIAS External",
+ "AMIC2", "MIC BIAS External2",
+ "AMIC3", "MIC BIAS External",
+ "DMIC1", "MIC BIAS Internal1",
+ "MIC BIAS Internal1", "Digital Mic1",
+ "DMIC2", "MIC BIAS Internal1",
+ "MIC BIAS Internal1", "Digital Mic2",
+ "WSA_SPK OUT", "VDD_WSA_SWITCH",
+ "SpkrMono WSA_IN", "WSA_SPK OUT";
+
+ qcom,hdmi-dba-codec-rx;
+
+ qcom,msm-gpios =
+ "pri_i2s",
+ "dmic_gpio",
+ "quin_i2s",
+ "comp_gpio";
+ qcom,pinctrl-names =
+ "all_off",
+ "pri_i2s_act",
+ "dmic_gpio_act",
+ "pri_i2s_dmic_gpio_act",
+ "quin_act",
+ "quin_pri_i2s_act",
+ "quin_dmic_gpio_act",
+ "quin_dmic_gpio_pri_i2s_act",
+ "comp_gpio_act",
+ "comp_gpio_pri_i2s_act",
+ "comp_gpio_dmic_gpio_act",
+ "comp_gpio_pri_i2s_dmic_gpio_act",
+ "comp_gpio_quin_act",
+ "comp_gpio_quin_pri_i2s_act",
+ "comp_gpio_quin_dmic_gpio_act",
+ "comp_gpio_quin_dmic_gpio_pri_i2s_act";
+
+ pinctrl-names =
+ "all_off",
+ "pri_i2s_act",
+ "dmic_gpio_act",
+ "pri_i2s_dmic_gpio_act",
+ "quin_act",
+ "quin_pri_i2s_act",
+ "quin_dmic_gpio_act",
+ "quin_dmic_gpio_pri_i2s_act",
+ "comp_gpio_act",
+ "comp_gpio_pri_i2s_act",
+ "comp_gpio_dmic_gpio_act",
+ "comp_gpio_pri_i2s_dmic_gpio_act",
+ "comp_gpio_quin_act",
+ "comp_gpio_quin_pri_i2s_act",
+ "comp_gpio_quin_dmic_gpio_act",
+ "comp_gpio_quin_dmic_gpio_pri_i2s_act";
+
+ pinctrl-0 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-1 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-2 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-3 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-4 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-5 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-6 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-7 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_sus
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-8 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-9 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-10 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-11 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_sus &pri_tlmm_ws_sus>;
+ pinctrl-12 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-13 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_sus
+ &cdc_dmic_clk_sus &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-14 = <&cdc_pdm_lines_sus &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_sus &cdc_dmic_lines_act
+ &cdc_dmic_clk_act &pri_tlmm_lines_act &pri_tlmm_ws_act>;
+ pinctrl-15 = <&cdc_pdm_lines_act &cdc_pdm_comp_lines_act
+ &cdc_pdm_lines_2_act &cdc_dmic_lines_act
+ &cdc_dmic_lines_act &pri_tlmm_lines_act
+ &pri_tlmm_ws_act>;
+
+ asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
+ <&loopback>, <&compress>, <&hostless>,
+ <&afe>, <&lsm>, <&routing>, <&lpa>;
+ asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
+ "msm-pcm-dsp.2", "msm-voip-dsp",
+ "msm-pcm-voice", "msm-pcm-loopback",
+ "msm-compress-dsp", "msm-pcm-hostless",
+ "msm-pcm-afe", "msm-lsm-client",
+ "msm-pcm-routing", "msm-pcm-lpa";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s0>, <&dai_mi2s1>,
+ <&dai_mi2s2>, <&dai_mi2s3>,
+ <&dai_mi2s5>, <&dai_mi2s6>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_3_rx>, <&sb_3_tx>, <&sb_4_rx>, <&sb_4_tx>,
+ <&bt_sco_rx>, <&bt_sco_tx>,
+ <&int_fm_rx>, <&int_fm_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1",
+ "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3",
+ "msm-dai-q6-mi2s.5", "msm-dai-q6-mi2s.6",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.224", "msm-dai-q6-dev.225",
+ "msm-dai-q6-dev.241", "msm-dai-q6-dev.240",
+ "msm-dai-q6-dev.32771", "msm-dai-q6-dev.32772",
+ "msm-dai-q6-dev.32773", "msm-dai-q6-dev.32770";
+
+ asoc-codec = <&stub_codec>, <&pm8953_diangu_dig>, <&hdmi_dba>;
+ asoc-codec-names = "msm-stub-codec.1", "cajon_codec",
+ "msm-hdmi-dba-codec-rx";
+ asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+ asoc-wsa-codec-prefixes = "SpkrMono";
+
+ msm-vdd-wsa-switch-supply = <&pm8953_l5>;
+ qcom,msm-vdd-wsa-switch-voltage = <1800000>;
+ qcom,msm-vdd-wsa-switch-current = <10000>;
+ };
+
+ clock_audio: audio_ext_clk {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ clock-names = "osr_clk";
+ qcom,node_has_rpm_clock;
+ #clock-cells = <1>;
+ };
+
+};
+
+&adsp_io {
+ qcom,virtual-addr-pool = <0x10000000 0x0fffffff>;
+ #iommu-cells = <1>;
+};
+
+&clock_audio {
+ status = "okay";
+ qcom,audio-ref-clk-gpio = <&pm8953_gpios 1 0>;
+ qcom,lpass-mclk-id = "pri_mclk";
+ clocks = <&clock_gcc clk_div_clk2>;
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&cdc_mclk2_sleep>;
+ pinctrl-1 = <&cdc_mclk2_active>;
+};
+
+&pm8953_1 {
+ status = "okay";
+ pm8953_diangu_dig: 8953_wcd_codec@f000 {
+ status = "okay";
+ compatible = "qcom,msm8x16_wcd_codec";
+ reg = <0xf000 0x100>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x1 0xf0 0x0>,
+ <0x1 0xf0 0x1>,
+ <0x1 0xf0 0x2>,
+ <0x1 0xf0 0x3>,
+ <0x1 0xf0 0x4>,
+ <0x1 0xf0 0x5>,
+ <0x1 0xf0 0x6>,
+ <0x1 0xf0 0x7>;
+ interrupt-names = "spk_cnp_int",
+ "spk_clip_int",
+ "spk_ocp_int",
+ "ins_rem_det1",
+ "but_rel_det",
+ "but_press_det",
+ "ins_rem_det",
+ "mbhc_int";
+
+ cdc-vdda-cp-supply = <&pm8953_s4>;
+ qcom,cdc-vdda-cp-voltage = <1900000 2050000>;
+ qcom,cdc-vdda-cp-current = <500000>;
+
+ cdc-vdd-io-supply = <&pm8953_l5>;
+ qcom,cdc-vdd-io-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-io-current = <5000>;
+
+ cdc-vdd-pa-supply = <&pm8953_s4>;
+ qcom,cdc-vdd-pa-voltage = <1900000 2050000>;
+ qcom,cdc-vdd-pa-current = <260000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>;
+ qcom,cdc-vdd-mic-bias-current = <5000>;
+
+ qcom,cdc-mclk-clk-rate = <9600000>;
+
+ qcom,cdc-static-supplies = "cdc-vdd-io",
+ "cdc-vdd-pa",
+ "cdc-vdda-cp";
+
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+ qcom,dig-cdc-base-addr = <0xc0f0000>;
+ };
+
+ pm8953_diangu_analog: 8953_wcd_codec@f100 {
+ status = "okay";
+ compatible = "qcom,msm8x16_wcd_codec";
+ reg = <0xf100 0x100>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x1 0xf1 0x0>,
+ <0x1 0xf1 0x1>,
+ <0x1 0xf1 0x2>,
+ <0x1 0xf1 0x3>,
+ <0x1 0xf1 0x4>,
+ <0x1 0xf1 0x5>;
+ interrupt-names = "ear_ocp_int",
+ "hphr_ocp_int",
+ "hphl_ocp_det",
+ "ear_cnp_int",
+ "hphr_cnp_int",
+ "hphl_cnp_int";
+ qcom,dig-cdc-base-addr = <0xc0f0000>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lat-concam-dev.dts b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-dev.dts
new file mode 100644
index 0000000..7947008
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-dev.dts
@@ -0,0 +1,159 @@
+/*
+ * 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 "apq8053-lat-concam.dtsi"
+#include "apq8053-camera-sensor-mtp.dtsi"
+#include "apq8053-lat-concam-regulator.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 LAT Concam Dev board";
+ compatible = "qcom,apq8053-mtp", "qcom,apq8053", "qcom,mtp";
+ qcom,board-id= <0x56 0x30>;
+};
+
+&pm8953_mpps {
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ qcom,mode = <4>; // A-input
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <1>; // QPNP_PIN_AIN_AMUX_CH6 = 1 for MPP2
+ qcom,master-en = <1>; //Enable MPP
+ qcom,src-sel = <0>; /* Function constant */
+ status = "okay";
+ };
+
+ mpp@a200 {
+ /* MPP3 - PA_THERM config */
+ reg = <0xa200 0x100>;
+ com,pin-num = <3>;
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <2>; /* AMUX 7 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ status = "okay";
+ };
+
+ mpp@a300 {
+ /* MPP4 - CASE_THERM config */
+ reg = <0xa300 0x100>;
+ com,pin-num = <4>;
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ status = "okay";
+ };
+};
+
+&tlmm {
+ button_active: button_active {
+ mux {
+ pins = "gpio57";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio57";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+
+ icr_int {
+ qcom,pins = <&tlmm 53>;
+ qcom,num-grp-pins = <1>;
+ qcom,pin-func = <0>;
+ label = "icr-int";
+ icr_int_default: icr_int_default {
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up; /* PULL UP*/
+ };
+ };
+
+ gcc_gp1_clk_pin {
+ qcom,pins = <&tlmm 33>;
+ qcom,num-grp-pins = <1>;
+ qcom,pin-func = <2>;
+ label = "gp1-clk-pin";
+ gcc_gp1_clk_pin: gcc_gp1_clk_pin {
+ drive-strength = <2>; /* 2 MA */
+ bias-disable;
+ };
+ };
+
+ bt_host_wake_default: bt_host_wake_default {
+ mux {
+ pins = "gpio52";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio52";
+ bias-disable; /* No PULL */
+ drive-strength = <2>;
+ };
+ };
+};
+
+&soc {
+ usb_detect: usb_detect {
+ compatible = "linux,extcon-usb-gpio";
+ vbus-gpio = <&tlmm 57 GPIO_ACTIVE_HIGH>;
+ qcom,enable-button-mode;
+
+ pinctrl-names = "button_active";
+ pinctrl-0 = <&button_active>;
+ };
+
+ hbtp {
+ status = "disabled";
+ };
+};
+
+&usb3 {
+ extcon = <&usb_detect>;
+};
+
+&firmware {
+ android {
+ vbmeta {
+ compatible = "android,vbmeta";
+ parts = "vbmeta,boot,system,vendor,bluetooth,modem,oem";
+ };
+ fstab {
+ /delete-node/ system;
+ vendor {
+ fsmgr_flags = "wait,slotselect,avb";
+ };
+ };
+ };
+};
+
+&modem_mem {
+ reg = <0x0 0x86c00000 0x0 0x1e00000>;
+};
+
+&wcnss_fw_mem {
+ reg = <0x0 0x89b00000 0x0 0x700000>;
+};
+
+&gpio_key_suspend {
+ config {
+ /delete-property/ bias-pull-up;
+ bias-pull-down;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lat-concam-proto.dts b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-proto.dts
new file mode 100644
index 0000000..f3124bc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-proto.dts
@@ -0,0 +1,161 @@
+/*
+ * 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 "apq8053-lat-concam.dtsi"
+#include "apq8053-camera-sensor-mtp.dtsi"
+#include "apq8053-lat-concam-regulator.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 LAT Concam Dev board";
+ compatible = "qcom,apq8053-mtp", "qcom,apq8053", "qcom,mtp";
+ qcom,board-id= <0x56 0x31>;
+};
+
+
+
+&pm8953_mpps {
+ mpp@a100 {
+ reg = <0xa100 0x100>;
+ qcom,pin-num = <2>;
+ qcom,mode = <4>; // A-input
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <1>; // QPNP_PIN_AIN_AMUX_CH6 = 1 for MPP2
+ qcom,master-en = <1>; //Enable MPP
+ qcom,src-sel = <0>; /* Function constant */
+ status = "okay";
+ };
+
+ mpp@a200 {
+ /* MPP3 - PA_THERM config */
+ reg = <0xa200 0x100>;
+ com,pin-num = <3>;
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <2>; /* AMUX 7 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ status = "okay";
+ };
+
+ mpp@a300 {
+ /* MPP4 - CASE_THERM config */
+ reg = <0xa300 0x100>;
+ com,pin-num = <4>;
+ qcom,mode = <4>; /* AIN input */
+ qcom,invert = <1>; /* Enable MPP */
+ qcom,ain-route = <3>; /* AMUX 8 */
+ qcom,master-en = <1>;
+ qcom,src-sel = <0>; /* Function constant */
+ status = "okay";
+ };
+};
+
+&tlmm {
+ button_active: button_active {
+ mux {
+ pins = "gpio57";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio57";
+ drive-strength = <8>;
+ bias-pull-up;
+ };
+ };
+
+ icr_int {
+ qcom,pins = <&tlmm 53>;
+ qcom,num-grp-pins = <1>;
+ qcom,pin-func = <0>;
+ label = "icr-int";
+ icr_int_default: icr_int_default {
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up; /* PULL UP*/
+ };
+ };
+
+ gcc_gp1_clk_pin {
+ qcom,pins = <&tlmm 33>;
+ qcom,num-grp-pins = <1>;
+ qcom,pin-func = <2>;
+ label = "gp1-clk-pin";
+ gcc_gp1_clk_pin: gcc_gp1_clk_pin {
+ drive-strength = <2>; /* 2 MA */
+ bias-disable;
+ };
+ };
+
+ bt_host_wake_default: bt_host_wake_default {
+ mux {
+ pins = "gpio52";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio52";
+ bias-disable; /* No PULL */
+ drive-strength = <2>;
+ };
+ };
+};
+
+&soc {
+ usb_detect: usb_detect {
+ compatible = "linux,extcon-usb-gpio";
+ vbus-gpio = <&tlmm 57 GPIO_ACTIVE_HIGH>;
+ qcom,enable-button-mode;
+
+ pinctrl-names = "button_active";
+ pinctrl-0 = <&button_active>;
+ };
+
+ hbtp {
+ status = "disabled";
+ };
+};
+
+&usb3 {
+ extcon = <&usb_detect>;
+};
+
+&firmware {
+ android {
+ vbmeta {
+ compatible = "android,vbmeta";
+ parts = "vbmeta,boot,system,vendor,bluetooth,modem,oem";
+ };
+ fstab {
+ /delete-node/ system;
+ vendor {
+ fsmgr_flags = "wait,slotselect,avb";
+ };
+ };
+ };
+};
+
+&modem_mem {
+ reg = <0x0 0x86c00000 0x0 0x1e00000>;
+};
+
+&wcnss_fw_mem {
+ reg = <0x0 0x89b00000 0x0 0x700000>;
+};
+
+&gpio_key_suspend {
+ config {
+ /delete-property/ bias-pull-up;
+ bias-pull-down;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lat-concam-regulator.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-regulator.dtsi
new file mode 100644
index 0000000..8fae286
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lat-concam-regulator.dtsi
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+&rpm_bus {
+ rpm-regulator-ldoa18 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <18>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ pm8953_l18: regulator-l18 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l18";
+ qcom,set = <3>;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <2700000>;
+ };
+
+ };
+
+ rpm-regulator-ldoa9 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <9>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+ regulator-boot-on;
+ regulator-always-on;
+ regulator-l9 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l9";
+ qcom,set = <3>;
+ regulator-boot-on;
+ regulator-always-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa10 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <10>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ regulator-boot-on;
+ regulator-always-on;
+ pm8953_l10: regulator-l10 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l10";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+
+ /* L4 for ALS, TMP, Moisture, Image Sensor, PD Control, Thermistor */
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ regulator-boot-on;
+ regulator-l4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l4";
+ qcom,set = <3>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+ };
+
+ /* l2, l7 and l17 for cci */
+ rpm-regulator-ldoa2 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <2>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+ regulator-l2 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l2";
+ qcom,set = <3>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa7 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <7>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+ regulator-l7 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l7";
+ qcom,set = <3>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+ };
+
+ rpm-regulator-ldoa17 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <17>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+
+ regulator-l17 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l17";
+ qcom,set = <3>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+ };
+
+ /* l6 for eeprom/ Image sensor */
+
+ rpm-regulator-ldoa6 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <6>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+ regulator-l6 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l6";
+ qcom,set = <3>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+ };
+
+ /* l5 for WSA8815 Speaker amp */
+ rpm-regulator-ldoa5 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <5>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-l5 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l5";
+ qcom,set = <3>;
+ regulator-always-on;
+ regulator-boot-on;
+ status = "okay";
+ };
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lat-concam.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lat-concam.dtsi
new file mode 100644
index 0000000..b359db3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lat-concam.dtsi
@@ -0,0 +1,580 @@
+/*
+ * 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 "msm8953.dtsi"
+#include "msm8953-pinctrl.dtsi"
+/ {
+ model = "Qualcomm Technologies, Inc. APQ 8953";
+ compatible = "qcom,apq8053";
+ qcom,msm-id = <304 0x0>;
+};
+
+/ {
+ /delete-property/ aliases;
+
+ aliases {
+ /* smdtty devices */
+ smd1 = &smdtty_apps_fm;
+ smd2 = &smdtty_apps_riva_bt_acl;
+ smd3 = &smdtty_apps_riva_bt_cmd;
+ smd4 = &smdtty_mbalbridge;
+ smd5 = &smdtty_apps_riva_ant_cmd;
+ smd6 = &smdtty_apps_riva_ant_data;
+ smd7 = &smdtty_data1;
+ smd8 = &smdtty_data4;
+ smd11 = &smdtty_data11;
+ smd21 = &smdtty_data21;
+ smd36 = &smdtty_loopback;
+ sdhc1 = &sdhc_1; /* SDC1 eMMC slot */
+ sdhc2 = &sdhc_2; /* SDC2 for SD card */
+ i2c1 = &i2c_1;
+ i2c2 = &i2c_2;
+ i2c3 = &i2c_3;
+ i2c4 = &i2c_4;
+ i2c5 = &i2c_5;
+ i2c7 = &i2c_7;
+ i2c8 = &i2c_8;
+ spi3 = &spi_3;
+ };
+
+};
+
+&sdhc_2 {
+ nest,workaround-ocr-add-vio = "VIO_3_3";
+};
+
+&soc {
+ i2c_4: i2c@78b8000 { /* BLSP1 QUP3 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x78b8000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 98 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp1_qup4_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_4_active>;
+ pinctrl-1 = <&i2c_4_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <86>;
+ dmas = <&dma_blsp1 10 64 0x20000020 0x20>,
+ <&dma_blsp1 11 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c_7: i2c@7AF7000 { /* BLSP2 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x7AF7000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 301 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup3_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_7_active>;
+ pinctrl-1 = <&i2c_7_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <84>;
+ dmas = <&dma_blsp1 8 64 0x20000020 0x20>,
+ <&dma_blsp1 9 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ i2c_8: i2c@7AF8000 { /* BLSP2 QUP3 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x7AF8000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 302 0>;
+ qcom,clk-freq-out = <400000>;
+ qcom,clk-freq-in = <19200000>;
+ clock-names = "iface_clk", "core_clk";
+ clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>,
+ <&clock_gcc clk_gcc_blsp2_qup4_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_8_active>;
+ pinctrl-1 = <&i2c_8_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <84>;
+ dmas = <&dma_blsp1 10 64 0x20000020 0x20>,
+ <&dma_blsp1 11 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ input-name = "gpio-keys";
+ pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+
+ camera_focus {
+ label = "camera_focus";
+ gpios = <&tlmm 87 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 86 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 85 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ };
+ };
+
+ hbtp {
+ compatible = "qcom,hbtp-input";
+ vcc_ana-supply = <&pm8953_l10>;
+ vcc_dig-supply = <&pm8953_l5>;
+ qcom,afe-load = <50000>;
+ qcom,afe-vtg-min = <2850000>;
+ qcom,afe-vtg-max = <2850000>;
+ qcom,dig-load = <15000>;
+ qcom,dig-vtg-min = <1800000>;
+ qcom,dig-vtg-max = <1800000>;
+ };
+};
+
+&soc {
+ qcom,rmnet-ipa {
+ status = "disabled";
+ };
+};
+
+&ipa_hw {
+ status = "disabled";
+};
+
+&secure_mem {
+ status = "disabled";
+};
+
+&tlmm {
+ i2c_4 {
+ i2c_4_active: i2c_4_active {
+ /* active state */
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "blsp_i2c4";
+ };
+
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_4_sleep: i2c_4_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio14", "gpio15";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ i2c_7 {
+ i2c_7_active: i2c_7_active {
+ /* active state */
+ mux {
+ pins = "gpio135", "gpio136";
+ function = "blsp_i2c7";
+ };
+
+ config {
+ pins = "gpio135", "gpio136";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_7_sleep: i2c_7_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio135", "gpio136";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio135", "gpio136";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+
+ i2c_8 {
+ i2c_8_active: i2c_8_active {
+ /* active state */
+ mux {
+ pins = "gpio98", "gpio99";
+ function = "blsp_i2c8";
+ };
+
+ config {
+ pins = "gpio98", "gpio99";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+
+ i2c_8_sleep: i2c_8_sleep {
+ /* suspended state */
+ mux {
+ pins = "gpio98", "gpio99";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio98", "gpio99";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
+};
+
+&blsp1_uart0 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+&i2c_4 {
+ status = "ok";
+
+ opt3001@44 {
+ compatible = "ti,opt3001";
+ reg = <0x44>; /* ALS_ADDR connected to ground */
+ status = "okay";
+ };
+
+ ina231@40 {
+ compatible = "ti,ina231";
+ reg = <0x40>;
+ shunt-resistor = <10000>;
+ };
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS200_1p8v";
+
+ status = "ok";
+};
+
+&i2c_8 {
+ status = "ok";
+
+ tlc59108@42 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <2>;
+ enable-gpio = <&tlmm 61 GPIO_ACTIVE_HIGH>;
+ compatible = "ti,tlc59108";
+ label = "tlc59108";
+ reg = <0x42>;
+
+ chan0@0 {
+ label = "tlc59108:chan0";
+ reg = <0x0>;
+ };
+
+ chan1@1 {
+ label = "tlc59108:chan1";
+ reg = <0x1>;
+ };
+
+ chan2@2 {
+ label = "tlc59108:chan2";
+ reg = <0x2>;
+ };
+
+ chan3@3 {
+ label = "tlc59108:chan3";
+ reg = <0x3>;
+ };
+
+ chan4@4 {
+ label = "tlc59108:chan4";
+ reg = <0x4>;
+ };
+
+ chan5@5 {
+ label = "tlc59108:chan5";
+ reg = <0x5>;
+ };
+
+ chan6@6 {
+ label = "tlc59108:chan6";
+ reg = <0x6>;
+ };
+
+ chan7@7 {
+ label = "tlc59108:chan7";
+ reg = <0x7>;
+ };
+ };
+
+ tlc59116@68 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #gpio-cells = <2>;
+ enable-gpio = <&tlmm 61 GPIO_ACTIVE_HIGH>;
+ compatible = "ti,tlc59116";
+ label = "tlc59116";
+ reg = <0x68>;
+
+ chan0@0 {
+ label = "tlc59116:chan0";
+ reg = <0x0>;
+ };
+
+ chan1@1 {
+ label = "tlc59116:chan1";
+ reg = <0x1>;
+ };
+
+ chan2@2 {
+ label = "tlc59116:chan2";
+ reg = <0x2>;
+ };
+
+ chan3@3 {
+ label = "tlc59116:chan3";
+ reg = <0x3>;
+ };
+
+ chan4@4 {
+ label = "tlc59116:chan4";
+ reg = <0x4>;
+ };
+
+ chan5@5 {
+ label = "tlc59116:chan5";
+ reg = <0x5>;
+ };
+
+ chan6@6 {
+ label = "tlc59116:chan6";
+ reg = <0x6>;
+ };
+
+ chan7@7 {
+ label = "tlc59116:chan7";
+ reg = <0x7>;
+ };
+
+ chan8@8 {
+ label = "tlc59116:chan8";
+ reg = <0x8>;
+ };
+
+ chan9@9 {
+ label = "tlc59116:chan9";
+ reg = <0x9>;
+ };
+
+ chan10@10 {
+ label = "tlc59116:chan10";
+ reg = <0xa>;
+ };
+
+ chan11@11 {
+ label = "tlc59116:chan11";
+ reg = <0xb>;
+ };
+
+ chan12@12 {
+ label = "tlc59116:chan12";
+ reg = <0xc>;
+ };
+
+ chan13@13 {
+ label = "tlc59116:chan13";
+ reg = <0xd>;
+ };
+
+ chan14@14 {
+ label = "tlc59116:chan14";
+ reg = <0xe>;
+ };
+
+ chan15@15 {
+ label = "tlc59116:chan15";
+ reg = <0xf>;
+ };
+ };
+
+};
+
+&i2c_3 {
+ status = "ok";
+ eeprom0: qcom,eeprom@0 {
+ cell-index = <0>;
+ reg = <0x56>;
+ qcom,eeprom-name = "cat24c512";
+ compatible = "qcom,eeprom";
+ qcom,slave-addr = <0x56>;
+ qcom,cci-master = <0>;
+ /* For 512 Kb eeprom chip
+ * add 8 logic eeprom blcoks each is 8KB
+ */
+ qcom,num-blocks = <8>;
+
+ qcom,page0 = <0 0 0 0 0 0>;
+ qcom,poll0 = <0 0 0 0 0 0>;
+ qcom,saddr0 = <0x56>;
+ qcom,mem0 = <8192 0x0000 2 0 1 0>;
+
+ qcom,page1 = <0 0 0 0 0 0>;
+ qcom,poll1 = <0 0 0 0 0 0>;
+ qcom,saddr1 = <0x56>;
+ qcom,mem1 = <8192 0x2000 2 0 1 0>;
+
+ qcom,page2 = <0 0 0 0 0 0>;
+ qcom,poll2 = <0 0 0 0 0 0>;
+ qcom,saddr2 = <0x56>;
+ qcom,mem2 = <8192 0x4000 2 0 1 0>;
+
+ qcom,page3 = <0 0 0 0 0 0>;
+ qcom,poll3 = <0 0 0 0 0 0>;
+ qcom,saddr3 = <0x56>;
+ qcom,mem3 = <8192 0x6000 2 0 1 0>;
+
+ qcom,page4 = <0 0 0 0 0 0>;
+ qcom,poll4 = <0 0 0 0 0 0>;
+ qcom,saddr4 = <0x56>;
+ qcom,mem4 = <8192 0x8000 2 0 1 0>;
+
+ qcom,page5 = <0 0 0 0 0 0>;
+ qcom,poll5 = <0 0 0 0 0 0>;
+ qcom,saddr5 = <0x56>;
+ qcom,mem5 = <8192 0xA000 2 0 1 0>;
+
+ qcom,page6 = <0 0 0 0 0 0>;
+ qcom,poll6 = <0 0 0 0 0 0>;
+ qcom,saddr6 = <0x56>;
+ qcom,mem6 = <8192 0xC000 2 0 1 0>;
+
+ qcom,page7 = <0 0 0 0 0 0>;
+ qcom,poll7 = <0 0 0 0 0 0>;
+ qcom,saddr7 = <0x56>;
+ qcom,mem7 = <8192 0xE000 2 0 1 0>;
+
+ cam_vio-supply = <&pm8953_l6>;
+ qcom,cam-vreg-name = "cam_vio";
+ qcom,cam-vreg-min-voltage = <0>;
+ qcom,cam-vreg-max-voltage = <0>;
+ qcom,cam-vreg-op-mode = <0>;
+ qcom,cam-power-seq-type = "sensor_vreg";
+ qcom,cam-power-seq-val = "cam_vio";
+ qcom,cam-power-seq-cfg-val = <1>;
+ qcom,cam-power-seq-delay = <1>;
+ status = "ok";
+ };
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l10>;
+ qcom,vdd-voltage-level = <18000000 1800000>;
+ qcom,vdd-current-level = <200 22000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l12>;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
+
+ #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 &tlmm 45 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+ /*cd-gpios = <&tlmm 45 0x1>;*/
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
+&pm8953_typec {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi
index 993799b..de707b8 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi
@@ -13,10 +13,23 @@
#include "apq8053-lite-dragon.dtsi"
+&rpm_bus {
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8953_l10: regulator-l10 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3300000>;
+ status = "okay";
+ };
+ };
+};
+
&mdss_dsi0 {
qcom,ext-vdd-gpio = <&tlmm 100 0>;
qcom,platform-bklight-en-gpio = <&tlmm 95 0>;
+ /delete-property/ vdd-supply;
qcom,platform-lane-config = [00 00 ff 0f
00 00 ff 0f
00 00 ff 0f
@@ -66,3 +79,17 @@
&camera2{
qcom,mount-angle = <270>;
};
+
+&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.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.1.dts
new file mode 100644
index 0000000..ef4c7a1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.1.dts
@@ -0,0 +1,32 @@
+/*
+ * 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 "apq8053-lite.dtsi"
+#include "apq8053-lite-dragon-v2.2.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard V2.2.1";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id = <0x01010320 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_inxnt51021_1200p_video>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi
index 1744c90..d4dbc9e 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi
@@ -13,9 +13,94 @@
#include "apq8053-lite-dragon.dtsi"
+&rpm_bus {
+ rpm-regulator-ldoa10 {
+ status = "okay";
+ pm8953_l10: regulator-l10 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ qcom,init-voltage = <3300000>;
+ 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
+ ];
+ };
};
&mdss_mdp {
@@ -32,7 +117,7 @@
pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
- vdd-supply = <&pm8953_l10>;
+ /delete-property/ vdd-supply;
vddio-supply = <&pm8953_l6>;
lab-supply = <&lab_regulator>;
ibb-supply = <&ibb_regulator>;
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 5cf8ac0..830cb17 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
@@ -13,6 +13,15 @@
#include "apq8053-lite-dragon.dtsi"
+&soc {
+ cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&sec_tlmm_lines_act>;
+ pinctrl-1 = <&sec_tlmm_lines_sus>;
+ };
+};
+
&pm8953_l4 {
status = "okay";
regulator-always-on;
@@ -42,6 +51,7 @@
&i2c_3 {
status = "okay";
+ /delete-node/ focaltech@38;
/delete-node/ himax_ts@48;
focaltech_ts@38 {
compatible = "focaltech,fts";
@@ -64,6 +74,7 @@
};
&wled {
+ qcom,cons-sync-write-delay-us = <1000>;
qcom,led-strings-list = [00 01 02];
};
@@ -78,3 +89,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 90b1d4f..6638aac 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
@@ -100,8 +100,8 @@
cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat {
compatible = "qcom,msm-cdc-pinctrl";
pinctrl-names = "aud_active", "aud_sleep";
- pinctrl-0 = <&sec_tlmm_lines_act>;
- pinctrl-1 = <&sec_tlmm_lines_sus>;
+ pinctrl-0 = <&sec_tlmm_lines_act &ext_amp_ctrl_active>;
+ pinctrl-1 = <&sec_tlmm_lines_sus &ext_amp_ctrl_sleep>;
};
gpio_keys {
@@ -123,13 +123,43 @@
qcom,rmnet-ipa {
status = "disabled";
};
+
+ qcom,qca402x {
+ compatible = "qcom,qca402";
+ endpoints = <1>;
+ };
+};
+
+&cdc_pdm_comp_lines_act {
+ mux {
+ pins = "gpio67";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <8>;
+ };
+};
+
+&cdc_pdm_comp_lines_sus {
+ mux {
+ pins = "gpio67";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <2>;
+ bias-disable;
+ };
};
&firmware {
android {
vbmeta {
compatible = "android,vbmeta";
- parts = "vbmeta,boot,system,vendor,bluetooth,modem,oem";
+ parts = "vbmeta,boot,system,vendor,bluetooth,modem,dsp,oem";
};
fstab {
/delete-node/ system;
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-som.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-som.dts
new file mode 100644
index 0000000..eae1118
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-som.dts
@@ -0,0 +1,443 @@
+/*
+ * 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 "apq8053-lite.dtsi"
+#include "msm8953-pinctrl.dtsi"
+#include "pmi8950.dtsi"
+#include "msm8953-pmi8950.dtsi"
+#include "msm8953-mdss-panels.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite SoM";
+};
+
+&soc {
+ vreg_5p0: vreg_5p0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vreg_5p0";
+ status = "ok";
+ enable-active-high;
+ };
+
+ eldo_cam0_vreg: eldo_cam0_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam0_vreg";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ status = "ok";
+ enable-active-high;
+ vin-supply = <&pm8953_l5>;
+ };
+
+ eldo_cam1_vreg: eldo_cam1_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam1_vreg";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ status = "ok";
+ enable-active-high;
+ vin-supply = <&pm8953_l5>;
+ };
+
+ eldo_cam2_vreg: eldo_cam2_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam2_vreg";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ status = "ok";
+ enable-active-high;
+ vin-supply = <&pm8953_l5>;
+ };
+
+ eldo_cam1_vcm_vreg: eldo_cam1_vcm_vreg {
+ compatible = "regulator-fixed";
+ regulator-name = "eldo_cam1_vcm_vreg";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ status = "ok";
+ enable-active-high;
+ };
+
+ 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 = <&pm8953_l6>;
+ 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 */
+ };
+
+ bluetooth: bt_qca9379 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&tlmm 76 0>; /* BT_EN */
+ };
+
+ cdc_dmic_gpios: cdc_dmic_pinctrl {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_dmic0_clk_act &cdc_dmic0_data_act>;
+ pinctrl-1 = <&cdc_dmic0_clk_sus &cdc_dmic0_data_sus>;
+ };
+
+ cdc_quat_mi2s_gpios: msm_cdc_pinctrl_quat {
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&sec_tlmm_lines_act &ext_amp_ctrl_active>;
+ pinctrl-1 = <&sec_tlmm_lines_sus &ext_amp_ctrl_sleep>;
+ };
+};
+
+&cdc_pdm_comp_lines_act {
+ mux {
+ pins = "gpio67";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <8>;
+ };
+};
+
+&cdc_pdm_comp_lines_sus {
+ mux {
+ pins = "gpio67";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio67";
+ drive-strength = <2>;
+ bias-disable;
+ };
+};
+
+&firmware {
+ android {
+ vbmeta {
+ compatible = "android,vbmeta";
+
+ parts = "vbmeta,boot,system,vendor,bluetooth,modem,oem";
+ };
+ fstab {
+ /delete-node/ system;
+ vendor {
+ fsmgr_flags = "wait,slotselect,avb";
+ };
+ };
+ };
+};
+
+&rpm_bus {
+ rpm-regulator-ldoa4 {
+ compatible = "qcom,rpm-smd-regulator-resource";
+ qcom,resource-name = "ldoa";
+ qcom,resource-id = <4>;
+ qcom,regulator-type = <0>;
+ qcom,hpm-min-load = <10000>;
+ status = "okay";
+
+ pm8953_l4: regulator-l4 {
+ compatible = "qcom,rpm-smd-regulator";
+ regulator-name = "pm8953_l4";
+ qcom,set = <3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ qcom,init-voltage = <1800000>;
+ status = "okay";
+ };
+ };
+};
+
+&int_codec {
+ status = "ok";
+ qcom,model = "msm8953-openq624-snd-card";
+
+ /delete-property/ qcom,cdc-us-euro-gpios;
+ qcom,msm-hs-micbias-type = "internal";
+
+ qcom,audio-routing =
+ "RX_BIAS", "MCLK",
+ "SPK_RX_BIAS", "MCLK",
+ "INT_LDO_H", "MCLK",
+ "MIC BIAS Internal1", "Handset Mic",
+ "MIC BIAS Internal2", "Headset Mic",
+ "MIC BIAS Internal1", "Secondary Mic",
+ "AMIC1", "MIC BIAS Internal1",
+ "AMIC2", "MIC BIAS Internal2",
+ "AMIC3", "MIC BIAS Internal1",
+ "DMIC1", "MIC BIAS Internal1",
+ "MIC BIAS Internal1", "Digital Mic1",
+ "DMIC2", "MIC BIAS Internal1",
+ "MIC BIAS Internal1", "Digital Mic2";
+
+ qcom,quat-mi2s-gpios = <&cdc_quat_mi2s_gpios>;
+ qcom,cdc-dmic-gpios = <&cdc_dmic_gpios>;
+
+ /delete-property/ asoc-wsa-codec-names;
+ /delete-property/ asoc-wsa-codec-prefixes;
+ /delete-property/ msm-vdd-wsa-switch-supply;
+ /delete-property/ qcom,msm-vdd-wsa-switch-voltage;
+ /delete-property/ qcom,msm-vdd-wsa-switch-current;
+};
+
+&soc {
+ /delete-node/ hbtp;
+};
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>;
+};
+
+&blsp1_uart0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+
+&blsp2_uart0 {
+ status = "okay";
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8953_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-lpm-sup;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>;
+ pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000
+ 384000000>;
+ qcom,nonremovable;
+ qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v";
+
+ status = "ok";
+};
+
+&tlmm {
+ sdc2_wlan_gpio_on: sdc2_wlan_gpio_on {
+ mux {
+ pins = "gpio75";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio75";
+ drive-strength = <10>;
+ bias-pull-up;
+ output-high;
+ };
+ };
+ sdc2_wlan_gpio_off: sdc2_wlan_gpio_off {
+ mux {
+ pins = "gpio75";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio75";
+ drive-strength = <2>;
+ bias-disable;
+ output-low;
+ };
+ };
+};
+
+&sdhc_2 {
+ /* device communication power supply */
+ vdd-io-supply = <&pm8953_l12>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 22000>;
+
+ qcom,core_3_0v_support;
+ qcom,nonremovable;
+
+ 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,clk-rates = <400000 20000000 25000000 50000000 100000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
+&spmi_bus {
+ qcom,pm8953@0 {
+ qcom,power-on@800 {
+ qcom,resin-gpiobase = <1019>;
+ qcom,pon_2 {
+ /delete-property/ linux,code;
+ };
+ };
+ };
+ qcom,pmi8950@2 {
+ qcom,leds@a100 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa100 0x100>;
+ label = "mpp";
+
+ qcom,led_mpp_2 {
+ label = "mpp";
+ linux,name = "green";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+
+ qcom,leds@a300 {
+ compatible = "qcom,leds-qpnp";
+ reg = <0xa300 0x100>;
+ label = "mpp";
+
+ qcom,led_mpp_4 {
+ label = "mpp";
+ linux,name = "blue";
+ linux,default-trigger = "none";
+ qcom,default-state = "off";
+ qcom,max-current = <40>;
+ qcom,current-setting = <5>;
+ qcom,id = <6>;
+ qcom,mode = "manual";
+ qcom,source-sel = <1>;
+ qcom,mode-ctrl = <0x60>;
+ };
+ };
+ };
+};
+
+&pm8953_typec {
+ ss-mux-supply = <&pm8953_l13>;
+ qcom,ssmux-gpio = <&tlmm 139 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&typec_ssmux_config>;
+};
+
+/{
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&pmi_haptic{
+ status = "disabled";
+ qcom,actuator-type = "lra";
+ qcom,lra-auto-res-mode="qwd";
+ qcom,lra-high-z="opt1";
+ qcom,lra-res-cal-period = <0>;
+ qcom,wave-play-rate-us = <4165>;
+};
+
+&flash_led {
+ status = "disabled";
+};
+
+&pm8953_pwm {
+ status = "ok";
+};
+
+&pm8953_vadc {
+ /delete-node/ chan@13;
+};
+
+&pmi8950_gpios {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmi_gpio1_default>;
+ pmi_gpio1_default: pmi8950_gpio1 {
+ pins = "gpio1";
+ function = "normal";
+ input-enable;
+ power-source = <0>;
+ status = "okay";
+ };
+};
+
+&pmi8950_mpps {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ext_fet_wled_pwr_en_default>;
+ ext_fet_wled_pwr_en_default: pmi8950_mpp3 {
+ pins = "mpp3"; /* MPP_3 */
+ function = "digital"; /* Digital */
+ output-high; /* Output */
+ drive-strength = <2>; /* 1.8 mA */
+ power-source = <1>;
+ bias-disable = <0>; /* no pull */
+ status = "okay";
+ };
+};
+
+&pm8953_gpios {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pm_gpio1_div_clk2_default>;
+ pm_gpio1_div_clk2_default: pm8953_gpio1 {
+ pins = "gpio1";
+ function = "normal";
+ output-high;
+ power-source = <1>;
+ status = "okay";
+ };
+};
+
+&pm8953_mpps {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pm_mpp4_wled_pwm_ctrl_default>;
+ pm_mpp4_wled_pwm_ctrl_default: pm8953_mpp4 {
+ pins = "mpp4"; /* WLED_PWM_CTRL */
+ function = "digital"; /* Digital */
+ output-high; /* Output */
+ drive-strength = <2>; /* 1.8 mA */
+ power-source = <0>; /* VPH_PWR */
+ qcom,dtest = <1>; /* DTEST1 */
+ bias-disable = <0>; /* no pull */
+ status = "okay";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite.dtsi
index 5be35e7..c9d7160 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-hx83100a-800p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi
index 03c3659..995ca4d 100644
--- a/arch/arm64/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-hx83100a-800p-video.dtsi
@@ -41,16 +41,6 @@
39 01 00 00 78 00 02 11 00
/*set display on and delay 20ms*/
39 01 00 00 14 00 02 29 00
- /*enable extended command set*/
- 39 01 00 00 00 00 04 b9 83 10 0a
- /*32KHZ PWM*/
- 39 01 00 00 00 00 08 c9 1f 00 08 1e 81 1e 00
- /*backlight enable*/
- 39 01 00 00 00 00 02 53 24
- /*still picture and delay 5ms*/
- 39 01 00 00 05 00 02 55 02
- /*about 80% duty ratio*/
- 39 01 00 00 00 00 0a ca 40 3c 38 34 33 32 30 2c 28
];
qcom,mdss-dsi-off-command = [05 01 00 00 96 00 02 28 00
05 01 00 00 00 00 02 10 00];
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 0000000..69f168b
--- /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 89c5178..7a71154 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/dsi-panel-inxnt51021-1200p-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-inxnt51021-1200p-video.dtsi
new file mode 100644
index 0000000..2131aec
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/dsi-panel-inxnt51021-1200p-video.dtsi
@@ -0,0 +1,106 @@
+/* Novatek Android Driver Sample Code for Novatek chipset
+*
+* Copyright (C) 2015 Novatek Microelectronics Corp.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+&mdss_mdp {
+ dsi_inxnt51021_1200p_video: qcom,mdss_dsi_inxnt51021_1200p_video {
+ qcom,mdss-dsi-panel-name = "inxnt51021 1200p video mode dsi panel";
+ qcom,mdss-dsi-panel-controller = <&mdss_dsi0>;
+ 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 = <1200>;
+ qcom,mdss-dsi-panel-height = <1920>;
+ qcom,mdss-dsi-h-front-porch = <100>;
+ qcom,mdss-dsi-h-back-porch = <32>;
+ qcom,mdss-dsi-h-pulse-width = <1>;
+ qcom,mdss-dsi-h-sync-skew = <0>;
+ qcom,mdss-dsi-v-back-porch = <14>;
+ qcom,mdss-dsi-v-front-porch = <25>;
+ qcom,mdss-dsi-v-pulse-width = <1>;
+ qcom,mdss-dsi-h-left-border = <0>;
+ qcom,mdss-dsi-h-right-border = <0>;
+ qcom,mdss-dsi-v-top-border = <0>;
+ qcom,mdss-dsi-v-bottom-border = <0>;
+ qcom,mdss-dsi-bpp = <24>;
+ qcom,mdss-dsi-underflow-color = <0xff>;
+ qcom,mdss-dsi-border-color = <0>;
+ qcom,mdss-dsi-on-command = [
+ 23 01 00 00 01 00 02 8F A5
+ 23 01 00 00 00 00 02 83 00
+ 23 01 00 00 00 00 02 84 00
+ 23 01 00 00 00 00 02 8C 84
+ 23 01 00 00 00 00 02 C5 50
+ 23 01 00 00 00 00 02 C7 50
+ 23 01 00 00 00 00 02 85 04
+ 23 01 00 00 00 00 02 86 08
+ 23 01 00 00 00 00 02 83 AA
+ 23 01 00 00 00 00 02 84 11
+ 23 01 00 00 00 00 02 9C 10
+ 23 01 00 00 00 00 02 A9 4B
+ 23 01 00 00 00 00 02 A0 36
+ 23 01 00 00 00 00 02 A1 36
+ 23 01 00 00 00 00 02 C0 00
+ 23 01 00 00 00 00 02 E0 3D
+ 23 01 00 00 00 00 02 83 BB
+ 23 01 00 00 00 00 02 84 22
+ 23 01 00 00 00 00 02 C0 00
+ 23 01 00 00 00 00 02 E0 3D
+ 23 01 00 00 00 00 02 83 CC
+ 23 01 00 00 00 00 02 84 33
+ 23 01 00 00 00 00 02 C0 00
+ 23 01 00 00 00 00 02 E0 3D
+ 23 01 00 00 00 00 02 8F 00
+ ];
+ qcom,mdss-dsi-off-command = [
+ 23 01 00 00 01 00 02 8F A5
+ 23 01 00 00 00 00 02 83 00
+ 23 01 00 00 78 00 02 84 00
+ 05 01 00 00 78 00 02 10 00
+ ];
+ qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-off-command-state = "dsi_lp_mode";
+ //qcom,cont-splash-enabled;
+ qcom,mdss-dsi-h-sync-pulse = <1>;
+ qcom,mdss-dsi-traffic-mode = "burst_mode";
+ qcom,mdss-dsi-lane-map = "lane_map_0123";
+ qcom,mdss-dsi-bllp-eof-power-mode;
+ qcom,mdss-dsi-bllp-power-mode;
+ qcom,mdss-dsi-lane-0-state;
+ qcom,mdss-dsi-lane-1-state;
+ qcom,mdss-dsi-lane-2-state;
+ qcom,mdss-dsi-lane-3-state;
+ qcom,mdss-dsi-panel-timings = [f2 3a 28 00 6c 70 2c 3e 2e 03 04 00];
+ qcom,mdss-dsi-t-clk-post = <0x0e>;
+ qcom,mdss-dsi-t-clk-pre = <0x33>;
+ qcom,mdss-dsi-bl-min-level = <1>;
+ qcom,mdss-dsi-bl-max-level = <4095>;
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-dma-trigger = "trigger_sw";
+ qcom,mdss-dsi-mdp-trigger = "none";
+ qcom,mdss-dsi-force-clock-lane-hs;
+ //qcom,platform-bklight-en-gpio = <&tlmm 46 0>;
+ //qcom,mdss-dsi-lcden-ctrl = <&tlmm 61 0>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
+ //qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ //qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ //qcom,mdss-dsi-pwm-gpio = <&pm8953_mpps 4 0>;
+ qcom,mdss-pan-physical-width-dimension = <135>;
+ qcom,mdss-pan-physical-height-dimension = <216>;
+ //qcom,mdss-dsi-reset-sequence = <1 10>, <0 5>, <1 50>;
+ qcom,mdss-dsi-lp11-init;
+ qcom,mdss-dsi-post-init-delay = <1>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
index e2fbc9e..ee2d0ac 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
@@ -113,17 +113,17 @@
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
- pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-names = "default";
pinctrl-0 = <&gpio_key_active>;
- pinctrl-1 = <&gpio_key_suspend>;
camera_focus {
label = "camera_focus";
gpios = <&msm_gpio 91 0x1>;
linux,input-type = <1>;
linux,code = <0x210>;
- gpio-key,wakeup;
debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
};
camera_snapshot {
@@ -131,8 +131,9 @@
gpios = <&msm_gpio 92 0x1>;
linux,input-type = <1>;
linux,code = <0x2fe>;
- gpio-key,wakeup;
debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
};
vol_up {
@@ -140,8 +141,9 @@
gpios = <&msm_gpio 90 0x1>;
linux,input-type = <1>;
linux,code = <115>;
- gpio-key,wakeup;
debounce-interval = <15>;
+ linux,can-disable;
+ gpio-key,wakeup;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi
index 1e3e497..8c06c93 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 f841097..3389d29 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 36a67af..7c3e932 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 0000000..23545f9
--- /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 377eda4..73ea29b 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 <dt-bindings/clock/msm-clocks-8952.h>
#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 6a2fecd..7690931 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 <dt-bindings/clock/msm-clocks-8952.h>
+#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 920bcae..0540e09 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 <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/clock/msm-clocks-8952.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#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 7f35e1e..9a3b6dae 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 <dt-bindings/clock/msm-clocks-8952.h>
#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 858936d..0e613b6 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 {
+ nfc_int_active: nfc_int_active {
+ /* active state */
+ mux {
+ /* GPIO 17 NFC Read Interrupt */
+ pins = "gpio17";
+ function = "gpio";
+ };
- nfc_int_active: active {
- drive-strength = <6>;
- bias-pull-up;
+ 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";
+ };
- 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: active {
- drive-strength = <6>;
- bias-pull-up;
+ config {
+ pins = "gpio17";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up;
+ };
};
- nfc_disable_suspend: suspend {
- drive-strength = <6>;
- bias-disable;
+ nfc_disable_active: nfc_disable_active {
+ /* active state */
+ mux {
+ /* 16: NFC ENABLE 130: FW DNLD */
+ pins = "gpio16", "gpio130";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio16", "gpio130";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-up;
+ };
+ };
+
+ 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-pmi8940.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
index 9b9cd47..9212d2d 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940.dtsi
@@ -33,3 +33,13 @@
qcom,switch-source = <&pmi8940_switch>;
};
};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&mdss_dsi0 {
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
index e86b9d7..95e003b 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
@@ -22,3 +22,13 @@
&usb_otg {
extcon = <&qpnp_smbcharger>;
};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&mdss_dsi0 {
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/msm8917-qrd-overlay.dts
index 6517757..c0dc217 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 <dt-bindings/clock/msm-clocks-8952.h>
#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 d5fd1ff..6a4c10e 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 <dt-bindings/clock/msm-clocks-8952.h>
#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/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi
index cc51694..d5f5243 100644
--- a/arch/arm64/boot/dts/qcom/msm8917.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi
@@ -68,14 +68,6 @@
fsmgr_flags = "wait,avb";
status = "ok";
};
- system {
- compatible = "android,system";
- dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
- type = "ext4";
- mnt_flags = "ro,barrier=1,discard";
- fsmgr_flags = "wait,avb";
- status = "ok";
- };
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index 85e3043..5180d1a 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -45,15 +45,6 @@
fsmgr_flags = "wait,avb";
status = "ok";
};
- system {
- compatible = "android,system";
- dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
- type = "ext4";
- mnt_flags = "ro,barrier=1,discard";
- fsmgr_flags = "wait,avb";
- status = "ok";
- };
-
};
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
index 7bc181c..fa218ca 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-mdss-panels.dtsi
@@ -26,6 +26,8 @@
#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"
+#include "dsi-panel-inxnt51021-1200p-video.dtsi"
&soc {
dsi_panel_pwr_supply: dsi_panel_pwr_supply {
@@ -184,3 +186,19 @@
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];
+};
+
+&dsi_inxnt51021_1200p_video {
+ qcom,mdss-dsi-panel-timings-phy-v2 = [25 20 08 0A 06 03 04 a0
+ 25 20 08 0A 06 03 04 a0
+ 25 20 08 0A 06 03 04 a0
+ 25 20 08 0A 06 03 04 a0
+ 25 1D 08 0A 06 03 04 a0];
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
index 65b2397..72513e1 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953-pinctrl.dtsi
@@ -466,6 +466,34 @@
};
};
+ ext_amp_ctrl {
+ label = "ext_amp_ctrl";
+ ext_amp_ctrl_active: ext_amp_ctrl_active {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio68";
+ drive-strength = <8>; /* 8 MA */
+ bias-pull-up; /* PULL UP */
+ output-high;
+ };
+ };
+
+ ext_amp_ctrl_sleep: ext_amp_ctrl_sleep {
+ mux {
+ pins = "gpio68";
+ function = "gpio";
+ };
+ configs {
+ pins = "gpio68";
+ drive-strength = <2>; /* 2 MA */
+ bias-pull-down; /* PULL DOWN */
+ };
+ };
+ };
+
cdc_dmic0_clk_act: cdc_dmic0_clk_act_default {
mux {
pins = "gpio89";
@@ -1461,6 +1489,103 @@
};
/* 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 {
mux {
diff --git a/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi b/arch/arm64/boot/dts/qcom/msm8953-regulator.dtsi
index 5a4f024..31e882f 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 3ab3b2b..efe01f7 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -55,14 +55,6 @@
fsmgr_flags = "wait,avb";
status = "ok";
};
- system {
- compatible = "android,system";
- dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
- type = "ext4";
- mnt_flags = "ro,barrier=1,discard";
- fsmgr_flags = "wait,avb";
- status = "ok";
- };
};
};
diff --git a/arch/arm64/boot/dts/qcom/pmi8937.dtsi b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
index c72225d..829e733 100644
--- a/arch/arm64/boot/dts/qcom/pmi8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi8937.dtsi
@@ -12,6 +12,8 @@
*/
#include <dt-bindings/msm/power-on.h>
+#include <dt-bindings/spmi/spmi.h>
+#include <dt-bindings/interrupt-controller/irq.h>
&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-360camera.dtsi b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
index 63bb25f..f5f3b3c 100644
--- a/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605-360camera.dtsi
@@ -184,6 +184,8 @@
"MIC BIAS External2", "Digital Mic3",
"DMIC4", "MIC BIAS External2",
"MIC BIAS External2", "Digital Mic4",
+ "MICBIAS_REGULATOR", "VDDA18_L10_REGULATOR",
+ "VDDA18_L10_REGULATOR", "VDD_L1_REGULATOR",
"PDM_IN_RX1", "PDM_OUT_RX1",
"PDM_IN_RX2", "PDM_OUT_RX2",
"PDM_IN_RX3", "PDM_OUT_RX3",
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 0000000..ab82fe6
--- /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 <dt-bindings/clock/qcom,audio-ext-clk.h>
+
+&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-base.dts b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-base.dts
new file mode 100644
index 0000000..622230c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/qcs605-lc-ipcamera-base.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 "qcs605-lc.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. QCS605 LC SoC Ipcam base";
+ compatible = "qcom,qcs605";
+ qcom,board-id = <0 4>;
+};
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 0000000..0cb7c33
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 = <0x020208 4>;
+};
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 0000000..37dc8e0
--- /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 = <0x020208 4>;
+};
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 0000000..d6d9a17
--- /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 61a812c..7801775 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 fcffd44..ea385bd 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/sda845-v2-hdk.dtsi b/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dtsi
index 378c4a1..d89a60e 100644
--- a/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda845-v2-hdk.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -91,3 +91,8 @@
qcom,afe-power-off-delay-us = <6>;
};
};
+
+&qupv3_se5_i2c {
+ status = "disabled";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi
index 77da1f3..9bb8a6c 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-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi
index eae8c56..2987d67 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-camera-sensor-mtp.dtsi
@@ -30,7 +30,7 @@
cell-index = <1>;
reg = <0x1>;
compatible = "qcom,actuator";
- qcom,cci-master = <0>;
+ qcom,cci-master = <1>;
cam_vaf-supply = <&pm8953_l17>;
qcom,cam-vreg-name = "cam_vaf";
qcom,cam-vreg-min-voltage = <2850000>;
@@ -156,6 +156,43 @@
qcom,clock-rates = <19200000 0>;
};
+ eeprom2: qcom,eeprom@2 {
+ cell-index = <2>;
+ compatible = "qcom,eeprom";
+ qcom,cci-master = <1>;
+ reg = <0x2>;
+ cam_vdig-supply = <&pm8953_l3>;
+ cam_vana-supply = <&pm8953_l22>;
+ cam_vio-supply = <&pm8953_l6>;
+ cam_vaf-supply = <&pm8953_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";
+ 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";
@@ -249,9 +286,9 @@
qcom,csiphy-sd-index = <1>;
qcom,csid-sd-index = <1>;
qcom,mount-angle = <90>;
- qcom,eeprom-src = <&eeprom1>;
+ qcom,eeprom-src = <&eeprom2>;
qcom,actuator-src = <&actuator1>;
- cam_vdig-supply = <&pm8953_l23>;
+ cam_vdig-supply = <&pm8953_l3>;
cam_vana-supply = <&pm8953_l22>;
cam_vio-supply = <&pm8953_l6>;
cam_vaf-supply = <&pm8953_l17>;
@@ -278,7 +315,7 @@
"CAM_STANDBY2";
qcom,sensor-position = <1>;
qcom,sensor-mode = <0>;
- qcom,cci-master = <0>;
+ qcom,cci-master = <1>;
status = "ok";
clocks = <&clock_gcc clk_mclk2_clk_src>,
<&clock_gcc clk_gcc_camss_mclk2_clk>;
diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi
index be05b6e..9067bc9 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-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi
index 4d6b32f..f55c050 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-audio-overlay.dtsi
@@ -124,6 +124,8 @@
"MIC BIAS External", "Digital Mic3",
"DMIC4", "MIC BIAS External",
"MIC BIAS External", "Digital Mic4",
+ "MICBIAS_REGULATOR", "VDDA18_L10_REGULATOR",
+ "VDDA18_L10_REGULATOR", "VDD_L1_REGULATOR",
"SpkrLeft IN", "SPK1 OUT",
"SpkrRight IN", "SPK2 OUT",
"PDM_IN_RX1", "PDM_OUT_RX1",
@@ -501,12 +503,22 @@
qcom,cdc-vdd-mic-bias-voltage = <3088000 3088000>;
qcom,cdc-vdd-mic-bias-current = <5000>;
+ cdc-vdda18-l10-supply = <&pm660_l10>;
+ qcom,cdc-vdda18-l10-voltage = <1800000 1800000>;
+ qcom,cdc-vdda18-l10-current = <30000>;
+
+ cdc-vdd-l1-supply = <&pm660l_l1>;
+ qcom,cdc-vdd-l1-voltage = <880000 880000>;
+ qcom,cdc-vdd-l1-current = <30000>;
+
qcom,cdc-mclk-clk-rate = <9600000>;
qcom,cdc-static-supplies = "cdc-vdda-cp",
"cdc-vdd-pa";
- qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias";
+ qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias",
+ "cdc-vdda18-l10",
+ "cdc-vdd-l1";
/*
* Not marking address @ as driver searches this child
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 c40fff6..1cfa3ae 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 237152d..76b7b05 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>;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm670-ion.dtsi
index 3fd1229..0968a52 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 0461429..0453cee 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-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index 5ff2c32..2b6b641 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -195,6 +195,8 @@
"AMIC1", "MIC BIAS External",
"MIC BIAS External", "Secondary Mic",
"AMIC3", "MIC BIAS External",
+ "MICBIAS_REGULATOR", "VDDA18_L10_REGULATOR",
+ "VDDA18_L10_REGULATOR", "VDD_L1_REGULATOR",
"SpkrLeft IN", "SPK1 OUT",
"PDM_IN_RX1", "PDM_OUT_RX1",
"PDM_IN_RX2", "PDM_OUT_RX2",
diff --git a/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm670-sde.dtsi
index 4ca4001..fb717f3 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 575e448..bb07c04 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-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index 9b88356..c53367a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -141,7 +141,9 @@
0x198 /* PLL_BIAS_CONTROL_2 */
0x228 /* QUSB2PHY_SQ_CTRL1 */
0x22c /* QUSB2PHY_SQ_CTRL2 */
- 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x27c /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x280 /* QUSB2PHY_DEBUG_CTRL2 */
+ 0x2a0>; /* QUSB2PHY_STAT5 */
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
@@ -431,7 +433,9 @@
0x198 /* PLL_BIAS_CONTROL_2 */
0x228 /* QUSB2PHY_SQ_CTRL1 */
0x22c /* QUSB2PHY_SQ_CTRL2 */
- 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x27c /* QUSB2PHY_DEBUG_CTRL1 */
+ 0x280 /* QUSB2PHY_DEBUG_CTRL2 */
+ 0x2a0>; /* QUSB2PHY_STAT5 */
qcom,qusb-phy-init-seq =
/* <value reg_offset> */
diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi
index e77dcc3..86b1704 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>,
@@ -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";
};
@@ -892,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>,
@@ -922,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>,
@@ -952,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>,
@@ -1074,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/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 20878c0..be8416f 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 e7af39f..2b3fd84 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 98%
rename from arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
rename to arch/arm64/boot/dts/qcom/sdw3100-msm8909w-wtp.dts
index 255c146..89f0bb8 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 0000000..5fc70df
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..7bcd1b6
--- /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 0000000..d2153c5
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..b1d701e
--- /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 0000000..3288a64f
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..6dbb766
--- /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 0000000..432035f
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..4e134c5
--- /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 0000000..f8a2a9a
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..7f9f155
--- /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 0000000..288f0ed
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..ea5f197
--- /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 0000000..9d7a706
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..04a045f
--- /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 0000000..7d92bfc
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..c551ef9
--- /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 0000000..a3f8044
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..a3c56fc
--- /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 0000000..a90d550
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..c3bf64b
--- /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 0000000..4b07f5a
--- /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 <dt-bindings/clock/qcom,gcc-sdm845.h>
+#include <dt-bindings/clock/qcom,camcc-sdm845.h>
+#include <dt-bindings/clock/qcom,dispcc-sdm845.h>
+#include <dt-bindings/clock/qcom,rpmh.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#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 0000000..e311b61
--- /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 0000000..abbf334
--- /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 0000000..75707b1
--- /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 bf35544..02d853a 100644
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -72,6 +72,7 @@
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_ARM64_SW_TTBR0_PAN=y
# CONFIG_ARM64_VHE is not set
CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
@@ -543,6 +544,7 @@
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 +589,8 @@
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 +635,7 @@
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 ba390c4..a2b4abb 100644
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -75,6 +75,7 @@
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_ARM64_SW_TTBR0_PAN=y
# CONFIG_ARM64_VHE is not set
CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
@@ -560,6 +561,7 @@
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 +608,8 @@
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 +701,7 @@
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 eeb1d74..698857a 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -73,6 +73,7 @@
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_ARM64_SW_TTBR0_PAN=y
# CONFIG_ARM64_VHE is not set
CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
@@ -471,6 +472,7 @@
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 +558,7 @@
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 +603,8 @@
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 +649,7 @@
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 d0783cd..6434a8e 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -76,6 +76,7 @@
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
CONFIG_SETEND_EMULATION=y
+CONFIG_ARM64_SW_TTBR0_PAN=y
# CONFIG_ARM64_VHE is not set
CONFIG_RANDOMIZE_BASE=y
CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y
@@ -481,6 +482,7 @@
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 +574,7 @@
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 +622,8 @@
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 +661,6 @@
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 +715,7 @@
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 6740bd7..ac21b63 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -513,6 +513,7 @@
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 53fb1cd..9a6da1f 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -527,6 +527,7 @@
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 0c54182..358b37b 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -516,6 +516,8 @@
CONFIG_QCOM_LLCC_PERFMON=m
CONFIG_MSM_SERVICE_LOCATOR=y
CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y
+CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_QCOM_EUD=y
CONFIG_QCOM_WATCHDOG_V2=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index ab983e0..c9f60b5 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -528,6 +528,8 @@
CONFIG_QCOM_LLCC_PERFMON=m
CONFIG_MSM_SERVICE_LOCATOR=y
CONFIG_MSM_SERVICE_NOTIFIER=y
+CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y
+CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y
CONFIG_MSM_BOOT_STATS=y
CONFIG_MSM_CORE_HANG_DETECT=y
CONFIG_MSM_GLADIATOR_HANG_DETECT=y
diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
index 7457ce0..d32a016 100644
--- a/arch/arm64/include/asm/atomic_lse.h
+++ b/arch/arm64/include/asm/atomic_lse.h
@@ -117,7 +117,7 @@
/* 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 @@
/* 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 @@
/* 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 @@
" 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
/* 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 @@
" 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 @@
/* 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 @@
" 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 b3423f5..829331c 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 <linux/jump_label.h>
-
#include <asm/cpucaps.h>
#include <asm/hwcap.h>
#include <asm/sysreg.h>
@@ -27,6 +25,8 @@
#ifndef __ASSEMBLY__
+#include <linux/bug.h>
+#include <linux/jump_label.h>
#include <linux/kernel.h>
extern const char *machine_name;
@@ -98,6 +98,7 @@
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 @@
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 @@
num, ARM64_NCAPS);
} else {
__set_bit(num, cpu_hwcaps);
- static_branch_enable(&cpu_hwcap_keys[num]);
}
}
@@ -202,7 +215,7 @@
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 0a33ea3..2abb449 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -24,6 +24,7 @@
#include <linux/types.h>
#include <linux/kvm_types.h>
+#include <asm/cpufeature.h>
#include <asm/kvm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmio.h>
@@ -358,9 +359,12 @@
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 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 24a8369..ecc2ae6 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -341,7 +341,7 @@
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 24c780d..1464b50 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -38,7 +38,7 @@
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 675bf45..2eea592 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -762,7 +762,7 @@
* 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 @@
__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 __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 @@
* we return.
*/
stop_machine(caps->enable, (void *)caps, cpu_online_mask);
+ }
+ }
}
/*
@@ -1163,6 +1173,14 @@
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 @@
/* 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 @@
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 08ca9dc..0a66fa1d 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -360,7 +360,7 @@
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 01e88c8..8e2c1d6 100644
--- a/arch/arm64/mm/ioremap.c
+++ b/arch/arm64/mm/ioremap.c
@@ -64,6 +64,11 @@
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 3a9af60..efb32b2 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -241,8 +241,9 @@
.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 6e4955b..fcd52ce 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -88,7 +88,8 @@
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 6054d49..8c9cbf1 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -212,6 +212,12 @@
*/
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 ecabc00..853b2f4 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -412,6 +412,8 @@
__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 df78b2c..22a6782 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(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 2f7c734..0df911e 100644
--- a/arch/mips/kernel/mcount.S
+++ b/arch/mips/kernel/mcount.S
@@ -116,10 +116,20 @@
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 @@
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 6e716a5..ebb575c 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -699,6 +699,10 @@
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 8f7bf74..4f64913 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -838,7 +838,7 @@
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 bc9afba..b1e9457 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -107,7 +107,7 @@
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 903e76a..e220010 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 @@
#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 7b33234..0bf8202 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -189,6 +189,22 @@
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 @@
#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 dc0996b..9d97810 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 0000000..44989b2
--- /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 6825a67..3f160cd 100644
--- a/arch/powerpc/include/asm/setup.h
+++ b/arch/powerpc/include/asm/setup.h
@@ -48,7 +48,7 @@
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 adb52d1..1388578 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -44,7 +44,7 @@
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 9e05c88..ff45d00 100644
--- a/arch/powerpc/kernel/cpu_setup_power.S
+++ b/arch/powerpc/kernel/cpu_setup_power.S
@@ -28,6 +28,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 2dc52e6..e24ae0f 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -586,6 +586,7 @@
* 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 94b5dfb..d50cc9b 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -846,7 +846,7 @@
#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 @@
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 @@
##_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 8f0c7c5..93a6eeb 100644
--- a/arch/powerpc/kernel/fadump.c
+++ b/arch/powerpc/kernel/fadump.c
@@ -1033,6 +1033,9 @@
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 469d86d..532c585 100644
--- a/arch/powerpc/kernel/hw_breakpoint.c
+++ b/arch/powerpc/kernel/hw_breakpoint.c
@@ -175,8 +175,8 @@
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 d973708..adfa63e 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -2380,6 +2380,7 @@
/* 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 0000000..2277df8
--- /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 <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/device.h>
+#include <linux/seq_buf.h>
+
+#include <asm/security_features.h>
+
+
+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 5243501..fdba106 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -679,6 +679,7 @@
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 @@
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 @@
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 @@
}
}
-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 @@
#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 @@
}
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 b61fb79..c16fddb 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -134,6 +134,20 @@
#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 = .;
*(__rfi_flush_fixup)
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index 46c8338..cf1398e 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -22,6 +22,7 @@
#include <asm/page.h>
#include <asm/sections.h>
#include <asm/setup.h>
+#include <asm/security_features.h>
#include <asm/firmware.h>
#include <asm/setup.h>
@@ -117,6 +118,120 @@
}
#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 @@
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 f602307..9ed90c5 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -3424,7 +3424,6 @@
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 6f8b4c1..17203ab 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -37,53 +37,92 @@
#include <asm/smp.h>
#include <asm/tm.h>
#include <asm/setup.h>
+#include <asm/security_features.h>
#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"))
+ init_fw_feat_flags(fw_features);
+ of_node_put(fw_features);
+
+ if (security_ftr_enabled(SEC_FTR_L1D_FLUSH_TRIG2))
type = L1D_FLUSH_MTTRIG;
- of_node_put(np);
-
- 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 @@
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 6a5e746..3784a7a 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -314,6 +314,9 @@
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 b1be7b7..62ff57c 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -79,4 +79,6 @@
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 1845fc6..91ade77 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -66,6 +66,7 @@
#include <asm/reg.h>
#include <asm/plpar_wrappers.h>
#include <asm/kexec.h>
+#include <asm/security_features.h>
#include "pseries.h"
@@ -450,35 +451,78 @@
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 @@
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 a4fd000..771cfd2 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -1187,7 +1187,7 @@
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 @@
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 f87a55d..9b3f2e2 100644
--- a/arch/sparc/kernel/ds.c
+++ b/arch/sparc/kernel/ds.c
@@ -908,7 +908,7 @@
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 d6b6c97..703127a 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 60a391b..dd19584 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 78d1c6a..eb53c2c 100644
--- a/arch/x86/include/asm/barrier.h
+++ b/arch/x86/include/asm/barrier.h
@@ -37,7 +37,7 @@
{
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 c278f27..aea30af 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 2737366..8852e3a 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -62,7 +62,7 @@
*/
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 fc3c7e4..ae357d0 100644
--- a/arch/x86/include/asm/kvm_emulate.h
+++ b/arch/x86/include/asm/kvm_emulate.h
@@ -105,11 +105,12 @@
* @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 @@
* @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 b0fd028..7a4279d 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -848,6 +848,13 @@
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 f46071c..3e0199e 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-severity.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
@@ -143,6 +143,11 @@
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 7bbd50f..c49e146 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -738,23 +738,25 @@
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 @@
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 @@
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 6f0ab305..9f36578 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();
}
/*
@@ -234,82 +231,16 @@
}
/*
- * 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
* xfeatures_mask is enumerated.
*/
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;
+ return XCNTXT_MASK;
}
-/*
- * Disable features dependent on eagerfpu.
- */
-static void __init fpu__clear_eager_fpu_features(void)
-{
- setup_clear_cpu_cap(X86_FEATURE_MPX);
-}
-
-/*
- * 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 @@
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_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 91c48cd..516be61 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -414,25 +414,38 @@
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 @@
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 0bee04d..b57100a 100644
--- a/arch/x86/kernel/quirks.c
+++ b/arch/x86/kernel/quirks.c
@@ -643,12 +643,19 @@
/* 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 f214293..5bbfa2f 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -799,16 +799,18 @@
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 4ef267f..e783a5d 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -352,8 +352,6 @@
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 c383697..8a841b9 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -179,7 +179,7 @@
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 c8d5738..510cfc0 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -802,6 +802,19 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
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 ebceda2..7cb1077 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -6928,8 +6928,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 4aa265a..5ca23af 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4395,11 +4395,10 @@
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 @@
}
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 @@
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 @@
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 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 e8ff3e4..2133a18 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -161,11 +161,11 @@
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 f92bdb9..ae9b84c 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -653,7 +653,9 @@
*/
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 e3a3f5a..2986a13 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -472,6 +472,12 @@
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 @@
xen_init_irq_ops();
xen_init_cpuid_mask();
+ xen_init_capabilities();
#ifdef CONFIG_X86_LOCAL_APIC
/*
@@ -1978,12 +1985,6 @@
}
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 @@
.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 a11540e..8eca26e 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -28,6 +28,7 @@
#include <xen/interface/vcpu.h>
#include <xen/interface/xenpmu.h>
+#include <asm/spec-ctrl.h>
#include <asm/xen/interface.h>
#include <asm/xen/hypercall.h>
@@ -87,6 +88,8 @@
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 @@
}
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 ce37d5b..44bd9a3 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -334,7 +334,7 @@
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 ce2df8c..7e6a43f 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -249,6 +249,15 @@
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 01de42c..bb2a5b5 100644
--- a/drivers/android/Kconfig
+++ b/drivers/android/Kconfig
@@ -32,9 +32,9 @@
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 0e2c0ac..82c59a1 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4426,9 +4426,6 @@
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 f3a65a3..0ad96c6 100644
--- a/drivers/ata/libata-zpodd.c
+++ b/drivers/ata/libata-zpodd.c
@@ -34,7 +34,7 @@
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 @@
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 81bfeec..d0fac64 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -1151,8 +1151,8 @@
}
-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 4272868..4bb8016 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -764,7 +764,7 @@
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 @@
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 @@
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 @@
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 @@
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) : "<NULL>");
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 94001aa..e494a93 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -651,7 +651,7 @@
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 c6755c9..51c233c 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -269,8 +269,8 @@
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 194db0e2..8beee2a 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -3900,7 +3900,6 @@
{
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 @@
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 74b2f4a..3a8b9ae 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -939,6 +939,12 @@
} 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 d84dea6..c582701 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 @@
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 {
@@ -301,6 +313,7 @@
unsigned int latency;
bool glink;
bool legacy;
+ bool secure_flag;
spinlock_t ctxlock;
struct smq_invoke_ctx *ctxtable[FASTRPC_CTX_MAX];
};
@@ -380,6 +393,8 @@
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 +1869,11 @@
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 +2506,31 @@
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)
{
@@ -2945,6 +2989,9 @@
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);
for (j = 0; j < chan->sesscount; j++) {
sess = &chan->session[j];
@@ -2972,6 +3019,9 @@
"%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:");
spin_lock(&fl->hlock);
@@ -3107,6 +3157,19 @@
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 +3186,8 @@
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 +3215,24 @@
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 &&
+ fl->apps->secure_flag == true) {
+ /*
+ * 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 +3292,18 @@
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 +3367,27 @@
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 +3604,16 @@
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 +3821,25 @@
}
}
+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 +3850,7 @@
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 +3860,19 @@
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) {
+ me->secure_flag = true;
+ configure_secure_channels(secure_domains);
+ } else {
+ me->secure_flag = false;
+ 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 +4018,7 @@
{
struct fastrpc_apps *me = &gfa;
struct device *dev = NULL;
+ struct device *secure_dev = NULL;
int err = 0, i;
memset(me, 0, sizeof(*me));
@@ -3893,6 +4026,7 @@
fastrpc_init(me);
me->dev = NULL;
me->glink = true;
+ me->secure_flag = false;
VERIFY(err, 0 == platform_driver_register(&fastrpc_driver));
if (err)
goto register_bail;
@@ -3903,7 +4037,7 @@
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 +4045,30 @@
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 +4093,11 @@
&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 +4119,15 @@
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 952b87c..25a2ad8 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 a7f29e6..acee74a 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 @@
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 @@
diag_debug_mask = (uint16_t)value;
return count;
}
+#endif
#ifdef CONFIG_DIAGFWD_BRIDGE_CODE
#ifdef CONFIG_USB_QCOM_DIAG_BRIDGE
@@ -1086,9 +1088,11 @@
.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 @@
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 4b8dd1b..839c8ca 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 44cf56c..a3c19c4 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -169,6 +169,9 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 c00fbfc..393f20fb 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -160,11 +160,12 @@
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 @@
}
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 @@
}
}
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 @@
}
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 @@
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 a169230..8b089eb 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -162,7 +162,7 @@
#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 @@
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 ac4394b..a6d5ca8 100644
--- a/drivers/char/diag/diagfwd_cntl.c
+++ b/drivers/char/diag/diagfwd_cntl.c
@@ -668,7 +668,7 @@
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 @@
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 2022e7b..848ce06 100644
--- a/drivers/char/diag/diagfwd_peripheral.c
+++ b/drivers/char/diag/diagfwd_peripheral.c
@@ -191,6 +191,7 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ 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 feafdab..4835b58 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -522,11 +522,12 @@
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 9ff8532..8d097d1 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/freezer.h>
#include <linux/major.h>
+#include <linux/of.h>
#include "tpm.h"
#include "tpm_eventlog.h"
@@ -388,8 +389,20 @@
*/
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 830d7e3..faf2db1 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -803,6 +803,10 @@
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 @@
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 aa4299c..a4fc2ba 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -143,6 +143,7 @@
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 45ad168..2bb2551 100644
--- a/drivers/clk/at91/clk-pll.c
+++ b/drivers/clk/at91/clk-pll.c
@@ -132,19 +132,8 @@
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 25c41cd..7ecc5ea 100644
--- a/drivers/clk/renesas/renesas-cpg-mssr.c
+++ b/drivers/clk/renesas/renesas-cpg-mssr.c
@@ -243,8 +243,9 @@
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 @@
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 @@
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 f474e70..6e16d9f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -773,6 +773,8 @@
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 854a567..fd96af1 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -32,9 +32,31 @@
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 @@
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 @@
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/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index e692f660..3c75997 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -83,7 +83,7 @@
};
static struct system_pm_ops *sys_pm_ops;
-
+static DEFINE_SPINLOCK(bc_timer_lock);
struct lpm_cluster *lpm_root_node;
@@ -1029,6 +1029,7 @@
struct lpm_cluster_level *level = &cluster->levels[idx];
struct cpumask online_cpus, cpumask;
unsigned int cpu;
+ int ret = 0;
cpumask_and(&online_cpus, &cluster->num_children_in_sync,
cpu_online_mask);
@@ -1067,9 +1068,13 @@
clear_predict_history();
clear_cl_predict_history();
- if (sys_pm_ops && sys_pm_ops->enter)
- if ((sys_pm_ops->enter(&cpumask)))
+ if (sys_pm_ops && sys_pm_ops->enter) {
+ spin_lock(&bc_timer_lock);
+ ret = sys_pm_ops->enter(&cpumask);
+ spin_unlock(&bc_timer_lock);
+ if (ret)
return -EBUSY;
+ }
}
/* Notify cluster enter event after successfully config completion */
cluster_notify(cluster, level, true);
@@ -1202,8 +1207,11 @@
level = &cluster->levels[cluster->last_level];
if (level->notify_rpm)
- if (sys_pm_ops && sys_pm_ops->exit)
+ if (sys_pm_ops && sys_pm_ops->exit) {
+ spin_lock(&bc_timer_lock);
sys_pm_ops->exit();
+ spin_unlock(&bc_timer_lock);
+ }
update_debug_pc_event(CLUSTER_EXIT, cluster->last_level,
cluster->num_children_in_sync.bits[0],
@@ -1298,6 +1306,7 @@
{
int affinity_level = 0, state_id = 0, power_state = 0;
bool success = false;
+ int ret = 0;
/*
* idx = 0 is the default LPM state
*/
@@ -1310,7 +1319,17 @@
}
if (from_idle && cpu->levels[idx].use_bc_timer) {
- if (tick_broadcast_enter())
+ /*
+ * tick_broadcast_enter can change the affinity of the
+ * broadcast timer interrupt, during which interrupt will
+ * be disabled and enabled back. To avoid system pm ops
+ * doing any interrupt state save or restore in between
+ * this window hold the lock.
+ */
+ spin_lock(&bc_timer_lock);
+ ret = tick_broadcast_enter();
+ spin_unlock(&bc_timer_lock);
+ if (ret)
return success;
}
diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c
index 8643667..19f2289 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 @@
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 @@
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 d8305dd..ff6ac4e 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -1081,7 +1081,7 @@
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 022c7ab..b0cd5af 100644
--- a/drivers/crypto/vmx/aes.c
+++ b/drivers/crypto/vmx/aes.c
@@ -53,8 +53,6 @@
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 94ad5c0..4613170 100644
--- a/drivers/crypto/vmx/aes_cbc.c
+++ b/drivers/crypto/vmx/aes_cbc.c
@@ -55,8 +55,6 @@
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 7cf6d31..6ef7548 100644
--- a/drivers/crypto/vmx/aes_ctr.c
+++ b/drivers/crypto/vmx/aes_ctr.c
@@ -53,8 +53,6 @@
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 27a94a1..1c4b5b8 100644
--- a/drivers/crypto/vmx/ghash.c
+++ b/drivers/crypto/vmx/ghash.c
@@ -64,8 +64,6 @@
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 6b54e02..e48140e 100644
--- a/drivers/dma-buf/dma-buf.c
+++ b/drivers/dma-buf/dma-buf.c
@@ -551,7 +551,7 @@
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 fff2ae9..0ce5bd9 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -559,6 +559,7 @@
{
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 @@
(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 @@
(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 @@
/* 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 @@
/* 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 @@
{
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 @@
{
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 @@
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 @@
&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 @@
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 @@
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 @@
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,8 +2571,8 @@
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);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 56b2419..dd00764 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3204,6 +3204,8 @@
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 @@
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 6394109..876a2d9 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -1062,6 +1062,7 @@
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 ca227e8..847ba40 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -205,6 +205,7 @@
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 3517c0e..479d641 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -864,6 +864,14 @@
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 359655a..6e6efa5 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -104,7 +104,7 @@
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 @@
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 @@
goto error;
buf = kzalloc(SZ_4K, GFP_KERNEL);
- if (!buf) {
+ if (ZERO_OR_NULL_PTR(buf)) {
rc = -ENOMEM;
goto error;
}
@@ -538,7 +538,7 @@
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 @@
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 @@
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 d9839e7..a0a0daf 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_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 2b7b217..f277ac0 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 @@
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 @@
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 @@
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 d58a746..9e251da 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 @@
return 0;
buf = kzalloc(max_len, GFP_KERNEL);
- if (!buf)
+ if (ZERO_OR_NULL_PTR(buf))
return -ENOMEM;
mutex_lock(&display->display_lock);
@@ -1161,7 +1161,7 @@
goto error;
}
- if (copy_to_user(user_buf, buf, len)) {
+ if (copy_to_user(user_buf, buf, max_len)) {
rc = -EFAULT;
goto error;
}
@@ -1248,7 +1248,7 @@
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 @@
}
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 1880ad1..85b92f59 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1559,14 +1559,14 @@
return rc;
error_free_payloads:
for (i = i - 1; i >= 0; i--) {
- cmd--;
- kfree(cmd->msg.tx_buf);
+ kfree(cmd[i].msg.tx_buf);
+ cmd[i].msg.tx_buf = NULL;
}
return rc;
}
-void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set)
+static void dsi_panel_destroy_cmds_packets_buf(struct dsi_panel_cmd_set *set)
{
u32 i = 0;
struct dsi_cmd_desc *cmd;
@@ -1574,9 +1574,15 @@
for (i = 0; i < set->count; i++) {
cmd = &set->cmds[i];
kfree(cmd->msg.tx_buf);
+ cmd->msg.tx_buf = NULL;
}
+}
+static void dsi_panel_destroy_cmd_packets(struct dsi_panel_cmd_set *set)
+{
+ dsi_panel_destroy_cmds_packets_buf(set);
kfree(set->cmds);
+ set->count = 0;
}
static int dsi_panel_alloc_cmd_packets(struct dsi_panel_cmd_set *cmd,
@@ -3160,10 +3166,13 @@
if (!mode->priv_info)
return;
+ kfree(mode->priv_info->phy_timing_val);
+
for (i = 0; i < DSI_CMD_SET_MAX; i++)
dsi_panel_destroy_cmd_packets(&mode->priv_info->cmd_sets[i]);
kfree(mode->priv_info);
+ mode->priv_info = NULL;
}
int dsi_panel_get_mode(struct dsi_panel *panel,
@@ -3363,9 +3372,9 @@
if (rc) {
pr_err("[%s] failed to send DSI_CMD_SET_PPS cmds, rc=%d\n",
panel->name, rc);
- goto error;
}
+ dsi_panel_destroy_cmds_packets_buf(set);
error:
mutex_unlock(&panel->panel_lock);
return rc;
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index fcdddb3..978aba2 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -158,6 +158,7 @@
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/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index ddd4607..00f9707 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -80,6 +80,9 @@
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ if (obj->import_attach)
+ return msm_obj->pages;
+
if (!msm_obj->pages) {
struct drm_device *dev = obj->dev;
struct page **p;
@@ -572,8 +575,13 @@
struct page **pages = get_pages(obj);
if (IS_ERR(pages))
return ERR_CAST(pages);
- msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
+ if (obj->import_attach)
+ msm_obj->vaddr = dma_buf_vmap(
+ obj->import_attach->dmabuf);
+ else
+ msm_obj->vaddr = vmap(pages, obj->size >> PAGE_SHIFT,
VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+
if (msm_obj->vaddr == NULL)
return ERR_PTR(-ENOMEM);
}
@@ -659,7 +667,11 @@
if (!msm_obj->vaddr || WARN_ON(!is_vunmapable(msm_obj)))
return;
- vunmap(msm_obj->vaddr);
+ if (obj->import_attach)
+ dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
+ else
+ vunmap(msm_obj->vaddr);
+
msm_obj->vaddr = NULL;
}
@@ -1012,7 +1024,7 @@
struct msm_gem_object *msm_obj;
struct drm_gem_object *obj = NULL;
uint32_t size;
- int ret, npages;
+ int ret;
/* if we don't have IOMMU, don't bother pretending we can import: */
if (!iommu_present(&platform_bus_type)) {
@@ -1033,19 +1045,9 @@
drm_gem_private_object_init(dev, obj, size);
- npages = size / PAGE_SIZE;
-
msm_obj = to_msm_bo(obj);
msm_obj->sgt = sgt;
- msm_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
- if (!msm_obj->pages) {
- ret = -ENOMEM;
- goto fail;
- }
-
- ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages);
- if (ret)
- goto fail;
+ msm_obj->pages = NULL;
return obj;
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 34d8400..cb4e82d 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -3689,6 +3689,7 @@
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 @@
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 @@
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 @@
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 @@
{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 @@
"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 @@
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 @@
}
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 99177b1..709a51f 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -59,6 +59,18 @@
};
/**
+ * enum sde_crtc_idle_pc_state: states of idle power collapse
+ * @IDLE_PC_NONE: no-op
+ * @IDLE_PC_ENABLE: enable idle power-collapse
+ * @IDLE_PC_DISABLE: disable idle power-collapse
+ */
+enum sde_crtc_idle_pc_state {
+ IDLE_PC_NONE,
+ IDLE_PC_ENABLE,
+ IDLE_PC_DISABLE,
+};
+
+/**
* @connectors : Currently associated drm connectors for retire event
* @num_connectors: Number of associated drm connectors for retire event
* @list: event list
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 73864b6..e7b7a6e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -200,7 +200,8 @@
* @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 @@
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;
@@ -258,6 +259,7 @@
struct kthread_work input_event_work;
struct kthread_work esd_trigger_work;
struct input_handler *input_handler;
+ bool input_handler_registered;
struct msm_display_topology topology;
bool vblank_enabled;
@@ -265,6 +267,8 @@
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)
@@ -740,6 +744,7 @@
if (sde_enc->input_handler) {
kfree(sde_enc->input_handler);
sde_enc->input_handler = NULL;
+ sde_enc->input_handler_registered = false;
}
kfree(sde_enc);
@@ -1849,6 +1854,7 @@
return rc;
}
+ sde_enc->elevated_ahb_vote = true;
/* enable DSI clks */
rc = sde_connector_clk_ctrl(sde_enc->cur_master->connector,
true);
@@ -1922,6 +1928,25 @@
&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 +1973,7 @@
* 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 +1981,9 @@
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 +2373,7 @@
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;
}
@@ -2611,6 +2636,7 @@
input_handler->private = sde_enc;
sde_enc->input_handler = input_handler;
+ sde_enc->input_handler_registered = false;
return rc;
}
@@ -2689,14 +2715,12 @@
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");
@@ -2734,12 +2758,14 @@
return;
}
- if (sde_enc->input_handler) {
+ if (sde_enc->input_handler && !sde_enc->input_handler_registered) {
ret = _sde_encoder_input_handler_register(
sde_enc->input_handler);
if (ret)
SDE_ERROR(
"input handler registration failed, rc = %d\n", ret);
+ else
+ sde_enc->input_handler_registered = true;
}
ret = sde_encoder_resource_control(drm_enc, SDE_ENC_RC_EVENT_KICKOFF);
@@ -2817,14 +2843,17 @@
SDE_EVT32(DRMID(drm_enc));
+ if (sde_enc->input_handler && sde_enc->input_handler_registered) {
+ input_unregister_handler(sde_enc->input_handler);
+ sde_enc->input_handler_registered = false;
+ }
+
+
/* 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 +3327,8 @@
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 +3406,20 @@
_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 +4528,7 @@
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 42b9e58..c40db41 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_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 d363d62..74bf518 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 @@
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 @@
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 82dd64a..4bbcb3a 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_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 @@
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 9a4c785..ed0e7b8 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -926,6 +926,12 @@
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 @@
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 @@
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 450695d..fb79fe7 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.h
+++ b/drivers/gpu/drm/msm/sde/sde_kms.h
@@ -288,6 +288,8 @@
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 @@
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/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 67ea2ce..39d0fdc 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -136,7 +136,10 @@
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 917dcb9..9259a2f 100644
--- a/drivers/gpu/drm/udl/udl_transfer.c
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -152,11 +152,11 @@
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 @@
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 757f9d73..2585a27 100644
--- a/drivers/gpu/msm/adreno.c
+++ b/drivers/gpu/msm/adreno.c
@@ -294,11 +294,11 @@
*/
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 @@
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 @@
.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 fbf298d..fc32fb9 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -327,6 +327,29 @@
};
/**
+ * 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
* @core: Match for the core version of the GPU
diff --git a/drivers/gpu/msm/adreno_ioctl.c b/drivers/gpu/msm/adreno_ioctl.c
index aa8c2bf..82629c6 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 @@
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 @@
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 b5999e6..2293919 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 @@
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 @@
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 3b55fc6..d3bbea3 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -541,7 +541,7 @@
*/
spin_lock(&proc_priv->ctxt_count_lock);
if (atomic_read(&proc_priv->ctxt_count) > KGSL_MAX_CONTEXTS_PER_PROC) {
- KGSL_DRV_ERR(device,
+ KGSL_DRV_ERR_RATELIMIT(device,
"Per process context limit reached for pid %u",
dev_priv->process_priv->pid);
spin_unlock(&proc_priv->ctxt_count_lock);
@@ -764,7 +764,7 @@
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 @@
/* 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 @@
}
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 c8c6456..4a98a24 100644
--- a/drivers/gpu/msm/kgsl_device.h
+++ b/drivers/gpu/msm/kgsl_device.h
@@ -156,6 +156,8 @@
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 acfb522..2942369 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -1152,6 +1152,8 @@
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 @@
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 @@
}
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 2548c5d..00bce00 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -477,7 +477,7 @@
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 20d647d..00aafe0 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 @@
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 @@
* 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 @@
*
* 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 @@
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 @@
*
* 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 @@
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 700145b..b59b15d 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -35,6 +35,7 @@
#include <linux/hiddev.h>
#include <linux/compat.h>
#include <linux/vmalloc.h>
+#include <linux/nospec.h>
#include "usbhid.h"
#ifdef CONFIG_USB_DYNAMIC_MINORS
@@ -478,10 +479,14 @@
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 @@
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 @@
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 @@
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 1ed92d6..5399670 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 @@
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 @@
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 @@
{
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 @@
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);
- goto fail_unlock;
- }
-
- }
-
- 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 =
- vadc->adc->adc_channels[dt_index].fast_avg_setup;
- 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);
- 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");
+ 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 =
+ vadc->adc->adc_channels[dt_index].fast_avg_setup;
+ 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;
}
}
- 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 b8e2992..f260922 100644
--- a/drivers/hwtracing/stm/core.c
+++ b/drivers/hwtracing/stm/core.c
@@ -27,6 +27,7 @@
#include <linux/stm.h>
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include "stm.h"
#include <uapi/linux/stm.h>
@@ -689,7 +690,7 @@
{
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 @@
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 @@
/* 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 c712866..abe1798 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -524,8 +524,16 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 726615e..c7592fe 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -700,6 +700,8 @@
pm_runtime_get_sync(dev);
+ rcar_i2c_init(priv);
+
ret = rcar_i2c_bus_barrier(priv);
if (ret < 0)
goto out;
@@ -857,8 +859,6 @@
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 c5b999f..e44181f 100644
--- a/drivers/iio/buffer/kfifo_buf.c
+++ b/drivers/iio/buffer/kfifo_buf.c
@@ -19,11 +19,18 @@
#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 @@
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 7dda14e..15d52dc 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 <linux/regulator/consumer.h>
+
+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 @@
.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_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 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 @@
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_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;
- icm20602_ldo_work(st, true);
+ ret = icm20602_ldo_work(true);
+ if (ret == MPU_FAIL)
+ return 0;
+
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 b369ae4..36f8e9c 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 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 ae04826..a32dd85 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -437,7 +437,7 @@
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 148b313..d30b3b9 100644
--- a/drivers/infiniband/hw/hfi1/chip.c
+++ b/drivers/infiniband/hw/hfi1/chip.c
@@ -6717,7 +6717,7 @@
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 @@
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 @@
/* 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 @@
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 bb72976..d612f9d 100644
--- a/drivers/infiniband/hw/hfi1/file_ops.c
+++ b/drivers/infiniband/hw/hfi1/file_ops.c
@@ -609,7 +609,7 @@
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 a3279f3d..a79d9b3 100644
--- a/drivers/infiniband/hw/hfi1/hfi.h
+++ b/drivers/infiniband/hw/hfi1/hfi.h
@@ -1631,6 +1631,7 @@
#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 ae1f90d..9dc8cf0 100644
--- a/drivers/infiniband/hw/hfi1/init.c
+++ b/drivers/infiniband/hw/hfi1/init.c
@@ -857,6 +857,10 @@
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 @@
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 @@
.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 @@
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 @@
u64 reg;
if (!rcd->rcvhdrq) {
- dma_addr_t dma_hdrqtail;
gfp_t gfp_flags;
/*
@@ -1628,13 +1640,13 @@
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 18d309e..d9323d7 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -1897,7 +1897,6 @@
"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 fc62a7d..a19ebb1 100644
--- a/drivers/infiniband/hw/mlx5/cq.c
+++ b/drivers/infiniband/hw/mlx5/cq.c
@@ -645,7 +645,7 @@
}
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 @@
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 @@
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 a3e21a2..ef092cc 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -1250,6 +1250,7 @@
#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 @@
/*
* 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 382466a..cc6a923 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -364,6 +364,8 @@
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 @@
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 1730aa8..caf7c51 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -878,6 +878,10 @@
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 @@
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 @@
.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 @@
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 75f0862..4715edf 100644
--- a/drivers/infiniband/hw/qib/qib_user_pages.c
+++ b/drivers/infiniband/hw/qib/qib_user_pages.c
@@ -98,23 +98,27 @@
*
* 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 b879d21..02a5e2d 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -879,15 +879,9 @@
}
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 @@
}
}
+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 @@
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 @@
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/Kconfig b/drivers/input/misc/Kconfig
index f8a987a..ee32e1a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -184,6 +184,15 @@
reporting the change in status of the KPDPWR_N line (connected to the
power-key) as well as reset features.
+config INPUT_QTI_HAPTICS
+ tristate "Haptics support for QTI PMIC"
+ depends on MFD_SPMI_PMIC
+ help
+ This option enables device driver support for the haptics peripheral
+ found on Qualcomm Technologies, Inc. PMICs. The haptics peripheral
+ is capable of driving both LRA and ERM vibrators. This module provides
+ haptic feedback for user actions such as a long press on the touch screen.
+
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
depends on PCI && SPARC64
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 149273c..c08ee8f 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -61,6 +61,7 @@
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_QPNP_POWER_ON) += qpnp-power-on.o
+obj-$(CONFIG_INPUT_QTI_HAPTICS) += qti-haptics.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c
index 93c28ef..65379ed 100644
--- a/drivers/input/misc/qpnp-power-on.c
+++ b/drivers/input/misc/qpnp-power-on.c
@@ -487,6 +487,19 @@
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 @@
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 @@
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 @@
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/qti-haptics.c b/drivers/input/misc/qti-haptics.c
new file mode 100644
index 0000000..d63ced7
--- /dev/null
+++ b/drivers/input/misc/qti-haptics.c
@@ -0,0 +1,1471 @@
+/* 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 <linux/device.h>
+#include <linux/err.h>
+#include <linux/hrtimer.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/uaccess.h>
+#include <linux/types.h>
+
+enum actutor_type {
+ ACT_LRA,
+ ACT_ERM,
+};
+
+enum lra_res_sig_shape {
+ RES_SIG_SINE,
+ RES_SIG_SQUARE,
+};
+
+enum lra_auto_res_mode {
+ AUTO_RES_MODE_ZXD,
+ AUTO_RES_MODE_QWD,
+};
+
+enum wf_src {
+ INT_WF_VMAX,
+ INT_WF_BUFFER,
+ EXT_WF_AUDIO,
+ EXT_WF_PWM,
+};
+
+enum haptics_custom_effect_param {
+ CUSTOM_DATA_EFFECT_IDX,
+ CUSTOM_DATA_TIMEOUT_SEC_IDX,
+ CUSTOM_DATA_TIMEOUT_MSEC_IDX,
+ CUSTOM_DATA_LEN,
+};
+
+/* common definitions */
+#define HAP_BRAKE_PATTERN_MAX 4
+#define HAP_WAVEFORM_BUFFER_MAX 8
+#define HAP_VMAX_MV_DEFAULT 1800
+#define HAP_VMAX_MV_MAX 3596
+#define HAP_ILIM_MA_DEFAULT 400
+#define HAP_ILIM_MA_MAX 800
+#define HAP_PLAY_RATE_US_DEFAULT 5715
+#define HAP_PLAY_RATE_US_MAX 20475
+#define HAP_PLAY_RATE_US_LSB 5
+#define VMAX_MIN_PLAY_TIME_US 20000
+#define HAP_SC_DET_MAX_COUNT 5
+#define HAP_SC_DET_TIME_US 1000000
+#define FF_EFFECT_COUNT_MAX 32
+
+/* haptics module register definitions */
+#define REG_HAP_STATUS1 0x0A
+#define HAP_SC_DET_BIT BIT(3)
+#define HAP_BUSY_BIT BIT(1)
+
+#define REG_HAP_EN_CTL1 0x46
+#define HAP_EN_BIT BIT(7)
+
+#define REG_HAP_EN_CTL2 0x48
+#define HAP_AUTO_STANDBY_EN_BIT BIT(1)
+#define HAP_BRAKE_EN_BIT BIT(0)
+
+#define REG_HAP_EN_CTL3 0x4A
+#define HAP_HBRIDGE_EN_BIT BIT(7)
+#define HAP_PWM_SIGNAL_EN_BIT BIT(6)
+#define HAP_ILIM_EN_BIT BIT(5)
+#define HAP_ILIM_CC_EN_BIT BIT(4)
+#define HAP_AUTO_RES_RBIAS_EN_BIT BIT(3)
+#define HAP_DAC_EN_BIT BIT(2)
+#define HAP_ZX_HYST_EN_BIT BIT(1)
+#define HAP_PWM_CTL_EN_BIT BIT(0)
+
+#define REG_HAP_AUTO_RES_CTRL 0x4B
+#define HAP_AUTO_RES_EN_BIT BIT(7)
+#define HAP_SEL_AUTO_RES_PERIOD BIT(6)
+#define HAP_AUTO_RES_CNT_ERR_DELTA_MASK GENMASK(5, 4)
+#define HAP_AUTO_RES_CNT_ERR_DELTA_SHIFT 4
+#define HAP_AUTO_RES_ERR_RECOVERY_BIT BIT(3)
+#define HAP_AUTO_RES_EN_DLY_MASK GENMASK(2, 0)
+#define AUTO_RES_CNT_ERR_DELTA(x) (x << HAP_AUTO_RES_CNT_ERR_DELTA_SHIFT)
+#define AUTO_RES_EN_DLY(x) x
+
+#define REG_HAP_CFG1 0x4C
+#define REG_HAP_CFG2 0x4D
+#define HAP_LRA_RES_TYPE_BIT BIT(0)
+
+#define REG_HAP_SEL 0x4E
+#define HAP_WF_SOURCE_MASK GENMASK(5, 4)
+#define HAP_WF_SOURCE_SHIFT 4
+#define HAP_WF_TRIGGER_BIT BIT(0)
+#define HAP_WF_SOURCE_VMAX (0 << HAP_WF_SOURCE_SHIFT)
+#define HAP_WF_SOURCE_BUFFER (1 << HAP_WF_SOURCE_SHIFT)
+#define HAP_WF_SOURCE_AUDIO (2 << HAP_WF_SOURCE_SHIFT)
+#define HAP_WF_SOURCE_PWM (3 << HAP_WF_SOURCE_SHIFT)
+
+#define REG_HAP_AUTO_RES_CFG 0x4F
+#define HAP_AUTO_RES_MODE_BIT BIT(7)
+#define HAP_AUTO_RES_MODE_SHIFT 7
+#define HAP_AUTO_RES_CAL_DURATON_MASK GENMASK(6, 5)
+#define HAP_CAL_EOP_EN_BIT BIT(3)
+#define HAP_CAL_PERIOD_MASK GENMASK(2, 0)
+#define HAP_CAL_OPT3_EVERY_8_PERIOD 2
+
+#define REG_HAP_SLEW_CFG 0x50
+#define REG_HAP_VMAX_CFG 0x51
+#define HAP_VMAX_SIGN_BIT BIT(7)
+#define HAP_VMAX_OVD_BIT BIT(6)
+#define HAP_VMAX_MV_MASK GENMASK(5, 1)
+#define HAP_VMAX_MV_SHIFT 1
+#define HAP_VMAX_MV_LSB 116
+
+#define REG_HAP_ILIM_CFG 0x52
+#define REG_HAP_SC_DEB_CFG 0x53
+#define REG_HAP_RATE_CFG1 0x54
+#define REG_HAP_RATE_CFG2 0x55
+#define REG_HAP_INTERNAL_PWM 0x56
+#define REG_HAP_EXTERNAL_PWM 0x57
+#define REG_HAP_PWM 0x58
+
+#define REG_HAP_SC_CLR 0x59
+#define HAP_SC_CLR_BIT BIT(0)
+
+#define REG_HAP_ZX_CFG 0x5A
+#define HAP_ZX_DET_DEB_MASK GENMASK(2, 0)
+#define ZX_DET_DEB_10US 0
+#define ZX_DET_DEB_20US 1
+#define ZX_DET_DEB_40US 2
+#define ZX_DET_DEB_80US 3
+
+#define REG_HAP_BRAKE 0x5C
+#define HAP_BRAKE_PATTERN_MASK 0x3
+#define HAP_BRAKE_PATTERN_SHIFT 2
+
+#define REG_HAP_WF_REPEAT 0x5E
+#define HAP_WF_REPEAT_MASK GENMASK(6, 4)
+#define HAP_WF_REPEAT_SHIFT 4
+#define HAP_WF_S_REPEAT_MASK GENMASK(1, 0)
+
+#define REG_HAP_WF_S1 0x60
+#define HAP_WF_SIGN_BIT BIT(7)
+#define HAP_WF_OVD_BIT BIT(6)
+#define HAP_WF_AMP_BIT GENMASK(5, 1)
+#define HAP_WF_AMP_SHIFT 1
+
+#define REG_HAP_PLAY 0x70
+#define HAP_PLAY_BIT BIT(7)
+
+#define REG_HAP_SEC_ACCESS 0xD0
+
+struct qti_hap_effect {
+ int id;
+ u8 *pattern;
+ int pattern_length;
+ u16 play_rate_us;
+ u8 wf_repeat_n;
+ u8 wf_s_repeat_n;
+ u8 brake[HAP_BRAKE_PATTERN_MAX];
+ int brake_pattern_length;
+ bool brake_en;
+ bool lra_auto_res_disable;
+};
+
+struct qti_hap_play_info {
+ struct qti_hap_effect *effect;
+ u16 vmax_mv;
+ int length_us;
+ int playing_pos;
+ bool playing_pattern;
+};
+
+struct qti_hap_config {
+ enum actutor_type act_type;
+ enum lra_res_sig_shape lra_shape;
+ enum lra_auto_res_mode lra_auto_res_mode;
+ enum wf_src ext_src;
+ u16 vmax_mv;
+ u16 ilim_ma;
+ u16 play_rate_us;
+ bool lra_allow_variable_play_rate;
+ bool use_ext_wf_src;
+};
+
+struct qti_hap_chip {
+ struct platform_device *pdev;
+ struct device *dev;
+ struct regmap *regmap;
+ struct input_dev *input_dev;
+ struct pwm_device *pwm_dev;
+ struct qti_hap_config config;
+ struct qti_hap_play_info play;
+ struct qti_hap_effect *predefined;
+ struct qti_hap_effect constant;
+ struct regulator *vdd_supply;
+ struct hrtimer stop_timer;
+ spinlock_t bus_lock;
+ ktime_t last_sc_time;
+ int play_irq;
+ int sc_irq;
+ int effects_count;
+ int sc_det_count;
+ u16 reg_base;
+ bool perm_disable;
+ bool play_irq_en;
+ bool vdd_enabled;
+};
+
+static int wf_repeat[8] = {1, 2, 4, 8, 16, 32, 64, 128};
+static int wf_s_repeat[4] = {1, 2, 4, 8};
+
+static inline bool is_secure(u8 addr)
+{
+ return ((addr & 0xFF) > 0xD0);
+}
+
+static int qti_haptics_read(struct qti_hap_chip *chip,
+ u8 addr, u8 *val, int len)
+{
+ int rc = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->bus_lock, flags);
+
+ rc = regmap_bulk_read(chip->regmap, chip->reg_base + addr, val, len);
+ if (rc < 0)
+ dev_err(chip->dev, "Reading addr 0x%x failed, rc=%d\n",
+ addr, rc);
+ spin_unlock_irqrestore(&chip->bus_lock, flags);
+
+ return rc;
+}
+
+static int qti_haptics_write(struct qti_hap_chip *chip,
+ u8 addr, u8 *val, int len)
+{
+ int rc = 0, i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->bus_lock, flags);
+ if (is_secure(addr)) {
+ for (i = 0; i < len; i++) {
+ rc = regmap_write(chip->regmap,
+ chip->reg_base + REG_HAP_SEC_ACCESS,
+ 0xA5);
+ if (rc < 0) {
+ dev_err(chip->dev, "write SEC_ACCESS failed, rc=%d\n",
+ rc);
+ goto unlock;
+ }
+
+ rc = regmap_write(chip->regmap,
+ chip->reg_base + addr + i, val[i]);
+ if (rc < 0) {
+ dev_err(chip->dev, "write val 0x%x to addr 0x%x failed, rc=%d\n",
+ val[i], addr + i, rc);
+ goto unlock;
+ }
+ }
+ } else {
+ if (len > 1)
+ rc = regmap_bulk_write(chip->regmap,
+ chip->reg_base + addr, val, len);
+ else
+ rc = regmap_write(chip->regmap,
+ chip->reg_base + addr, *val);
+
+ if (rc < 0)
+ dev_err(chip->dev, "write addr 0x%x failed, rc=%d\n",
+ addr, rc);
+ }
+
+ for (i = 0; i < len; i++)
+ dev_dbg(chip->dev, "Update addr 0x%x to val 0x%x\n",
+ addr + i, val[i]);
+
+unlock:
+ spin_unlock_irqrestore(&chip->bus_lock, flags);
+ return rc;
+}
+
+static int qti_haptics_masked_write(struct qti_hap_chip *chip, u8 addr,
+ u8 mask, u8 val)
+{
+ int rc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->bus_lock, flags);
+ if (is_secure(addr)) {
+ rc = regmap_write(chip->regmap,
+ chip->reg_base + REG_HAP_SEC_ACCESS,
+ 0xA5);
+ if (rc < 0) {
+ dev_err(chip->dev, "write SEC_ACCESS failed, rc=%d\n",
+ rc);
+ goto unlock;
+ }
+ }
+
+ rc = regmap_update_bits(chip->regmap, chip->reg_base + addr, mask, val);
+ if (rc < 0)
+ dev_err(chip->dev, "Update addr 0x%x to val 0x%x with mask 0x%x failed, rc=%d\n",
+ addr, val, mask, rc);
+
+ dev_dbg(chip->dev, "Update addr 0x%x to val 0x%x with mask 0x%x\n",
+ addr, val, mask);
+unlock:
+ spin_unlock_irqrestore(&chip->bus_lock, flags);
+
+ return rc;
+}
+
+static void construct_constant_waveform_in_pattern(
+ struct qti_hap_play_info *play)
+{
+ struct qti_hap_chip *chip = container_of(play,
+ struct qti_hap_chip, play);
+ struct qti_hap_config *config = &chip->config;
+ struct qti_hap_effect *effect = play->effect;
+ int total_samples, samples, left, magnitude, i, j, k;
+ int delta = INT_MAX, delta_min = INT_MAX;
+
+ /* Using play_rate_us in config for constant waveform */
+ effect->play_rate_us = config->play_rate_us;
+ total_samples = play->length_us / effect->play_rate_us;
+ left = play->length_us % effect->play_rate_us;
+
+ if (total_samples <= HAP_WAVEFORM_BUFFER_MAX) {
+ effect->pattern_length = total_samples;
+ effect->wf_s_repeat_n = 0;
+ effect->wf_repeat_n = 0;
+ } else {
+ /*
+ * Find a closest setting to achieve the constant waveform
+ * with the required length by using buffer waveform source:
+ * play_length_us = pattern_length * wf_s_repeat_n
+ * * wf_repeat_n * play_rate_us
+ */
+ for (i = 0; i < ARRAY_SIZE(wf_repeat); i++) {
+ for (j = 0; j < ARRAY_SIZE(wf_s_repeat); j++) {
+ for (k = 1; k <= HAP_WAVEFORM_BUFFER_MAX; k++) {
+ samples = k * wf_s_repeat[j] *
+ wf_repeat[i];
+ delta = abs(total_samples - samples);
+ if (delta < delta_min) {
+ delta_min = delta;
+ effect->pattern_length = k;
+ effect->wf_s_repeat_n = j;
+ effect->wf_repeat_n = i;
+ }
+ if (samples > total_samples)
+ break;
+ }
+ }
+ }
+ }
+
+ if (left > 0 && effect->pattern_length < HAP_WAVEFORM_BUFFER_MAX)
+ effect->pattern_length++;
+
+ play->length_us = effect->pattern_length * effect->play_rate_us;
+ dev_dbg(chip->dev, "total_samples = %d, pattern_length = %d, wf_s_repeat = %d, wf_repeat = %d\n",
+ total_samples, effect->pattern_length,
+ wf_s_repeat[effect->wf_s_repeat_n],
+ wf_repeat[effect->wf_repeat_n]);
+
+ for (i = 0; i < effect->pattern_length; i++) {
+ magnitude = play->vmax_mv / HAP_VMAX_MV_LSB;
+ effect->pattern[i] = (u8)magnitude << HAP_WF_AMP_SHIFT;
+ }
+}
+
+static int qti_haptics_config_wf_buffer(struct qti_hap_chip *chip)
+{
+ struct qti_hap_play_info *play = &chip->play;
+ struct qti_hap_effect *effect = play->effect;
+ u8 addr, pattern[HAP_WAVEFORM_BUFFER_MAX] = {0};
+ int rc = 0;
+ size_t len;
+
+ if (play->playing_pos == effect->pattern_length) {
+ dev_dbg(chip->dev, "pattern playing done\n");
+ return 0;
+ }
+
+ if (effect->pattern_length - play->playing_pos
+ >= HAP_WAVEFORM_BUFFER_MAX)
+ len = HAP_WAVEFORM_BUFFER_MAX;
+ else
+ len = effect->pattern_length - play->playing_pos;
+
+ dev_dbg(chip->dev, "copy %d bytes start from %d\n",
+ (int)len, play->playing_pos);
+ memcpy(pattern, &effect->pattern[play->playing_pos], len);
+
+ play->playing_pos += len;
+
+ addr = REG_HAP_WF_S1;
+ rc = qti_haptics_write(chip, REG_HAP_WF_S1, pattern,
+ HAP_WAVEFORM_BUFFER_MAX);
+ if (rc < 0)
+ dev_err(chip->dev, "Program WF_SAMPLE failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qti_haptics_config_wf_repeat(struct qti_hap_chip *chip)
+{
+ struct qti_hap_effect *effect = chip->play.effect;
+ u8 addr, mask, val;
+ int rc = 0;
+
+ addr = REG_HAP_WF_REPEAT;
+ mask = HAP_WF_REPEAT_MASK | HAP_WF_S_REPEAT_MASK;
+ val = effect->wf_repeat_n << HAP_WF_REPEAT_SHIFT;
+ val |= effect->wf_s_repeat_n;
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0)
+ dev_err(chip->dev, "Program WF_REPEAT failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qti_haptics_play(struct qti_hap_chip *chip, bool play)
+{
+ int rc = 0;
+ u8 val = play ? HAP_PLAY_BIT : 0;
+
+ rc = qti_haptics_write(chip,
+ REG_HAP_PLAY, &val, 1);
+ if (rc < 0)
+ dev_err(chip->dev, "%s playing haptics failed, rc=%d\n",
+ play ? "start" : "stop", rc);
+
+ return rc;
+}
+
+static int qti_haptics_module_en(struct qti_hap_chip *chip, bool en)
+{
+ int rc = 0;
+ u8 val = en ? HAP_EN_BIT : 0;
+
+ rc = qti_haptics_write(chip,
+ REG_HAP_EN_CTL1, &val, 1);
+ if (rc < 0)
+ dev_err(chip->dev, "%s haptics failed, rc=%d\n",
+ en ? "enable" : "disable", rc);
+
+
+ return rc;
+}
+
+static int qti_haptics_config_vmax(struct qti_hap_chip *chip, int vmax_mv)
+{
+ u8 addr, mask, val;
+ int rc;
+
+ addr = REG_HAP_VMAX_CFG;
+ mask = HAP_VMAX_MV_MASK;
+ val = (vmax_mv / HAP_VMAX_MV_LSB) << HAP_VMAX_MV_SHIFT;
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0)
+ dev_err(chip->dev, "write VMAX_CFG failed, rc=%d\n",
+ rc);
+
+ return rc;
+}
+
+static int qti_haptics_config_wf_src(struct qti_hap_chip *chip,
+ enum wf_src src)
+{
+ u8 addr, mask, val = 0;
+ int rc;
+
+ addr = REG_HAP_SEL;
+ mask = HAP_WF_SOURCE_MASK | HAP_WF_TRIGGER_BIT;
+ val = src << HAP_WF_SOURCE_SHIFT;
+ if (src == EXT_WF_AUDIO || src == EXT_WF_PWM)
+ val |= HAP_WF_TRIGGER_BIT;
+
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0)
+ dev_err(chip->dev, "set HAP_SEL failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qti_haptics_config_play_rate_us(struct qti_hap_chip *chip,
+ int play_rate_us)
+{
+ u8 addr, val[2];
+ int tmp, rc;
+
+ addr = REG_HAP_RATE_CFG1;
+ tmp = play_rate_us / HAP_PLAY_RATE_US_LSB;
+ val[0] = tmp & 0xff;
+ val[1] = (tmp >> 8) & 0xf;
+ rc = qti_haptics_write(chip, addr, val, 2);
+ if (rc < 0)
+ dev_err(chip->dev, "write play_rate failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qti_haptics_config_brake(struct qti_hap_chip *chip, u8 *brake)
+{
+ u8 addr, mask, val;
+ int i, rc;
+ bool en = true;
+
+ addr = REG_HAP_BRAKE;
+ for (val = 0, i = 0; i < HAP_BRAKE_PATTERN_MAX; i++)
+ val |= (brake[i] & HAP_BRAKE_PATTERN_MASK) <<
+ i * HAP_BRAKE_PATTERN_SHIFT;
+
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "write brake pattern failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ if (val == 0)
+ en = false;
+
+ /* Set BRAKE_EN only if brake pattern is non-zero */
+ addr = REG_HAP_EN_CTL2;
+ mask = HAP_BRAKE_EN_BIT;
+ val = en;
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0)
+ dev_err(chip->dev, "set EN_CTL2 failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qti_haptics_lra_auto_res_enable(struct qti_hap_chip *chip, bool en)
+{
+ int rc;
+ u8 addr, val, mask;
+
+ addr = REG_HAP_AUTO_RES_CTRL;
+ mask = HAP_AUTO_RES_EN_BIT;
+ val = en ? HAP_AUTO_RES_EN_BIT : 0;
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0)
+ dev_err(chip->dev, "set AUTO_RES_CTRL failed, rc=%d\n", rc);
+
+ return rc;
+}
+
+static int qti_haptics_load_constant_waveform(struct qti_hap_chip *chip)
+{
+ struct qti_hap_play_info *play = &chip->play;
+ struct qti_hap_config *config = &chip->config;
+ int rc = 0;
+
+ rc = qti_haptics_module_en(chip, true);
+ if (rc < 0)
+ return rc;
+
+ /*
+ * Using VMAX waveform source if playing length is >= 20ms,
+ * otherwise using buffer waveform source and calculate the
+ * pattern length and repeating times to achieve accurate
+ * playing time accuracy.
+ */
+ if (play->length_us >= VMAX_MIN_PLAY_TIME_US) {
+ rc = qti_haptics_config_vmax(chip, play->vmax_mv);
+ if (rc < 0)
+ return rc;
+
+ /* Enable Auto-Resonance when VMAX wf-src is selected */
+ if (config->act_type == ACT_LRA) {
+ rc = qti_haptics_lra_auto_res_enable(chip, true);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* Set WF_SOURCE to VMAX */
+ rc = qti_haptics_config_wf_src(chip, INT_WF_VMAX);
+ if (rc < 0)
+ return rc;
+
+ play->playing_pattern = false;
+ } else {
+ rc = qti_haptics_config_vmax(chip, config->vmax_mv);
+ if (rc < 0)
+ return rc;
+
+ play->effect = &chip->constant;
+ play->playing_pos = 0;
+ /* Format and config waveform in patterns */
+ construct_constant_waveform_in_pattern(play);
+ rc = qti_haptics_config_wf_buffer(chip);
+ if (rc < 0)
+ return rc;
+
+ rc = qti_haptics_config_wf_repeat(chip);
+ if (rc < 0)
+ return rc;
+
+ /* Set WF_SOURCE to buffer */
+ rc = qti_haptics_config_wf_src(chip, INT_WF_BUFFER);
+ if (rc < 0)
+ return rc;
+
+ play->playing_pattern = true;
+ }
+
+ return 0;
+}
+
+static int qti_haptics_load_predefined_effect(struct qti_hap_chip *chip,
+ int effect_idx)
+{
+ struct qti_hap_play_info *play = &chip->play;
+ struct qti_hap_config *config = &chip->config;
+ int rc = 0;
+
+ if (effect_idx >= chip->effects_count)
+ return -EINVAL;
+
+ play->effect = &chip->predefined[effect_idx];
+ play->playing_pos = 0;
+
+ rc = qti_haptics_module_en(chip, true);
+ if (rc < 0)
+ return rc;
+
+ rc = qti_haptics_config_vmax(chip, play->vmax_mv);
+ if (rc < 0)
+ return rc;
+
+ rc = qti_haptics_config_play_rate_us(chip, play->effect->play_rate_us);
+ if (rc < 0)
+ return rc;
+
+ if (config->act_type == ACT_LRA) {
+ rc = qti_haptics_lra_auto_res_enable(chip,
+ !play->effect->lra_auto_res_disable);
+ if (rc < 0)
+ return rc;
+ }
+
+ /* Set brake pattern in the effect */
+ rc = qti_haptics_config_brake(chip, play->effect->brake);
+ if (rc < 0)
+ return rc;
+
+ rc = qti_haptics_config_wf_buffer(chip);
+ if (rc < 0)
+ return rc;
+
+ rc = qti_haptics_config_wf_repeat(chip);
+ if (rc < 0)
+ return rc;
+
+ /* Set WF_SOURCE to buffer */
+ rc = qti_haptics_config_wf_src(chip, INT_WF_BUFFER);
+ if (rc < 0)
+ return rc;
+
+ play->playing_pattern = true;
+
+ return 0;
+}
+
+static irqreturn_t qti_haptics_play_irq_handler(int irq, void *data)
+{
+ struct qti_hap_chip *chip = (struct qti_hap_chip *)data;
+ struct qti_hap_play_info *play = &chip->play;
+ struct qti_hap_effect *effect = play->effect;
+ int rc;
+
+ dev_dbg(chip->dev, "play_irq triggered\n");
+ if (play->playing_pos == effect->pattern_length) {
+ dev_dbg(chip->dev, "waveform playing done\n");
+ qti_haptics_play(chip, false);
+ if (chip->play_irq_en) {
+ disable_irq_nosync(chip->play_irq);
+ chip->play_irq_en = false;
+ }
+
+ goto handled;
+ }
+
+ /* Config to play remaining patterns */
+ rc = qti_haptics_config_wf_repeat(chip);
+ if (rc < 0)
+ goto handled;
+
+ rc = qti_haptics_config_wf_buffer(chip);
+ if (rc < 0)
+ goto handled;
+
+handled:
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qti_haptics_sc_irq_handler(int irq, void *data)
+{
+ struct qti_hap_chip *chip = (struct qti_hap_chip *)data;
+ u8 addr, val;
+ ktime_t temp;
+ s64 sc_delta_time_us;
+ int rc;
+
+ dev_dbg(chip->dev, "sc_irq triggered\n");
+ addr = REG_HAP_STATUS1;
+ rc = qti_haptics_read(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "read HAP_STATUS1 failed, rc=%d\n", rc);
+ goto handled;
+ }
+
+ if (!(val & HAP_SC_DET_BIT))
+ goto handled;
+
+ temp = ktime_get();
+ sc_delta_time_us = ktime_us_delta(temp, chip->last_sc_time);
+ chip->last_sc_time = temp;
+
+ if (sc_delta_time_us > HAP_SC_DET_TIME_US)
+ chip->sc_det_count = 0;
+ else
+ chip->sc_det_count++;
+
+ addr = REG_HAP_SC_CLR;
+ val = HAP_SC_CLR_BIT;
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "write SC_CLR failed, rc=%d\n", rc);
+ goto handled;
+ }
+
+ if (chip->sc_det_count > HAP_SC_DET_MAX_COUNT) {
+ rc = qti_haptics_module_en(chip, false);
+ if (rc < 0)
+ goto handled;
+
+ dev_crit(chip->dev, "Short circuit persists, disable haptics\n");
+ chip->perm_disable = true;
+ }
+
+handled:
+ return IRQ_HANDLED;
+}
+
+static inline void get_play_length(struct qti_hap_play_info *play,
+ int *length_us)
+{
+ struct qti_hap_effect *effect = play->effect;
+ int tmp;
+
+ tmp = effect->pattern_length * effect->play_rate_us;
+ tmp *= wf_s_repeat[effect->wf_s_repeat_n];
+ tmp *= wf_repeat[effect->wf_repeat_n];
+ if (effect->brake_en)
+ tmp += effect->play_rate_us * effect->brake_pattern_length;
+
+ *length_us = tmp;
+}
+
+static int qti_haptics_upload_effect(struct input_dev *dev,
+ struct ff_effect *effect, struct ff_effect *old)
+{
+ struct qti_hap_chip *chip = input_get_drvdata(dev);
+ struct qti_hap_config *config = &chip->config;
+ struct qti_hap_play_info *play = &chip->play;
+ int rc = 0, tmp, i;
+ s16 level, data[CUSTOM_DATA_LEN];
+
+ if (chip->vdd_supply && !chip->vdd_enabled) {
+ rc = regulator_enable(chip->vdd_supply);
+ if (rc < 0) {
+ dev_err(chip->dev, "Enable VDD supply failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ chip->vdd_enabled = true;
+ }
+
+ switch (effect->type) {
+ case FF_CONSTANT:
+ play->length_us = effect->replay.length * USEC_PER_MSEC;
+ level = effect->u.constant.level;
+ tmp = level * config->vmax_mv;
+ play->vmax_mv = tmp / 0x7fff;
+ dev_dbg(chip->dev, "upload constant effect, length = %dus, vmax_mv=%d\n",
+ play->length_us, play->vmax_mv);
+
+ rc = qti_haptics_load_constant_waveform(chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "Play constant waveform failed, rc=%d\n",
+ rc);
+ goto disable_vdd;
+ }
+ break;
+
+ case FF_PERIODIC:
+ if (chip->effects_count == 0) {
+ rc = -EINVAL;
+ goto disable_vdd;
+ }
+
+ if (effect->u.periodic.waveform != FF_CUSTOM) {
+ dev_err(chip->dev, "Only accept custom waveforms\n");
+ rc = -EINVAL;
+ goto disable_vdd;
+ }
+
+ level = effect->u.periodic.magnitude;
+ tmp = level * config->vmax_mv;
+ play->vmax_mv = tmp / 0x7fff;
+
+ if (copy_from_user(data, effect->u.periodic.custom_data,
+ sizeof(s16) * CUSTOM_DATA_LEN)) {
+ rc = -EFAULT;
+ goto disable_vdd;
+ }
+
+ for (i = 0; i < chip->effects_count; i++)
+ if (chip->predefined[i].id ==
+ data[CUSTOM_DATA_EFFECT_IDX])
+ break;
+
+ if (i == chip->effects_count) {
+ dev_err(chip->dev, "predefined effect %d is NOT supported\n",
+ data[0]);
+ rc = -EINVAL;
+ goto disable_vdd;
+ }
+
+ dev_dbg(chip->dev, "upload effect %d, vmax_mv=%d\n",
+ chip->predefined[i].id, play->vmax_mv);
+ rc = qti_haptics_load_predefined_effect(chip, i);
+ if (rc < 0) {
+ dev_err(chip->dev, "Play predefined effect %d failed, rc=%d\n",
+ chip->predefined[i].id, rc);
+ goto disable_vdd;
+ }
+
+ get_play_length(play, &play->length_us);
+ data[CUSTOM_DATA_TIMEOUT_SEC_IDX] =
+ play->length_us / USEC_PER_SEC;
+ data[CUSTOM_DATA_TIMEOUT_MSEC_IDX] =
+ (play->length_us % USEC_PER_SEC) / USEC_PER_MSEC;
+
+ /*
+ * Copy the custom data contains the play length back to
+ * userspace so that the userspace client can wait and
+ * send stop playing command after it's done.
+ */
+ if (copy_to_user(effect->u.periodic.custom_data, data,
+ sizeof(s16) * CUSTOM_DATA_LEN)) {
+ rc = -EFAULT;
+ goto disable_vdd;
+ }
+ break;
+
+ default:
+ dev_err(chip->dev, "Unsupported effect type: %d\n",
+ effect->type);
+ break;
+ }
+
+ return 0;
+disable_vdd:
+ if (chip->vdd_supply && chip->vdd_enabled) {
+ rc = regulator_disable(chip->vdd_supply);
+ if (rc < 0) {
+ dev_err(chip->dev, "Disable VDD supply failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ chip->vdd_enabled = false;
+ }
+ return rc;
+}
+
+static int qti_haptics_playback(struct input_dev *dev, int effect_id, int val)
+{
+ struct qti_hap_chip *chip = input_get_drvdata(dev);
+ struct qti_hap_play_info *play = &chip->play;
+ s64 secs;
+ unsigned long nsecs;
+ int rc = 0;
+
+ dev_dbg(chip->dev, "playback, val = %d\n", val);
+ if (!!val) {
+ rc = qti_haptics_play(chip, true);
+ if (rc < 0)
+ return rc;
+
+ if (play->playing_pattern) {
+ if (!chip->play_irq_en) {
+ enable_irq(chip->play_irq);
+ chip->play_irq_en = true;
+ }
+ } else {
+ if (chip->play_irq_en) {
+ disable_irq_nosync(chip->play_irq);
+ chip->play_irq_en = false;
+ }
+ secs = play->length_us / USEC_PER_SEC;
+ nsecs = (play->length_us % USEC_PER_SEC) *
+ NSEC_PER_USEC;
+ hrtimer_start(&chip->stop_timer, ktime_set(secs, nsecs),
+ HRTIMER_MODE_REL);
+ }
+ } else {
+ play->length_us = 0;
+ rc = qti_haptics_play(chip, false);
+ if (rc < 0)
+ return rc;
+
+ rc = qti_haptics_module_en(chip, false);
+ if (rc < 0)
+ return rc;
+
+ if (chip->play_irq_en) {
+ disable_irq_nosync(chip->play_irq);
+ chip->play_irq_en = false;
+ }
+ }
+
+ return rc;
+}
+
+static int qti_haptics_erase(struct input_dev *dev, int effect_id)
+{
+ struct qti_hap_chip *chip = input_get_drvdata(dev);
+ int rc = 0;
+
+ if (chip->vdd_supply && chip->vdd_enabled) {
+ rc = regulator_disable(chip->vdd_supply);
+ if (rc < 0) {
+ dev_err(chip->dev, "Disable VDD supply failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ chip->vdd_enabled = false;
+ }
+
+ return rc;
+}
+
+static int qti_haptics_hw_init(struct qti_hap_chip *chip)
+{
+ struct qti_hap_config *config = &chip->config;
+ u8 addr, val, mask;
+ int rc = 0;
+
+ /* Config actuator type */
+ addr = REG_HAP_CFG1;
+ val = config->act_type;
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "write actuator type failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Config ilim_ma */
+ addr = REG_HAP_ILIM_CFG;
+ val = config->ilim_ma == 400 ? 0 : 1;
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "write ilim_ma failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Set HAP_EN_CTL3 */
+ addr = REG_HAP_EN_CTL3;
+ val = HAP_HBRIDGE_EN_BIT | HAP_PWM_SIGNAL_EN_BIT | HAP_ILIM_EN_BIT |
+ HAP_ILIM_CC_EN_BIT | HAP_AUTO_RES_RBIAS_EN_BIT |
+ HAP_DAC_EN_BIT | HAP_PWM_CTL_EN_BIT;
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "set EN_CTL3 failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /* Set ZX_CFG */
+ addr = REG_HAP_ZX_CFG;
+ mask = HAP_ZX_DET_DEB_MASK;
+ val = ZX_DET_DEB_80US;
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0) {
+ dev_err(chip->dev, "write ZX_CFG failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ /*
+ * Config play rate: this is the resonance period for LRA,
+ * or the play duration of each waveform sample for ERM.
+ */
+ rc = qti_haptics_config_play_rate_us(chip, config->play_rate_us);
+ if (rc < 0)
+ return rc;
+
+ /* Set external waveform source if it's used */
+ if (config->use_ext_wf_src) {
+ rc = qti_haptics_config_wf_src(chip, config->ext_src);
+ if (rc < 0)
+ return rc;
+ }
+
+ /*
+ * Skip configurations below for ERM actuator
+ * as they're only for LRA actuators
+ */
+ if (config->act_type == ACT_ERM)
+ return 0;
+
+ addr = REG_HAP_CFG2;
+ val = config->lra_shape;
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "write lra_sig_shape failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ addr = REG_HAP_AUTO_RES_CFG;
+ mask = HAP_AUTO_RES_MODE_BIT | HAP_CAL_EOP_EN_BIT | HAP_CAL_PERIOD_MASK;
+ val = config->lra_auto_res_mode << HAP_AUTO_RES_MODE_SHIFT;
+ val |= HAP_CAL_EOP_EN_BIT | HAP_CAL_OPT3_EVERY_8_PERIOD;
+ rc = qti_haptics_masked_write(chip, addr, mask, val);
+ if (rc < 0) {
+ dev_err(chip->dev, "set AUTO_RES_CFG failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ addr = REG_HAP_AUTO_RES_CTRL;
+ val = HAP_AUTO_RES_EN_BIT | HAP_SEL_AUTO_RES_PERIOD |
+ AUTO_RES_CNT_ERR_DELTA(2) | HAP_AUTO_RES_ERR_RECOVERY_BIT |
+ AUTO_RES_EN_DLY(4);
+ rc = qti_haptics_write(chip, addr, &val, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "set AUTO_RES_CTRL failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static enum hrtimer_restart qti_hap_stop_timer(struct hrtimer *timer)
+{
+ struct qti_hap_chip *chip = container_of(timer, struct qti_hap_chip,
+ stop_timer);
+ int rc;
+
+ chip->play.length_us = 0;
+ rc = qti_haptics_play(chip, false);
+ if (rc < 0) {
+ dev_err(chip->dev, "Stop playing failed, rc=%d\n", rc);
+ goto err_out;
+ }
+
+ rc = qti_haptics_module_en(chip, false);
+ if (rc < 0)
+ dev_err(chip->dev, "Disable module failed, rc=%d\n", rc);
+err_out:
+ return HRTIMER_NORESTART;
+}
+
+static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
+{
+ struct qti_hap_config *config = &chip->config;
+ const struct device_node *node = chip->dev->of_node;
+ struct device_node *child_node;
+ struct qti_hap_effect *effect;
+ const char *str;
+ int rc = 0, tmp, i = 0, j;
+ u8 val;
+
+ rc = of_property_read_u32(node, "reg", &tmp);
+ if (rc < 0) {
+ dev_err(chip->dev, "Failed to reg base, rc=%d\n", rc);
+ return rc;
+ }
+ chip->reg_base = (u16)tmp;
+
+ chip->sc_irq = platform_get_irq_byname(chip->pdev, "hap-sc-irq");
+ if (chip->sc_irq < 0) {
+ dev_err(chip->dev, "Failed to get hap-sc-irq\n");
+ return chip->sc_irq;
+ }
+
+ chip->play_irq = platform_get_irq_byname(chip->pdev, "hap-play-irq");
+ if (chip->play_irq < 0) {
+ dev_err(chip->dev, "Failed to get hap-play-irq\n");
+ return chip->play_irq;
+ }
+
+ config->act_type = ACT_LRA;
+ rc = of_property_read_string(node, "qcom,actuator-type", &str);
+ if (!rc) {
+ if (strcmp(str, "erm") == 0) {
+ config->act_type = ACT_ERM;
+ } else if (strcmp(str, "lra") == 0) {
+ config->act_type = ACT_LRA;
+ } else {
+ dev_err(chip->dev, "Invalid actuator type: %s\n",
+ str);
+ return -EINVAL;
+ }
+ }
+
+ config->vmax_mv = HAP_VMAX_MV_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,vmax-mv", &tmp);
+ if (!rc)
+ config->vmax_mv = (tmp > HAP_VMAX_MV_MAX) ?
+ HAP_VMAX_MV_MAX : tmp;
+
+ config->ilim_ma = HAP_ILIM_MA_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,ilim-ma", &tmp);
+ if (!rc)
+ config->ilim_ma = (tmp >= HAP_ILIM_MA_MAX) ?
+ HAP_ILIM_MA_MAX : HAP_ILIM_MA_DEFAULT;
+
+ config->play_rate_us = HAP_PLAY_RATE_US_DEFAULT;
+ rc = of_property_read_u32(node, "qcom,play-rate-us", &tmp);
+ if (!rc)
+ config->play_rate_us = (tmp >= HAP_PLAY_RATE_US_MAX) ?
+ HAP_PLAY_RATE_US_MAX : tmp;
+
+ if (of_find_property(node, "qcom,external-waveform-source", NULL)) {
+ if (!of_property_read_string(node,
+ "qcom,external-waveform-source", &str)) {
+ if (strcmp(str, "audio") == 0) {
+ config->ext_src = EXT_WF_AUDIO;
+ } else if (strcmp(str, "pwm") == 0) {
+ config->ext_src = EXT_WF_PWM;
+ } else {
+ dev_err(chip->dev, "Invalid external waveform source: %s\n",
+ str);
+ return -EINVAL;
+ }
+ }
+ config->use_ext_wf_src = true;
+ }
+
+ if (of_find_property(node, "vdd-supply", NULL)) {
+ chip->vdd_supply = devm_regulator_get(chip->dev, "vdd");
+ if (IS_ERR(chip->vdd_supply)) {
+ rc = PTR_ERR(chip->vdd_supply);
+ if (rc != -EPROBE_DEFER)
+ dev_err(chip->dev, "Failed to get vdd regulator");
+ return rc;
+ }
+ }
+
+ if (config->act_type == ACT_LRA) {
+ config->lra_shape = RES_SIG_SINE;
+ rc = of_property_read_string(node,
+ "qcom,lra-resonance-sig-shape", &str);
+ if (!rc) {
+ if (strcmp(str, "sine") == 0) {
+ config->lra_shape = RES_SIG_SINE;
+ } else if (strcmp(str, "square") == 0) {
+ config->lra_shape = RES_SIG_SQUARE;
+ } else {
+ dev_err(chip->dev, "Invalid resonance signal shape: %s\n",
+ str);
+ return -EINVAL;
+ }
+ }
+
+ config->lra_allow_variable_play_rate = of_property_read_bool(
+ node, "qcom,lra-allow-variable-play-rate");
+
+ config->lra_auto_res_mode = AUTO_RES_MODE_ZXD;
+ rc = of_property_read_string(node,
+ "qcom,lra-auto-resonance-mode", &str);
+ if (!rc) {
+ if (strcmp(str, "zxd") == 0) {
+ config->lra_auto_res_mode = AUTO_RES_MODE_ZXD;
+ } else if (strcmp(str, "qwd") == 0) {
+ config->lra_auto_res_mode = AUTO_RES_MODE_QWD;
+ } else {
+ dev_err(chip->dev, "Invalid auto resonance mode: %s\n",
+ str);
+ return -EINVAL;
+ }
+ }
+ }
+
+ chip->constant.pattern = devm_kcalloc(chip->dev,
+ HAP_WAVEFORM_BUFFER_MAX,
+ sizeof(u8), GFP_KERNEL);
+ if (!chip->constant.pattern)
+ return -ENOMEM;
+
+ tmp = of_get_available_child_count(node);
+ if (tmp == 0)
+ return 0;
+
+ chip->predefined = devm_kcalloc(chip->dev, tmp,
+ sizeof(*chip->predefined), GFP_KERNEL);
+ if (!chip->predefined)
+ return -ENOMEM;
+
+ chip->effects_count = tmp;
+
+ for_each_available_child_of_node(node, child_node) {
+ effect = &chip->predefined[i++];
+ rc = of_property_read_u32(child_node, "qcom,effect-id",
+ &effect->id);
+ if (rc < 0) {
+ dev_err(chip->dev, "Read qcom,effect-id failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ rc = of_property_count_elems_of_size(child_node,
+ "qcom,wf-pattern", sizeof(u8));
+ if (rc < 0) {
+ dev_err(chip->dev, "Count qcom,wf-pattern property failed, rc=%d\n",
+ rc);
+ return rc;
+ } else if (rc == 0) {
+ dev_dbg(chip->dev, "qcom,wf-pattern has no data\n");
+ return -EINVAL;
+ }
+
+ effect->pattern_length = rc;
+ effect->pattern = devm_kcalloc(chip->dev,
+ effect->pattern_length, sizeof(u8), GFP_KERNEL);
+ if (!effect->pattern)
+ return -ENOMEM;
+
+ rc = of_property_read_u8_array(child_node, "qcom,wf-pattern",
+ effect->pattern, effect->pattern_length);
+ if (rc < 0) {
+ dev_err(chip->dev, "Read qcom,wf-pattern property failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ effect->play_rate_us = config->play_rate_us;
+ rc = of_property_read_u32(child_node, "qcom,wf-play-rate-us",
+ &tmp);
+ if (rc < 0)
+ dev_dbg(chip->dev, "Read qcom,wf-play-rate-us failed, rc=%d\n",
+ rc);
+ else
+ effect->play_rate_us = tmp;
+
+ if (config->act_type == ACT_LRA &&
+ !config->lra_allow_variable_play_rate &&
+ config->play_rate_us != effect->play_rate_us) {
+ dev_warn(chip->dev, "play rate should match with LRA resonance frequency\n");
+ effect->play_rate_us = config->play_rate_us;
+ }
+
+ rc = of_property_read_u32(child_node, "qcom,wf-repeat-count",
+ &tmp);
+ if (rc < 0) {
+ dev_dbg(chip->dev, "Read qcom,wf-repeat-count failed, rc=%d\n",
+ rc);
+ } else {
+ for (j = 0; j < ARRAY_SIZE(wf_repeat); j++)
+ if (tmp <= wf_repeat[j])
+ break;
+
+ effect->wf_repeat_n = j;
+ }
+
+ rc = of_property_read_u32(child_node, "qcom,wf-s-repeat-count",
+ &tmp);
+ if (rc < 0) {
+ dev_dbg(chip->dev, "Read qcom,wf-s-repeat-count failed, rc=%d\n",
+ rc);
+ } else {
+ for (j = 0; j < ARRAY_SIZE(wf_s_repeat); j++)
+ if (tmp <= wf_s_repeat[j])
+ break;
+
+ effect->wf_s_repeat_n = j;
+ }
+
+ effect->lra_auto_res_disable = of_property_read_bool(node,
+ "qcom,lra-auto-resonance-disable");
+
+ tmp = of_property_count_elems_of_size(child_node,
+ "qcom,wf-brake-pattern", sizeof(u8));
+ if (tmp <= 0)
+ continue;
+
+ if (tmp > HAP_BRAKE_PATTERN_MAX) {
+ dev_err(chip->dev, "wf-brake-pattern shouldn't be more than %d bytes\n",
+ HAP_BRAKE_PATTERN_MAX);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u8_array(child_node,
+ "qcom,wf-brake-pattern", effect->brake, tmp);
+ if (rc < 0) {
+ dev_err(chip->dev, "Failed to get wf-brake-pattern, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ effect->brake_pattern_length = tmp;
+ for (j = tmp - 1; j >= 0; j--) {
+ if (effect->brake[j] != 0)
+ break;
+ effect->brake_pattern_length--;
+ }
+
+ for (val = 0, j = 0; j < effect->brake_pattern_length; j++)
+ val |= (effect->brake[j] & HAP_BRAKE_PATTERN_MASK)
+ << j * HAP_BRAKE_PATTERN_SHIFT;
+
+ effect->brake_en = (val != 0);
+ }
+
+ return 0;
+}
+
+static int qti_haptics_probe(struct platform_device *pdev)
+{
+ struct qti_hap_chip *chip;
+ struct input_dev *input_dev;
+ struct ff_device *ff;
+ int rc = 0, effect_count_max;
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ chip->pdev = pdev;
+ chip->dev = &pdev->dev;
+ chip->regmap = dev_get_regmap(chip->dev->parent, NULL);
+ if (!chip->regmap) {
+ dev_err(chip->dev, "Failed to get regmap handle\n");
+ return -ENXIO;
+ }
+
+ rc = qti_haptics_parse_dt(chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "parse device-tree failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ spin_lock_init(&chip->bus_lock);
+
+ rc = qti_haptics_hw_init(chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "parse device-tree failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = devm_request_threaded_irq(chip->dev, chip->play_irq, NULL,
+ qti_haptics_play_irq_handler,
+ IRQF_ONESHOT, "hap_play_irq", chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "request play-irq failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ disable_irq(chip->play_irq);
+ chip->play_irq_en = false;
+
+ rc = devm_request_threaded_irq(chip->dev, chip->sc_irq, NULL,
+ qti_haptics_sc_irq_handler,
+ IRQF_ONESHOT, "hap_sc_irq", chip);
+ if (rc < 0) {
+ dev_err(chip->dev, "request sc-irq failed, rc=%d\n", rc);
+ return rc;
+ }
+
+ hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ chip->stop_timer.function = qti_hap_stop_timer;
+
+ input_dev->name = "vibrator";
+ input_set_drvdata(input_dev, chip);
+ chip->input_dev = input_dev;
+
+ input_set_capability(input_dev, EV_FF, FF_CONSTANT);
+ if (chip->effects_count != 0) {
+ input_set_capability(input_dev, EV_FF, FF_PERIODIC);
+ input_set_capability(input_dev, EV_FF, FF_CUSTOM);
+ }
+
+ if (chip->effects_count + 1 > FF_EFFECT_COUNT_MAX)
+ effect_count_max = chip->effects_count + 1;
+ else
+ effect_count_max = FF_EFFECT_COUNT_MAX;
+ rc = input_ff_create(input_dev, effect_count_max);
+ if (rc < 0) {
+ dev_err(chip->dev, "create FF input device failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ ff = input_dev->ff;
+ ff->upload = qti_haptics_upload_effect;
+ ff->playback = qti_haptics_playback;
+ ff->erase = qti_haptics_erase;
+
+ rc = input_register_device(input_dev);
+ if (rc < 0) {
+ dev_err(chip->dev, "register input device failed, rc=%d\n",
+ rc);
+ goto destroy_ff;
+ }
+
+ dev_set_drvdata(chip->dev, chip);
+ return 0;
+
+destroy_ff:
+ input_ff_destroy(chip->input_dev);
+ return rc;
+}
+
+static int qti_haptics_remove(struct platform_device *pdev)
+{
+ struct qti_hap_chip *chip = dev_get_drvdata(&pdev->dev);
+
+ input_ff_destroy(chip->input_dev);
+ dev_set_drvdata(chip->dev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id haptics_match_table[] = {
+ { .compatible = "qcom,haptics" },
+ { .compatible = "qcom,pm660-haptics" },
+ { .compatible = "qcom,pm8150b-haptics" },
+ {},
+};
+
+static struct platform_driver qti_haptics_driver = {
+ .driver = {
+ .name = "qcom,haptics",
+ .of_match_table = haptics_match_table,
+ },
+ .probe = qti_haptics_probe,
+ .remove = qti_haptics_remove,
+};
+module_platform_driver(qti_haptics_driver);
+
+MODULE_DESCRIPTION("QTI haptics driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
index 34508b2..425f51b 100644
--- a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
@@ -1948,12 +1948,6 @@
input_set_drvdata(data->input_dev_ps, data);
/* Register sysfs hooks */
- data->range_kobj = kobject_create_and_add("range", kernel_kobj);
- if (!data->range_kobj) {
- rc = -ENOMEM;
- err("%d error:%d\n", __LINE__, rc);
- goto exit_unregister_dev_ps;
- }
rc = sysfs_create_group(&data->input_dev_ps->dev.kobj,
&stmvl53l0x_attr_group);
if (rc) {
@@ -1981,7 +1975,6 @@
return 0;
exit_unregister_dev_ps_1:
kobject_put(data->range_kobj);
-exit_unregister_dev_ps:
input_unregister_device(data->input_dev_ps);
exit_free_dev_ps:
input_free_device(data->input_dev_ps);
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index c0ec261..83dd0ce 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 3851d57..97f6e05 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -595,7 +595,7 @@
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 @@
{ "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 e23b249..d21bd55 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_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 @@
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 @@
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 @@
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_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 @@
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 @@
{
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 @@
{
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 @@
{
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 @@
{
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 @@
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 @@
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 @@
{
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 c519c0b..4e77adb 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -800,7 +800,7 @@
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 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 @@
__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 e9c1d69..a259ef3 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1299,8 +1299,18 @@
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 c8e0104..2579346 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -104,5 +104,6 @@
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_GT9XX_v28) += gt9xx_v2.8/
\ No newline at end of file
+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 0000000..715b891
--- /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 0000000..71a30f2
--- /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 <chuming.zhang@elanic.com.cn>
+ *
+ * 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 <linux/module.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/async.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/buffer_head.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/input/mt.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <asm/unaligned.h>
+
+
+/* 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 <chuming.zhang@elanic.com.cn>");
+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 b3d7322..7639c9f 100644
--- a/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
+++ b/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
@@ -514,11 +514,11 @@
#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 5907fdd..c599b5a 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -858,6 +858,7 @@
#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/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i
deleted file mode 100644
index e69de29..0000000
--- a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i
+++ /dev/null
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 e69de29..0000000
--- a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i
+++ /dev/null
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 e69de29..0000000
--- a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i
+++ /dev/null
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 e69de29..0000000
--- a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i
+++ /dev/null
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 e69de29..0000000
--- a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i
+++ /dev/null
diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig
index ebf3aa4..3dc5a02 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 509d491..522907a 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 417b0c0..d4bc5be 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;
+struct himax_ic_data *ic_data;
-static int HX_TOUCH_INFO_POINT_CNT;
+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;
+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 @@
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 @@
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);
+ 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_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);
+/*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 @@
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*/
+ 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);
+ 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_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(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_range(1000, 2000);
+ } 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 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;
+ }
- I("%s: i_fullFileLength = %d\n", __func__,fullFileLength);
+ if (i_CTPM_FW == NULL) {
+ I("%s: i_CTPM_FW = NULL\n", __func__);
+ ret = -3;
+ return ret;
+ }
+ fullFileLength = i_CTPM_FW->size;
+
+ 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*/
}
+ } 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);
- himax_int_enable(private_ts->client->irq,1);
- return result;
- }
- else
- {
+ // 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 @@
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 @@
#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 @@
#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 @@
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;i<GEST_PTLG_ID_LEN;i++)
- {
- if (check_FC==0)
- {
- if((buf[0]!=0x00)&&((buf[0]<=0x0F)||(buf[0]==0x80)))
- {
+ for (i = 0 ; i < GEST_PTLG_ID_LEN ; i++) {
+ if (check_FC == 0) {
+ if ((buf[0] != 0x00) &&
+ ((buf[0] <= 0x0F) || (buf[0] == 0x80))) {
check_FC = 1;
gesture_flag = buf[i];
- }
- else
- {
+ } else {
check_FC = 0;
- I("ID START at %x , value = %x skip the event\n", i, buf[i]);
+ I("ID START at %x,value = %x skip event\n",
+ i, buf[i]);
break;
}
- }
- else
- {
- if(buf[i]!=gesture_flag)
- {
+ } else {
+ if (buf[i] != gesture_flag) {
check_FC = 0;
- I("ID NOT the same %x != %x So STOP parse event\n", buf[i], gesture_flag);
+ I("ID NOT same %x != %x So STOP parse event\n",
+ buf[i], gesture_flag);
break;
}
}
I("0x%2.2X ", buf[i]);
if (i % 8 == 7)
- I("\n");
+ I("\n");
}
- I("Himax gesture_flag= %x\n",gesture_flag );
+ I("Himax gesture_flag= %x\n", gesture_flag);
I("Himax check_FC is %d\n", check_FC);
if (check_FC == 0)
return 0;
- if(buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 ||
- buf[GEST_PTLG_ID_LEN+1] != GEST_PTLG_HDR_ID2)
+ if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1
+ || buf[GEST_PTLG_ID_LEN+1] != GEST_PTLG_HDR_ID2)
return 0;
- for(i=0;i<(GEST_PTLG_ID_LEN+GEST_PTLG_HDR_LEN);i++)
- {
- I("P[%x]=0x%2.2X \n", i, buf[i]);
- I("checksum=0x%2.2X \n", check_sum_cal);
+ for (i = 0 ; i < (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN) ; i++) {
+ I("P[%x]=0x%2.2X\n", i, buf[i]);
+ I("checksum=0x%2.2X\n", check_sum_cal);
check_sum_cal += buf[i];
}
- if ((check_sum_cal != 0x00) )
- {
- I(" %s : check_sum_cal: 0x%02X\n",__func__ ,check_sum_cal);
+ if ((check_sum_cal != 0x00)) {
+ I(" %s : check_sum_cal: 0x%02X\n", __func__ , check_sum_cal);
return 0;
}
#ifdef HX_GESTURE_TRACK
- if(buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 &&
- buf[GEST_PTLG_ID_LEN+1] == GEST_PTLG_HDR_ID2)
- {
- gest_len = buf[GEST_PTLG_ID_LEN+2];
-
- I("gest_len = %d ",gest_len);
-
+ if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1
+ && buf[GEST_PTLG_ID_LEN+1] == GEST_PTLG_HDR_ID2) {
+ gest_len = buf[GEST_PTLG_ID_LEN + 2];
+ I("gest_len = %d ", gest_len);
i = 0;
gest_pt_cnt = 0;
- I("gest doornidate start \n %s",__func__);
- while(i<(gest_len+1)/2)
- {
- gest_pt_log_coordinate(buf[GEST_PTLG_ID_LEN+4+i*2],buf[GEST_PTLG_ID_LEN+4+i*2+1]);
+ I("gest doornidate start\n %s", __func__);
+ while (i < (gest_len + 1) / 2) {
+ gest_pt_log_coordinate
+ (buf[GEST_PTLG_ID_LEN + 4 + i * 2],
+ buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]);
i++;
- I("gest_pt_x[%d]=%d \n",gest_pt_cnt,gest_pt_x[gest_pt_cnt]);
- I("gest_pt_y[%d]=%d \n",gest_pt_cnt,gest_pt_y[gest_pt_cnt]);
+ I("gest_pt_x[%d]=%d\n",
+ gest_pt_cnt, gest_pt_x[gest_pt_cnt]);
+ I("gest_pt_y[%d]=%d\n",
+ gest_pt_cnt, gest_pt_y[gest_pt_cnt]);
- gest_pt_cnt +=1;
+ gest_pt_cnt += 1;
}
- 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, 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 @@
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 @@
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 @@
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 == 1 && HX_ESD_RESET_ACTIVATE == 0)
- {
- I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n");
+ if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) {
+ I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n");
ESD_HW_REST();
return;
}
- else if (HX_ESD_RESET_ACTIVATE)
- {
+ 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) {
#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 @@
}
}
- //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)
- {
- mutual_data = getMutualBuffer_2();
- self_data = getSelfBuffer();
- // initiallize the block number of mutual and self
+#ifdef HX_TP_PROC_2T2R
+ if (Is_2T2R && diag_cmd == 4) {
+ mutual_data = getMutualBuffer_2();
+ self_data = getSelfBuffer();
+
+ /* 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;
+ 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;
+ 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--;
+ /* Touch Point information*/
+ if ((hx_point_num != 0) && (vk_press == 0x00)) {
+ uint16_t old_finger = ts->pre_finger_mask;
- 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);
- }
- }
- }
+ 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 (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);
- }
- }
- }
- }
- }
-
- }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;
+ 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)
+
+ 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);
-
- 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;
+ } else {
+ ts->last_slot = i;
+ input_mt_report_slot_state
+ (ts->input_dev,
+ MT_TOOL_FINGER, 1);
}
- if (ts->first_pressed == 1) {
+ if (!ts->first_pressed) {
+ ts->first_pressed = 1;
+ I("S1@%d, %d\n", x, y);
+ }
+
+ 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]);
+ I("E1@%d, %d\n",
+ ts->pre_finger_data[0][0],
+ ts->pre_finger_data[0][1]);
}
-
- if (ts->debug_log_level & BIT(1))
- I("All Finger leave\n");
-
+ 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;
- }
- else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) {
- 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);
}
- 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);
+ } 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);
+ }
+ }
+ 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]);
+ }
+
+ 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;
+ }
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
/* 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 @@
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 @@
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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
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 @@
}
#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 @@
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 @@
}
#endif
- return 0;
+ return 0;
#ifdef CONFIG_FB
err_fb_notif_wq_create:
@@ -1783,8 +1834,10 @@
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 @@
}
}
#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 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 @@
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 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 @@
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 @@
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 27ce9aa..c4e24ba 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 <asm/segment.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
+/*#include <asm/uaccess.h>*/
+/*#include <asm/atomic.h>*/
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
#include <linux/delay.h>
#include <linux/i2c.h>
@@ -36,7 +40,6 @@
#include <linux/buffer_head.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
-#include "himax_platform.h"
#if defined(CONFIG_FB)
#include <linux/notifier.h>
@@ -48,7 +51,7 @@
#ifdef CONFIG_OF
#include <linux/of_gpio.h>
#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
+/*===========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_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_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 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 @@
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 @@
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 @@
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 @@
#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 @@
#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 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 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 @@
};
#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 @@
#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 @@
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 f8bee11..a5bdbf2 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
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 @@
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 @@
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<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);
+ 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)
+ if (i != len - 2)
ts->debug_log_level <<= 4;
}
@@ -395,8 +346,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 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(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 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 @@
{
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 @@
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 @@
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 @@
{
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 @@
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);
+ debug_level_cmd = buf[0];
+ fw_update_complete = false;
- himax_int_enable(private_ts->client->irq,0);
-
- debug_level_cmd = buf[0];
- fw_update_complete = false;
-
- memset(fileName, 0, 128);
- // 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;
+ 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;
}
- I("%s: FW len %d\n", __func__, fw->size);
- fw_data = (unsigned char *)fw->data;
+ memset(fileName, 0, 128);
+/* parse the file name*/
+ snprintf(fileName, len-4, "%s", &buf[4]);
+ I("%s: upgrade from file(%s) start!\n", __func__, fileName);
+ result = request_firmware(&fw, fileName, private_ts->dev);
+ 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);
- 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 ((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 @@
#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 @@
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 @@
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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
/* 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 @@
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 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 @@
{
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 91a7ae2..7a24a17 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);
-#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};
+ 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);
+#endif
+ 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 @@
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 @@
#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 @@
#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 6ad8dc0..e2934c2 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"
-};
+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 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;
-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
+ /*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 @@
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 @@
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 @@
}
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 @@
{
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 @@
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;
+ 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);
+ 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;
+ /*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 @@
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 @@
}
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 @@
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 @@
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];
-int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length)
-{
- uint8_t data_byte[256];
- int i = 0, j = 0;
-
- 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;
+ if (i2c_himax_write(client, 0x00,
+ data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
}
- return 0;
}
-int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data)
+int himax_flash_write_burst_length(struct i2c_client *client,
+uint8_t *reg_byte, uint8_t *write_data, int length)
{
- int i =0, address = 0;
- int ret = 0;
+ uint8_t data_byte[256];
+ int i = 0, j = 0, err = -1;
- address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0];
+ for (i = 0 ; i < 4 ; i++)
+ data_byte[i] = reg_byte[i];
- for (i = address; i < address + write_length * 4; i = i + 4)
- {
- if (write_length > 1)
- {
+ 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 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];
+
+ 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 @@
{
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 @@
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 @@
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 @@
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]);
+ 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(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);
+ /*=====================================
+ 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_lenth(client, tmp_addr, tmp_data, 4);
+ 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 @@
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 @@
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 @@
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);
+ 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);
+ 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);
+ /*=====================================
+ 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);
+ 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] = 0x20;
- 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);
- msleep(200);
+ msleep(200);
- if (!wait_wip(client, 100))
- {
- E("%s:83100_Erase Fail\n", __func__);
- return false;
- }
- }
- return true;
+ 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 */
- for (i = 0; i < FW_length; i = i + 128)
- {
+ /*himax_sense_off(client);*/
+
+ 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 @@
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);
+ 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;
}
- 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);
-
- //=================================
- // 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 @@
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 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);
+ 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_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);
- }
- 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);
+ 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
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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)
+ /*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) {
+ 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) {
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+ }
+
+ /*if (isBusrtOn == false)
{
- 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) {
- 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) {
- 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) {
- 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;
- // }
- //}
+ 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 @@
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 @@
}
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);
+ 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);
+ /*==================================
+ 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];
+ 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];
-
+ /*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 @@
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);
+ 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;
+ 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 @@
{
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 @@
{
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];
+ if (temp1 >= temp2)
+ break;
+
+ /*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 18cd12b..ce7d0d4 100644
--- a/drivers/input/touchscreen/hxchipset/himax_ic.h
+++ b/drivers/input/touchscreen/hxchipset/himax_ic.h
@@ -18,7 +18,6 @@
#include <linux/slab.h>
-
#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 @@
};
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 7e8a1d6..309bb5e 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 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
};
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 @@
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 @@
}
#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;
- }
+ int retval;
- return 0;
+ 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;
+ 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;
+ 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 @@
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,187 +403,163 @@
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;
-
-#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;
- }
- }
-#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));
- }
+ int error = 0;
-#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);
- }
- else
- {
- E("irq gpio not provided\n");
+#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;
}
-#endif
-
- 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;
- }
+ error = gpio_direction_output(pdata->gpio_reset, 0);
+ if (error) {
+ E("unable to set direction for gpio [%d]\n",
+ pdata->gpio_reset);
+ return error;
}
- msleep(20);
+ }
#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));
+ }
+
+#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);
+ } else {
+ E("irq gpio not provided\n");
return error;
}
#endif
+ 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;
+ }
+ }
+ msleep(20);
+#endif
+
+ return error;
+}
+#endif
+
static void himax_ts_isr_func(struct himax_ts_data *ts)
{
himax_ts_work(ts);
@@ -595,34 +575,40 @@
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 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 @@
} 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 @@
{
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 @@
{
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 @@
{
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 @@
};
#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 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_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 1223685..6871e53 100644
--- a/drivers/input/touchscreen/hxchipset/himax_platform.h
+++ b/drivers/input/touchscreen/hxchipset/himax_platform.h
@@ -22,6 +22,7 @@
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+
#if defined(CONFIG_HMX_DB)
#include <linux/regulator/consumer.h>
#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 @@
#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 @@
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);
+int i2c_himax_read(struct i2c_client *client,
+ uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry);
-extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata);
+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 3359afb..a836169 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -4864,6 +4864,10 @@
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 6b71457..08fcdbf 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -213,11 +213,10 @@
}
#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 @@
.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 @@
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 d91dd58..37aaea8 100644
--- a/drivers/isdn/hardware/eicon/diva.c
+++ b/drivers/isdn/hardware/eicon/diva.c
@@ -387,10 +387,10 @@
** 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 @@
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 @@
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 @@
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 e979085..a0a607c 100644
--- a/drivers/isdn/hardware/eicon/diva.h
+++ b/drivers/isdn/hardware/eicon/diva.h
@@ -19,10 +19,11 @@
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 32f3451..1e8b991 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -591,19 +591,22 @@
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_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 8a850c5..3f97c803 100644
--- a/drivers/leds/leds-qpnp-haptics.c
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -2515,6 +2515,16 @@
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 @@
},
.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 861d987..d272ca6 100644
--- a/drivers/leds/leds-qpnp-wled.c
+++ b/drivers/leds/leds-qpnp-wled.c
@@ -22,6 +22,7 @@
#include <linux/spmi.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/leds-qpnp-wled.h>
@@ -420,6 +421,7 @@
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 @@
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 @@
__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 @@
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 @@
/* 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 @@
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 89fc93b..dafa981 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -551,4 +551,24 @@
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 809a4df..c837def 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -373,9 +373,6 @@
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 @@
* 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 @@
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 @@
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 @@
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;
+ 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);
- 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;
-
- 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 eb419a5..ea1bfc1 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -1384,6 +1384,8 @@
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 @@
if (r)
return;
- if (nr_free)
+ if (nr_free) {
set_pool_mode(pool, PM_WRITE);
+ requeue_bios(pool);
+ }
}
/*
@@ -1474,7 +1478,10 @@
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 d96aa84..0a7a828 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -1049,6 +1049,14 @@
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 de0f8de..13b3424 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -2694,7 +2694,8 @@
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 @@
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 01511e5..2f054db 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -251,8 +251,20 @@
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 @@
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 d558ed3..cc56660 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -467,8 +467,13 @@
{
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 @@
* 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 @@
/* 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 @@
* 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/Makefile b/drivers/media/platform/msm/Makefile
index 24c27cd..e19da45 100644
--- a/drivers/media/platform/msm/Makefile
+++ b/drivers/media/platform/msm/Makefile
@@ -9,3 +9,4 @@
obj-$(CONFIG_MSMB_CAMERA) += camera_v2/
obj-y += broadcast/
obj-$(CONFIG_DVB_MPQ) += dvb/
+obj-$(CONFIG_QCA402X) += qca402/
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 29de315..cddbd83 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 @@
.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 fa98be2..e4ec08b 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 @@
.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 c8b830f..a97a5196 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 @@
2, /* GenerateIRQ*/
3, /* WaitForEvent*/
1, /* ChangeBase*/
- 1, /* PERF_CONTINUOUSROL*/
+ 1, /* PERF_CONTROL*/
3, /* DMI32*/
3, /* DMI64*/
};
@@ -540,3 +548,169 @@
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 09d0d63..8f2b488 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 @@
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 f167ef7..fce7fc6 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 @@
*/
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 90603de..2120650 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 0187a64..cdc8a3b 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 @@
}
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 @@
.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 b73b32a..83cd326 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 @@
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 f6ae8a8..7f50d12 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_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_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 158bbb9..f8687cf 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 @@
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 @@
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 @@
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 3f01244..d5068ca 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 @@
.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/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 a18afc6..87dc694 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 @@
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 @@
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 6d9d330..c7ef37c 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 @@
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 @@
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 @@
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 @@
.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 4f91f73..7df806b 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 @@
.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 4256064..3e636c6 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 @@
* @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 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;
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 2153cea..f652cfa 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 @@
/**
* @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
};
/**
@@ -286,6 +292,16 @@
};
/**
+ * struct sfr_buf
+ * @size: Number of characters
+ * @msg : Subsystem failure reason
+ */
+struct sfr_buf {
+ uint32_t size;
+ char msg[ICP_MSG_SFR_SIZE_IN_BYTES];
+};
+
+/**
* struct hfi_q_tbl
* @q_tbl_hdr: Queue table header
* @q_hdr: Queue header info, it holds info of cmd, msg and debug queues
diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c
index de72e85..14a3e65 100644
--- a/drivers/media/platform/msm/camera/cam_icp/hfi.c
+++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c
@@ -600,7 +600,7 @@
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);
@@ -610,6 +610,8 @@
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,
@@ -635,6 +637,7 @@
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);
@@ -716,6 +719,9 @@
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;
@@ -788,7 +794,10 @@
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,
@@ -845,7 +854,7 @@
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 4aa6b4b..f4bc813 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 14c3c9c..3b652e7 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 @@
.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 5bd7f1c..d016374 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 <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
+#include <linux/iopoll.h>
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
@@ -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 @@
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 @@
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 feb0bd8..56abb4b 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 @@
};
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 @@
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 @@
.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 d2314c4..1da99a4 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 @@
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 3c5690d..d32d4b6 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 @@
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 @@
* 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 @@
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 @@
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 @@
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 @@
}
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 @@
rc = -ENOMEM;
goto err;
}
- icp_hw_mgr.icp_pc_flag = false;
if (!debugfs_create_bool("ipe_bps_pc",
0644,
@@ -1328,8 +1332,6 @@
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 @@
return rc;
err:
debugfs_remove_recursive(icp_hw_mgr.dentry);
+ icp_hw_mgr.dentry = NULL;
return rc;
}
@@ -1456,8 +1459,10 @@
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 @@
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 @@
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 @@
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:
@@ -1862,6 +1983,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
}
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 @@
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;
@@ -2407,7 +2579,8 @@
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]);
@@ -2640,6 +2813,10 @@
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;
@@ -2800,6 +2977,7 @@
hw_mgr->ctxt_cnt = 0;
hw_mgr->fw_download = true;
+ hw_mgr->recovery = false;
CAM_INFO(CAM_ICP, "FW download done successfully");
@@ -3014,8 +3192,10 @@
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);
@@ -3201,8 +3381,11 @@
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) {
@@ -3218,7 +3401,9 @@
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;
@@ -3439,7 +3624,8 @@
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);
@@ -3635,6 +3821,7 @@
{
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:");
@@ -3654,10 +3841,22 @@
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);
@@ -3695,7 +3894,7 @@
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");
@@ -3716,9 +3915,15 @@
}
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);
@@ -3732,10 +3937,10 @@
}
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");
+ CAM_DBG(CAM_ICP, "Release done for ctx_id %d", ctx_id);
return rc;
}
@@ -3912,6 +4117,21 @@
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;
@@ -4043,7 +4263,10 @@
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;
@@ -4289,6 +4512,9 @@
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 3e3c0e0..0b931f3 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 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;
};
@@ -309,6 +311,9 @@
* @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;
@@ -356,6 +361,7 @@
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 4f07172..0f76a05 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 @@
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 0943bef..d1e3b9a 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 @@
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 87478af..620a4bd 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 <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
+#include <linux/iopoll.h>
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
@@ -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 @@
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 @@
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 cc2b1b1..a01d114 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 @@
};
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 @@
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 @@
.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 d24305a..91d440f 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 @@
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 7b02aac..f5b1bb1 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 @@
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 @@
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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 e775daa..a067915 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 @@
.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 e5c54d6..8d764b0 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
@@ -1540,7 +1540,7 @@
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,
@@ -1696,8 +1696,6 @@
"config done Success for req_id=%llu",
cfg->request_id);
}
-
- rc = 0;
}
} else {
CAM_ERR(CAM_ISP, "No commands to config");
@@ -1953,7 +1951,8 @@
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)) {
@@ -2231,7 +2230,7 @@
}
/* 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;
@@ -2418,7 +2417,7 @@
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,
@@ -2571,7 +2570,8 @@
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;
@@ -2699,6 +2699,52 @@
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;
@@ -2730,6 +2776,9 @@
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);
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 1444911..abc6bb0 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
@@ -469,11 +469,12 @@
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;
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 3a89732..2c08e4d 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 @@
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 @@
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 @@
*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 @@
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 @@
}
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 @@
{
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 @@
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 @@
&tasklet->free_cmd_list);
}
+ atomic_set(&tasklet->tasklet_active, 1);
+
tasklet_enable(&tasklet->tasklet);
return 0;
@@ -298,9 +300,10 @@
{
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 @@
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 0e4bf12..8bd93d8 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 @@
* @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 @@
* @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 feb79cc..e418fa9 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 <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/ratelimit.h>
+
#include "cam_io_util.h"
#include "cam_irq_controller.h"
#include "cam_debug_util.h"
@@ -42,7 +44,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 e3071ac..c3c1e7c 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_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 @@
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 5410858..8f1911e 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 @@
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 @@
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 bdd59d2..70223f1 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 @@
.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 29b9e11..e5fb03f 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
@@ -1851,8 +1851,8 @@
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;
@@ -2476,6 +2476,61 @@
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)
{
@@ -2498,8 +2553,11 @@
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;
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 128c050..2556b65 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 @@
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 @@
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 36c6df0..6c39bd8 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 @@
.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 e11ff63..d3261f8 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 @@
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 8911f99..bbd092f 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 @@
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 c56c49f..70e0467 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 @@
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 fd38a96..f6becfb 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 @@
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 @@
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 @@
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 @@
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 74627b8..66b647d 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 @@
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 0af32ad..d002f84 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 @@
.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 3c8abbf..ab692cf 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 @@
.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 3c37b83..67b572e 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 @@
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 @@
/* 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 @@
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 @@
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 8bc9bd2..b554fe4 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 @@
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 @@
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 @@
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 @@
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 be0ca18..47a0438 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 @@
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 60feeac..46cc08f 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 @@
.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 fdeee54..f0913b2 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 @@
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 @@
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 @@
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;
+ }
+
+ 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 @@
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 @@
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 @@
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_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;
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 ef10406..fd4fdab 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 @@
.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 9fa691b..7fcc1ad 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 @@
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 d1eb526..d4daa6d 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 @@
.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 5be16ef..a4ee104 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 @@
.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/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 6f98354..595bb81 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 @@
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 @@
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 ec392f5..ec42978 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
@@ -300,6 +300,7 @@
.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 93e4249..d192018 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 @@
{
*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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
int rc = 0;
if (!hdl || !buf) {
- CAM_ERR(CAM_CRM, "Invalid params");
+ CAM_ERR(CAM_MEM, "Invalid params");
return -EINVAL;
}
@@ -320,7 +320,7 @@
*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 @@
int rc = 0;
if (!hdl || !fd) {
- CAM_ERR(CAM_CRM, "Invalid params");
+ CAM_ERR(CAM_MEM, "Invalid params");
return -EINVAL;
}
@@ -353,7 +353,7 @@
*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_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_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 @@
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 @@
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 @@
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 @@
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 @@
&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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
return rc;
unmap_end:
- CAM_ERR(CAM_CRM, "unmapping failed");
+ CAM_ERR(CAM_MEM, "unmapping failed");
return rc;
}
@@ -762,11 +763,11 @@
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 @@
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 @@
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 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 @@
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 @@
&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 @@
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 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 @@
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 @@
&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 @@
&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 @@
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 @@
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 060aaf2..346cd56 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 @@
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 @@
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 @@
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 @@
__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 @@
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 @@
}
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 @@
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 @@
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 @@
* - 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);
@@ -1115,6 +1116,32 @@
}
/**
+ * __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()
*
* @brief : Apoptosis - Handles case when connected devices are not responding
@@ -1138,6 +1165,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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;
@@ -2499,7 +2553,7 @@
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;
@@ -2516,8 +2570,8 @@
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;
@@ -2591,6 +2645,9 @@
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 9a93feb..543e332 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 @@
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 @@
.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 1ca6cc5..9929212 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_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_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c
index da8ff21..ed0a26b 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
@@ -54,6 +54,7 @@
free_power_settings:
kfree(power_info->power_setting);
power_info->power_setting = NULL;
+ power_info->power_setting_size = 0;
return rc;
}
@@ -269,7 +270,10 @@
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);
}
}
@@ -359,6 +363,28 @@
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) {
@@ -368,7 +394,7 @@
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;
@@ -391,7 +417,6 @@
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;
@@ -555,6 +580,7 @@
"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) {
@@ -564,11 +590,13 @@
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;
@@ -583,20 +611,19 @@
"Manual move lens parsing failed: %d", rc);
return rc;
}
- break;
- }
- if ((csl_packet->header.op_code & 0xFFFFFF) !=
- CAM_ACTUATOR_PACKET_OPCODE_INIT) {
- add_req.link_hdl = a_ctrl->bridge_intf.link_hdl;
- add_req.req_id = csl_packet->header.request_id;
- add_req.dev_hdl = a_ctrl->bridge_intf.device_hdl;
- add_req.skip_before_applying = 0;
- if (a_ctrl->bridge_intf.crm_cb &&
- a_ctrl->bridge_intf.crm_cb->add_req)
- a_ctrl->bridge_intf.crm_cb->add_req(&add_req);
- CAM_DBG(CAM_ACTUATOR, "Req Id: %lld added to Bridge",
- add_req.req_id);
+ 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;
+ }
+
+ cam_actuator_update_req_mgr(a_ctrl, csl_packet);
+ break;
}
return rc;
@@ -633,6 +660,8 @@
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;
}
@@ -642,12 +671,19 @@
{
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);
@@ -730,6 +766,12 @@
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: {
@@ -836,6 +878,11 @@
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 733c9e8..7d23f90 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
@@ -397,6 +397,7 @@
.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 b47f4f3..058e352 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 @@
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 c8ca85d..ce7ac3f 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 @@
.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 2688cd5..bc61df4 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 @@
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 e2f061f..32bb34b 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 @@
.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 afe4239..9c85af3 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 @@
* @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 @@
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 6db5a97..28326ec 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 @@
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 @@
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 7f94f8d..c8730ca 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 @@
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 @@
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 b8c32d4..cc34a70 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 @@
.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 5a6a401..afab016 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 @@
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 @@
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 @@
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 f0efd4c..4a9cfb0 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 @@
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 @@
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],
@@ -338,6 +338,10 @@
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 !=
@@ -381,6 +385,10 @@
} 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);
@@ -411,6 +419,8 @@
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 */
@@ -445,6 +455,8 @@
} 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) &&
@@ -482,8 +494,14 @@
"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;
}
}
@@ -754,17 +772,20 @@
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;
@@ -914,19 +935,15 @@
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 f9411fc..d9b5f64 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 @@
.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 92726a9..4adc1b2 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 @@
* @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 6f77e0e..c2d2e5f 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
@@ -56,6 +56,7 @@
free_power_settings:
kfree(power_info->power_setting);
power_info->power_setting = NULL;
+ power_info->power_setting_size = 0;
return rc;
}
@@ -638,10 +639,9 @@
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;
@@ -666,6 +666,8 @@
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;
}
@@ -679,11 +681,13 @@
*/
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;
}
@@ -694,6 +698,10 @@
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:
@@ -764,6 +772,13 @@
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_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_res_mgr/cam_res_mgr.c
index bb3789b..d03faef 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 @@
.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 6fe051a..a2431be 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 @@
&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 @@
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 @@
{
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,8 +590,6 @@
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 {
@@ -603,9 +599,6 @@
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,
@@ -615,9 +608,7 @@
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*/
@@ -629,18 +620,14 @@
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 */
@@ -648,9 +635,7 @@
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,
@@ -662,9 +647,7 @@
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
@@ -678,6 +661,15 @@
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;
@@ -886,6 +878,16 @@
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)
@@ -962,6 +964,16 @@
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);
@@ -999,6 +1011,16 @@
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;
@@ -1131,7 +1153,7 @@
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);
@@ -1155,6 +1177,11 @@
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 b60111a..6cf40f8 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 @@
.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 cc6070c..34f8b8d 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 @@
* @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 @@
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 1c3ead0..e997419 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 @@
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 @@
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 1c6ab0b..9145a1e 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 @@
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 @@
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 @@
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 73a0cf7..46bda05 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 @@
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 @@
(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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
rc);
soc_info->rgltr[vreg_idx] = NULL;
+ goto power_up_failed;
}
rc = cam_soc_util_regulator_enable(
@@ -1442,7 +1538,12 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 c9ccc5c..6c0287e 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 @@
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 5cd3008..52da37f 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 @@
.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 55896f4..e5df874 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 @@
} 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);
@@ -166,6 +167,7 @@
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);
@@ -220,20 +222,36 @@
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
@@ -244,15 +262,13 @@
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
@@ -337,10 +353,8 @@
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;
}
@@ -352,7 +366,6 @@
} 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);
@@ -1053,6 +1066,7 @@
.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 43bce51..f391c8c 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
@@ -31,20 +31,21 @@
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;
@@ -58,147 +59,95 @@
return 0;
}
-uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table,
- uint32_t *sync_objs,
- uint32_t num_objs)
-{
- int i;
- struct sync_table_row *child_row = NULL;
- int success_count = 0;
- int active_count = 0;
-
- if (!table || !sync_objs)
- return CAM_SYNC_STATE_SIGNALED_ERROR;
-
- /*
- * We need to arrive at the state of the merged object based on
- * counts of error, active and success states of all children objects
- */
- for (i = 0; i < num_objs; i++) {
- spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
- child_row = table + sync_objs[i];
- switch (child_row->state) {
- case CAM_SYNC_STATE_SIGNALED_ERROR:
- spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
- return CAM_SYNC_STATE_SIGNALED_ERROR;
- case CAM_SYNC_STATE_SIGNALED_SUCCESS:
- success_count++;
- break;
- case CAM_SYNC_STATE_ACTIVE:
- active_count++;
- break;
- default:
- CAM_ERR(CAM_SYNC,
- "Invalid state of child object during merge");
- spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
- return CAM_SYNC_STATE_SIGNALED_ERROR;
- }
- spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
- }
-
- 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;
+ 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;
- INIT_LIST_HEAD(&row->parents_list);
-
- INIT_LIST_HEAD(&row->children_list);
+ cam_sync_init_row(table, idx, "merged_fence", CAM_SYNC_TYPE_GROUP);
/*
- * 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
+ * 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_info = kzalloc(sizeof(*child_info), GFP_ATOMIC);
-
- if (!child_info) {
- cam_sync_util_cleanup_children_list(row,
- SYNC_LIST_CLEAN_ALL, 0);
- return -ENOMEM;
- }
-
- child_info->sync_id = sync_objs[i];
- list_add_tail(&child_info->list, &row->children_list);
- }
-
- for (i = 0; i < num_objs; i++) {
- /* This gets us the row corresponding to the sync object */
child_row = table + sync_objs[i];
spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+
+ /* validate child */
+ if ((child_row->type == CAM_SYNC_TYPE_GROUP) ||
+ (child_row->state == CAM_SYNC_STATE_INVALID)) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ CAM_ERR(CAM_SYNC,
+ "Invalid child fence:%i state:%u type:%u",
+ child_row->sync_id, child_row->state,
+ child_row->type);
+ rc = -EINVAL;
+ goto clean_children_info;
+ }
+
+ /* check for child's state */
+ if (child_row->state == CAM_SYNC_STATE_SIGNALED_ERROR) {
+ row->state = CAM_SYNC_STATE_SIGNALED_ERROR;
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ continue;
+ }
+ if (child_row->state != CAM_SYNC_STATE_ACTIVE) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ continue;
+ }
+
+ row->remaining++;
+
+ /* Add child info */
+ child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC);
+ if (!child_info) {
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ rc = -ENOMEM;
+ goto clean_children_info;
+ }
+ child_info->sync_id = sync_objs[i];
+ list_add_tail(&child_info->list, &row->children_list);
+
+ /* Add parent info */
parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC);
if (!parent_info) {
- 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);
-
- if (row->state != CAM_SYNC_STATE_ACTIVE)
- complete_all(&row->signaled);
-
return 0;
+
+clean_children_info:
+ row->state = CAM_SYNC_STATE_INVALID;
+ for (i = i-1; i >= 0; i--) {
+ spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ child_row = table + sync_objs[i];
+ cam_sync_util_cleanup_parents_list(child_row,
+ SYNC_LIST_CLEAN_ONE, idx);
+ spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]);
+ }
+
+ cam_sync_util_cleanup_children_list(row, SYNC_LIST_CLEAN_ALL, 0);
+ return rc;
}
int cam_sync_deinit_object(struct sync_table_row *table, uint32_t idx)
@@ -363,32 +312,6 @@
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)
@@ -409,34 +332,27 @@
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;
+ int rc = 0;
- 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;
-
+ 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 ae7d542..a9d6f86 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 @@
* @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
@@ -104,16 +103,6 @@
int len);
/**
- * @brief: Function to validate sync merge arguments
- *
- * @param sync_obj : Array of sync objects to merge
- * @param num_objs : Number of sync objects in the array
- *
- * @return Status of operation. Negative in case of error. Zero otherwise.
- */
-int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs);
-
-/**
* @brief: Function which adds sync object information to the signalable list
*
* @param sync_obj : Sync object to add
@@ -135,7 +124,7 @@
*
* @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 26f2ba1..4f32634 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 @@
name = "CAM-CORE";
break;
case CAM_CRM:
- name = "CAM_CRM";
+ name = "CAM-CRM";
break;
case CAM_CPAS:
name = "CAM-CPAS";
@@ -86,6 +86,18 @@
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 4e97100..1ed7056 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_soc_util.c b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.c
index d0a13ab..a5456a9 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 @@
}
#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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ 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 @@
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 @@
/* 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 18fad8d..4c6ed4b 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 <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/clk/qcom.h>
+#include <linux/debugfs.h>
#include "cam_io_util.h"
@@ -156,6 +157,9 @@
* @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_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 @@
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 90ec566..c7dc0b6 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_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 21bac16..b5a6f44 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 @@
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/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c
index 1ad2f257..85ca275 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 @@
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 @@
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 cd16236..f4305ea 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 @@
.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 @@
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;
}
- /*IMPLEMENT READING PART*/
+ 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;
+ }
+
+ 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 @@
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 @@
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 7832181..4bc13d0 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 @@
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 @@
/* 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 @@
/* 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/qca402/Makefile b/drivers/media/platform/msm/qca402/Makefile
new file mode 100644
index 0000000..cffd2c4
--- /dev/null
+++ b/drivers/media/platform/msm/qca402/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for MSM HTC driver.
+#
+obj-y += msm_qca402.o
diff --git a/drivers/media/platform/msm/qca402/msm_qca402.c b/drivers/media/platform/msm/qca402/msm_qca402.c
new file mode 100644
index 0000000..74b4929
--- /dev/null
+++ b/drivers/media/platform/msm/qca402/msm_qca402.c
@@ -0,0 +1,1530 @@
+/* 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/of_device.h>
+#include <uapi/media/msmb_qca.h>
+#include <linux/spinlock_types.h>
+#include "msm_qca402.h"
+
+#define DEVICE_NAME "msm_qca402char"
+#define DEVICE_CLASS "msm_qca402"
+#define MAX_DEVICE_NUM (1)
+#define QCA402_START_ENQ_BUFFS (8)
+#define QCA402_MAX_EVENTS_IN_MSG (16)
+#undef pr_fmt
+#define pr_fmt(fmt) "[qca402x]: %s: " fmt, __func__
+
+static int msm_qca402_major;
+static struct class *msm_qca402_class;
+struct msm_qca402_device_t {
+ struct msm_qca402_dev_data_t *dev;
+ struct task_struct *user_task;
+ struct task_struct *recv_task;
+};
+
+static struct msm_qca402_device_t msm_qca402_device[MAX_DEVICE_NUM];
+
+static const struct of_device_id msm_qca402_dt_match[] = {
+ {
+ .compatible = "qcom,qca402",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, msm_qca402_dt_match);
+
+static int msm_qca402_open(struct inode *ip, struct file *fp)
+{
+ struct msm_qca402_dev_data_t *dev_data = container_of(ip->i_cdev,
+ struct msm_qca402_dev_data_t, cdev);
+ struct msm_qca402_file_data_t *file_data;
+ struct file_data_list_t *f_entry;
+
+ pr_debug("called for device %d\n", dev_data->dev_idx);
+
+ file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
+ if (!file_data)
+ return -EINVAL;
+ pr_debug("Out q %pK", &file_data->out_queue);
+ init_waitqueue_head(&file_data->out_queue);
+ /* initialize channel list here */
+ file_data->dev_data = dev_data;
+ INIT_LIST_HEAD(&file_data->evt_list);
+ INIT_LIST_HEAD(&file_data->ready_ch_list);
+ mutex_init(&file_data->file_mutex);
+ f_entry = kzalloc(sizeof(*f_entry), GFP_KERNEL);
+ if (!f_entry) {
+ mutex_destroy(&file_data->file_mutex);
+ kfree(file_data);
+ return -EINVAL;
+ }
+ f_entry->file_data = file_data;
+ list_add_tail(&f_entry->list, &dev_data->file_list);
+ fp->private_data = file_data;
+ return 0;
+}
+
+static void msm_qca402_free_file_data(struct msm_qca402_file_data_t *file_data)
+{
+ struct msm_qca402_evt_list_t *cur_evt, *next_evt;
+ struct msm_qca402_ready_list_t *cur_rch, *next_rch;
+
+ list_for_each_entry_safe(cur_evt, next_evt, &file_data->evt_list,
+ list) {
+ list_del_init(&cur_evt->list);
+ kfree(cur_evt);
+ break;
+ }
+ list_for_each_entry_safe(cur_rch, next_rch, &file_data->ready_ch_list,
+ list) {
+ list_del_init(&cur_rch->list);
+ kfree(cur_rch);
+ break;
+ }
+ mutex_destroy(&file_data->file_mutex);
+ kfree(file_data);
+}
+
+static void msm_qca402_release_file(struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca402_file_data_t *file_data)
+{
+ struct file_data_list_t *f_entry;
+ struct file_data_list_t *next;
+
+ list_for_each_entry_safe(f_entry, next, &dev_data->file_list, list) {
+ if (!file_data || f_entry->file_data == file_data) {
+ list_del_init(&f_entry->list);
+ msm_qca402_free_file_data(f_entry->file_data);
+ kfree(f_entry);
+ break;
+ }
+ }
+}
+
+static int msm_qca402_release(struct inode *ip, struct file *fp)
+{
+ struct msm_qca402_file_data_t *file_data =
+ (struct msm_qca402_file_data_t *)fp->private_data;
+ struct msm_qca402_dev_data_t *dev_data = container_of(ip->i_cdev,
+ struct msm_qca402_dev_data_t, cdev);
+
+ pr_debug("called\n");
+
+ msm_qca402_release_file(dev_data, file_data);
+
+ return 0;
+}
+
+static struct msm_qca402_channel_list_t *msm_qca402_init_channel(
+ struct msm_qca402_dev_data_t *dev_data,
+ __u32 channel_id)
+{
+ struct msm_qca402_channel_list_t *channel = NULL;
+ struct msm_qca402_channel_list_t *new_channel = NULL;
+
+ list_for_each_entry(channel, &dev_data->channel_list, list) {
+ if (channel->channel_id == channel_id) {
+ channel->ref_cnt++;
+ pr_debug("channel with %d exists\n", channel_id);
+ return channel;
+ }
+ }
+ new_channel = kzalloc(sizeof(*new_channel), GFP_KERNEL);
+ if (!new_channel)
+ return NULL;
+ new_channel->channel_id = channel_id;
+ INIT_LIST_HEAD(&new_channel->enqueued_list);
+ INIT_LIST_HEAD(&new_channel->ready_list);
+ INIT_LIST_HEAD(&new_channel->dequeued_list);
+ list_add_tail(&new_channel->list, &dev_data->channel_list);
+ new_channel->ref_cnt = 1;
+ return new_channel;
+}
+
+static void msm_qca402_free_buffer_list(struct msm_qca402_dev_data_t *dev_data,
+ struct list_head *buffer_list)
+{
+ struct msm_qca402_buffer_list_t *buffer;
+ struct msm_qca402_buffer_list_t *n_buffer;
+
+ list_for_each_entry_safe(buffer, n_buffer, buffer_list, list) {
+ if (buffer->ih)
+ ion_unmap_kernel(dev_data->ion_client, buffer->ih);
+ list_del_init(&buffer->list);
+ kfree(buffer);
+ }
+}
+
+static int msm_qca402_deinit_channel(
+ struct msm_qca402_dev_data_t *dev_data,
+ __u32 channel_id)
+{
+ struct msm_qca402_channel_list_t *channel;
+ struct msm_qca402_channel_list_t *c_channel = NULL;
+
+ list_for_each_entry(channel, &dev_data->channel_list, list) {
+ if (channel->channel_id == channel_id) {
+ c_channel = channel;
+ break;
+ }
+ }
+ if (!c_channel) {
+ pr_debug("No channel %d\n", channel_id);
+ return -EINVAL;
+ }
+ c_channel->ref_cnt--;
+ if (channel->ref_cnt)
+ return 0;
+ msm_qca402_free_buffer_list(dev_data, &channel->enqueued_list);
+ msm_qca402_free_buffer_list(dev_data, &channel->ready_list);
+ msm_qca402_free_buffer_list(dev_data, &channel->dequeued_list);
+ list_del_init(&channel->list);
+ kfree(channel);
+ return 0;
+}
+
+static void msm_qca402_unregister_events(
+ struct msm_qca402_file_data_t *file_data, int num_events,
+ struct msm_qca_event_type *evts)
+{
+ int i;
+ struct msm_qca402_evt_list_t *c_evt_entry;
+ struct msm_qca402_evt_list_t *next;
+
+ for (i = 0; i < num_events; i++) {
+ list_for_each_entry_safe(c_evt_entry, next,
+ &file_data->evt_list, list) {
+ if (c_evt_entry->channel_id == evts[i].channel_id &&
+ c_evt_entry->cmd == evts[i].cmd) {
+ pr_debug("%pK Unregistering %d %d\n", file_data,
+ c_evt_entry->channel_id,
+ c_evt_entry->cmd);
+ msm_qca402_deinit_channel(file_data->dev_data,
+ evts[i].channel_id);
+ list_del_init(&c_evt_entry->list);
+ kfree(c_evt_entry);
+ break;
+ }
+ }
+ }
+}
+
+static int msm_qca402_register_events(struct msm_qca402_file_data_t *file_data,
+ int num_events,
+ struct msm_qca_event_type *evts)
+{
+ int i;
+ int ret = 0;
+ struct msm_qca402_evt_list_t *c_evt_entry;
+
+ for (i = 0; i < num_events; i++) {
+ c_evt_entry = kzalloc(sizeof(*c_evt_entry), GFP_KERNEL);
+ if (!c_evt_entry) {
+ ret = -ENOMEM;
+ break;
+ }
+ c_evt_entry->channel_id = evts[i].channel_id;
+ c_evt_entry->cmd = evts[i].cmd;
+ pr_debug("%pK Registering %d %d\n", file_data,
+ c_evt_entry->channel_id, c_evt_entry->cmd);
+ list_add_tail(&c_evt_entry->list, &file_data->evt_list);
+ msm_qca402_init_channel(file_data->dev_data,
+ evts[i].channel_id);
+ }
+
+ if (ret)
+ msm_qca402_unregister_events(file_data, num_events, evts);
+
+ return ret;
+}
+
+static void msm_qca402_free_workbuffs(struct msm_qca402_dev_data_t *dev_data)
+{
+ struct msm_qca402_workbuff_list_t *wb;
+ struct msm_qca402_workbuff_list_t *next;
+
+ list_for_each_entry_safe(wb, next, &dev_data->work_list, list) {
+ list_del_init(&wb->list);
+ kfree(wb);
+ }
+}
+
+static int msm_qca402_alloc_add_workbuffs(
+ struct msm_qca402_dev_data_t *dev_data,
+ __u32 num_buffs)
+{
+ int ret = 0;
+ int i;
+ struct msm_qca402_workbuff_list_t *wb;
+
+ for (i = 0; i < num_buffs; i++) {
+ wb = kzalloc(sizeof(*wb), GFP_KERNEL);
+ if (!wb) {
+ ret = -ENOMEM;
+ msm_qca402_free_workbuffs(dev_data);
+ break;
+ }
+ list_add_tail(&wb->list, &dev_data->work_list);
+ }
+ return ret;
+}
+
+static struct msm_qca402_workbuff_list_t *msm_qca402_get_workbuff(
+ struct msm_qca402_dev_data_t *dev_data)
+{
+ int ret;
+ struct msm_qca402_workbuff_list_t *wb;
+
+ if (list_empty(&dev_data->work_list)) {
+ ret = msm_qca402_alloc_add_workbuffs(dev_data, 1);
+ if (ret)
+ return NULL;
+ }
+ wb = list_first_entry(&dev_data->work_list,
+ struct msm_qca402_workbuff_list_t, list);
+ list_del_init(&wb->list);
+ return wb;
+}
+
+static void msm_qca402_propagate_event(struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca_event_type *event,
+ struct msm_qca402_channel_list_t *channel)
+{
+ struct msm_qca402_file_data_t *file_data;
+ struct file_data_list_t *f_entry;
+ struct msm_qca402_evt_list_t *e_entry;
+ struct msm_qca402_ready_list_t *r_entry;
+
+ list_for_each_entry(f_entry, &dev_data->file_list, list) {
+ file_data = f_entry->file_data;
+ list_for_each_entry(e_entry, &file_data->evt_list, list) {
+ if (e_entry->channel_id == event->channel_id &&
+ e_entry->cmd == event->cmd) {
+ /**
+ * put event into queue
+ * unblock poll
+ */
+ pr_debug("%d %d\n", event->channel_id,
+ e_entry->cmd);
+ r_entry = kzalloc(sizeof(*r_entry), GFP_KERNEL);
+ if (!r_entry)
+ return;
+
+ channel->ref_cnt += 1;
+ r_entry->ch_data = channel;
+ r_entry->cmd = e_entry->cmd;
+ list_add_tail(&r_entry->list,
+ &file_data->ready_ch_list);
+ pr_debug("called\n");
+ wake_up_interruptible(&file_data->out_queue);
+ }
+ }
+ }
+}
+
+static int msm_qca402_copy_data(struct msm_qca402_htca_message_t *htca_msg,
+ struct msm_qca402_buffer_list_t *buffer,
+ __u32 size)
+{
+
+ __u32 c_payload_size = 0;
+ __u32 c_meta_size = 0;
+
+ if (size < (QCA_MSG_HEADER_SIZE + htca_msg->header.meta_size))
+ return -EINVAL;
+ c_payload_size = size - htca_msg->header.meta_size -
+ QCA_MSG_HEADER_SIZE;
+
+
+ switch (htca_msg->header.msg_flags & LPCHTCA_PACKET_MASK) {
+ case LPCHTCA_FULL_PACKET:
+ case LPCHTCA_START_PACKET: {
+ if (buffer->valid_size > 0)
+ buffer->valid_size = 0;
+ if ((htca_msg->header.meta_size >
+ buffer->qca_msg.header_size) ||
+ (c_payload_size > buffer->qca_msg.data_size))
+ return -EINVAL;
+ c_meta_size = htca_msg->header.meta_size;
+ }
+ break;
+
+ case LPCHTCA_END_PACKET:
+ case LPCHTCA_MID_PACKET:
+ if (c_payload_size + buffer->valid_size >
+ buffer->qca_msg.data_size) {
+ /* indicate ERROR here */
+ return -EINVAL;
+ }
+ break;
+ case LPCHTCA_UNSPEC_PACKET:
+ if (c_payload_size + buffer->valid_size >
+ buffer->qca_msg.data_size) {
+ if (buffer->valid_size)
+ /* continue in next buffer */
+ return -ENOMEM;
+ else
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (c_meta_size)
+ if (copy_to_user((void __user *)
+ (uintptr_t)buffer->qca_msg.header,
+ htca_msg->payload,
+ c_meta_size))
+ return -EFAULT;
+
+ if (c_payload_size) {
+ __u8 *ptr;
+
+ if (buffer->vaddr) {
+ /* ion buffer */
+ ptr = (__u8 *)buffer->vaddr;
+ ptr += buffer->valid_size;
+ memcpy((void *)ptr,
+ &htca_msg->payload[htca_msg->header.meta_size],
+ c_payload_size);
+ } else {
+ ptr = (__u8 *)((uintptr_t)buffer->qca_msg.buff_addr);
+ ptr += buffer->valid_size;
+ if (copy_to_user((void __user *)ptr,
+ &htca_msg->payload[htca_msg->header.meta_size],
+ c_payload_size))
+ return -EFAULT;
+ }
+ buffer->valid_size += c_payload_size;
+ }
+
+ switch (htca_msg->header.msg_flags & LPCHTCA_PACKET_MASK) {
+ case LPCHTCA_START_PACKET: {
+ buffer->qca_msg.header_size = c_meta_size;
+ }
+ break;
+
+ case LPCHTCA_FULL_PACKET: {
+ buffer->qca_msg.header_size = c_meta_size;
+ buffer->qca_msg.data_size = buffer->valid_size;
+ }
+ break;
+
+ case LPCHTCA_END_PACKET: {
+ buffer->qca_msg.data_size = buffer->valid_size;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int msm_qca402_move_userbuff_to_(struct list_head *target_list,
+ struct msm_qca402_channel_list_t *ch_data)
+{
+ struct msm_qca402_buffer_list_t *c_entry;
+
+ c_entry = ch_data->current_entry;
+ if (c_entry) {
+ list_del_init(&c_entry->list);
+ list_add_tail(&c_entry->list, target_list);
+ }
+ ch_data->current_entry = NULL;
+ if (!list_empty(&ch_data->enqueued_list)) {
+ ch_data->current_entry = list_first_entry(
+ &ch_data->enqueued_list,
+ struct msm_qca402_buffer_list_t, list);
+ }
+ return 0;
+}
+
+static int msm_qca402_process_htca_message(
+ struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca402_workbuff_list_t *wb)
+{
+ int ret = 0;
+ int keep = 0;
+ __u8 pkt_flags;
+ struct msm_qca402_htca_message_t *htca_msg = &wb->htca_msg;
+ struct msm_qca402_channel_list_t *ch_data_cur;
+ struct msm_qca402_channel_list_t *ch_data = NULL;
+
+ pr_debug("wb %pK %d\n", htca_msg,
+ htca_msg->header.channel_id);
+ list_for_each_entry(ch_data_cur, &dev_data->channel_list, list) {
+ if (ch_data_cur->channel_id == htca_msg->header.channel_id) {
+ ch_data = ch_data_cur;
+ break;
+ }
+ }
+ if (!ch_data && !(htca_msg->header.msg_flags & LPCHTCA_ASYNC_MESSAGE)) {
+ /* No registered handler and not ASYNC message, drop packet */
+ goto return_wb;
+ } else if (!ch_data) {
+ /* if ASYNC message with no registered handler, add it */
+ ch_data = msm_qca402_init_channel(dev_data,
+ htca_msg->header.channel_id);
+ if (!ch_data)
+ return -EINVAL;
+ }
+ if (!ch_data->has_buff &&
+ !(htca_msg->header.msg_flags & LPCHTCA_FULL_PACKET)) {
+ /* data packet but no free enqueued buffers, drop packet */
+ /* indicate ERROR here */
+ goto return_wb;
+ } else if (ch_data->has_buff) {
+ if (!ch_data->current_entry) {
+ pr_debug("NO CURRENT ENTRY\n");
+ return -EINVAL;
+ }
+ /* data packet and there is enqueued buffer start filling it */
+ ret = msm_qca402_copy_data(htca_msg, ch_data->current_entry,
+ wb->size);
+ pkt_flags = htca_msg->header.msg_flags & LPCHTCA_PACKET_MASK;
+ if ((pkt_flags == LPCHTCA_UNSPEC_PACKET && ret == -ENOMEM) ||
+ (pkt_flags == LPCHTCA_FULL_PACKET) ||
+ (pkt_flags == LPCHTCA_END_PACKET) ||
+ (htca_msg->header.msg_flags &
+ LPCHTCA_END_TRANSMISSON)) {
+ struct msm_qca_event_type event;
+
+ event.cmd = MSM_QCA_EVENT_ENQ_BUF;
+ event.channel_id = ch_data->channel_id;
+ msm_qca402_move_userbuff_to_(&ch_data->ready_list,
+ ch_data);
+ msm_qca402_propagate_event(dev_data, &event, ch_data);
+ }
+ if (ret == -ENOMEM) {
+ ret = msm_qca402_copy_data(htca_msg,
+ ch_data->current_entry, wb->size);
+ }
+ } else {
+ struct msm_qca_event_type event;
+
+ /* control message, save for future receiving */
+ keep = 1;
+ ch_data->wbout = wb;
+ event.cmd = MSM_QCA_EVENT_RECV_MSG;
+ event.channel_id = ch_data->channel_id;
+ msm_qca402_propagate_event(dev_data, &event, ch_data);
+ }
+
+return_wb:
+ if (!keep)
+ list_add_tail(&wb->list, &dev_data->work_list);
+ return ret;
+}
+
+static struct msm_qca402_channel_list_t *msm_qca402_find_channel(
+ struct msm_qca402_dev_data_t *dev_data,
+ __u32 channel_id)
+{
+ struct msm_qca402_channel_list_t *ch_data;
+
+ list_for_each_entry(ch_data, &dev_data->channel_list, list) {
+ if (ch_data->channel_id == channel_id)
+ return ch_data;
+ }
+
+ return NULL;
+}
+
+static int msm_qca402_copy_header(struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca402_buffer_list_t *buff,
+ struct msm_qca_message_type *data)
+{
+ buff->wbb = msm_qca402_get_workbuff(dev_data);
+ if (!buff->wbb)
+ return -ENOMEM;
+
+ if (data->header_size <= QCA_MSG_PAYLOAD_SIZE) {
+ if (copy_from_user(
+ (void *)&buff->wbb->htca_msg.payload[0],
+ (void __user *)(uintptr_t)data->header,
+ data->header_size))
+ return -EFAULT;
+ buff->wbb->htca_msg.header.meta_size =
+ data->header_size;
+ } else
+ return -EINVAL;
+ return 0;
+}
+
+static struct msm_qca402_buffer_list_t *msm_qca402_deq_map_buff(
+ struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca402_channel_list_t *ch_data,
+ struct msm_qca_message_type *data)
+{
+ int ret;
+ struct msm_qca402_buffer_list_t *buff;
+
+ list_for_each_entry(buff, &ch_data->dequeued_list, list) {
+ if (buff->qca_msg.fd == data->fd) {
+ list_del_init(&buff->list);
+ if (!ch_data->has_buff) {
+ ret = msm_qca402_copy_header(dev_data, buff,
+ data);
+ if (ret < 0)
+ return NULL;
+ }
+ buff->qca_msg = *data;
+ return buff;
+ }
+ }
+ buff = kzalloc(sizeof(*buff), GFP_KERNEL);
+ if (!buff)
+ return NULL;
+ if (!ch_data->has_buff) {
+ ret = msm_qca402_copy_header(dev_data, buff, data);
+ if (ret < 0)
+ return NULL;
+ }
+ buff->qca_msg = *data;
+ if (data->is_ion_data) {
+ buff->ih = ion_import_dma_buf_fd(dev_data->ion_client,
+ data->fd);
+ buff->vaddr = ion_map_kernel(dev_data->ion_client, buff->ih);
+ }
+
+ return buff;
+}
+
+static unsigned int msm_qca402_recv_message(
+ struct msm_qca402_file_data_t *file,
+ struct msm_qca_message_type *data)
+{
+ struct msm_qca402_channel_list_t *channel;
+ struct msm_qca402_ready_list_t *rq_entry;
+ struct msm_qca402_buffer_list_t *buffer;
+ int ret = 0;
+
+ if (list_empty(&file->ready_ch_list))
+ return -ENODATA;
+ rq_entry = list_first_entry(&file->ready_ch_list,
+ struct msm_qca402_ready_list_t, list);
+ channel = rq_entry->ch_data;
+ list_del_init(&rq_entry->list);
+ kfree(rq_entry);
+
+ if (!list_empty(&channel->ready_list)) {
+ buffer = list_first_entry(&channel->ready_list,
+ struct msm_qca402_buffer_list_t, list);
+ *data = buffer->qca_msg;
+ if (channel->has_buff)
+ data->cmd = MSM_QCA_EVENT_ENQ_BUF;
+ else
+ data->cmd = MSM_QCA_EVENT_SEND_MSG;
+ list_del_init(&buffer->list);
+ buffer->valid_size = 0;
+ channel->ref_cnt--;
+ list_add_tail(&buffer->list, &channel->dequeued_list);
+ } else if (channel->wbout) {
+ data->channel_id = channel->channel_id;
+ data->is_ion_data = 0;
+ data->data_size = 0;
+ if (data->header_size >=
+ channel->wbout->htca_msg.header.meta_size) {
+ data->header_size =
+ channel->wbout->htca_msg.header.meta_size;
+ data->cmd = MSM_QCA_EVENT_RECV_MSG;
+ if (copy_to_user((void __user *)(uintptr_t)data->header,
+ channel->wbout->htca_msg.payload,
+ channel->wbout->htca_msg.header.meta_size)) {
+ list_add_tail(&channel->wbout->list,
+ &file->dev_data->work_list);
+ return -EFAULT;
+ }
+ channel->ref_cnt--;
+ list_add_tail(&channel->wbout->list,
+ &file->dev_data->work_list);
+ } else {
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static __u8 msm_qca402_fill_wb(
+ struct msm_qca402_buffer_list_t *buff,
+ struct msm_qca402_workbuff_list_t *wb)
+{
+ __u32 total_size = buff->qca_msg.header_size +
+ buff->qca_msg.data_size;
+ __u32 write_size = 0;
+ __u8 *ptr;
+
+ wb->htca_msg.header.msg_flags = 0;
+
+ wb->htca_msg.header.channel_id = buff->qca_msg.channel_id;
+
+ pr_debug("valid size %d total %d\n", buff->valid_size, total_size);
+ if (buff->valid_size == 0) {
+ if (total_size <= QCA_MSG_PAYLOAD_SIZE)
+ wb->htca_msg.header.msg_flags = LPCHTCA_FULL_PACKET;
+ else
+ wb->htca_msg.header.msg_flags = LPCHTCA_START_PACKET;
+ write_size = min(QCA_MSG_PAYLOAD_SIZE -
+ wb->htca_msg.header.meta_size,
+ buff->qca_msg.data_size);
+ } else {
+ wb->htca_msg.header.meta_size = 0;
+ if (total_size - buff->valid_size <= QCA_MSG_PAYLOAD_SIZE)
+ wb->htca_msg.header.msg_flags = LPCHTCA_END_PACKET;
+ else
+ wb->htca_msg.header.msg_flags = LPCHTCA_MID_PACKET;
+ write_size = min(QCA_MSG_PAYLOAD_SIZE,
+ buff->qca_msg.data_size - buff->valid_size);
+ }
+ if (buff->vaddr) {
+ ptr = (__u8 *)buff->vaddr + buff->valid_size;
+ memcpy(&wb->htca_msg.payload[wb->htca_msg.header.meta_size],
+ (void *)ptr, write_size);
+ } else {
+ ptr = (__u8 *)((uintptr_t)buff->qca_msg.buff_addr) +
+ buff->valid_size;
+ if (copy_from_user(
+ &wb->htca_msg.payload[wb->htca_msg.header.meta_size],
+ (void __user *)ptr, write_size))
+ return -EFAULT;
+ }
+ buff->valid_size += write_size;
+ wb->size = QCA_MSG_HEADER_SIZE + wb->htca_msg.header.meta_size +
+ write_size;
+ if (buff->qca_msg.last_data &&
+ ((wb->htca_msg.header.msg_flags == LPCHTCA_FULL_PACKET) ||
+ (wb->htca_msg.header.msg_flags == LPCHTCA_END_PACKET)))
+ wb->htca_msg.header.msg_flags |= LPCHTCA_END_TRANSMISSON;
+
+ pr_debug("flags %x\n", wb->htca_msg.header.msg_flags);
+ return wb->htca_msg.header.msg_flags;
+}
+static unsigned int msm_qca402_process_wb(
+ struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca402_channel_list_t *ch_data,
+ struct msm_qca402_buffer_list_t *buff,
+ struct msm_qca402_workbuff_list_t **wb)
+{
+ __u8 flags;
+ struct msm_qca_event_type event;
+
+ if (!*wb)
+ *wb = msm_qca402_get_workbuff(dev_data);
+
+ flags = msm_qca402_fill_wb(buff, *wb);
+
+ if ((flags & LPCHTCA_PACKET_MASK) == LPCHTCA_FULL_PACKET ||
+ (flags & LPCHTCA_PACKET_MASK) == LPCHTCA_END_PACKET) {
+ msm_qca402_move_userbuff_to_(&ch_data->ready_list,
+ ch_data);
+ event.cmd = MSM_QCA_EVENT_SEND_MSG;
+ event.channel_id = ch_data->channel_id;
+ msm_qca402_propagate_event(dev_data, &event, ch_data);
+ return 1;
+ }
+
+ return 0;
+}
+
+static unsigned int msm_qca402_send_htca_message(
+ struct msm_qca402_dev_data_t *dev_data,
+ struct msm_qca402_channel_list_t *ch_data)
+{
+ int status;
+ int ret;
+ struct msm_qca402_buffer_list_t *buff = ch_data->current_entry;
+ struct msm_qca402_workbuff_list_t *wb = NULL;
+
+
+ wb = ch_data->wbin;
+ if (!wb) {
+ if (!buff)
+ return -EINVAL;
+ wb = buff->wbb;
+ if (!wb) {
+ pr_err("Incorrect header error\n");
+ return -EINVAL;
+ }
+ ret = msm_qca402_process_wb(dev_data, ch_data, buff,
+ &wb);
+ if (!wb)
+ return -EINVAL;
+ buff->wbb = NULL;
+ }
+
+ pr_debug("send %d\n", wb->size);
+ dev_data->sending++;
+ status = htca_buffer_send(dev_data->htca_target, 0,
+ (void *)&wb->htca_msg.header, wb->size, wb);
+ ch_data->wbin = NULL;
+ if (status)
+ return -EINVAL;
+ if (((wb->htca_msg.header.msg_flags & LPCHTCA_PACKET_MASK) ==
+ LPCHTCA_FULL_PACKET) ||
+ ((wb->htca_msg.header.msg_flags & LPCHTCA_PACKET_MASK) ==
+ LPCHTCA_END_PACKET)) {
+ return 0;
+ }
+
+ if (!buff)
+ return -EINVAL;
+ ret = msm_qca402_process_wb(dev_data, ch_data, buff, &ch_data->wbin);
+
+ return -EAGAIN;
+}
+
+
+static unsigned int msm_qca402_poll(struct file *fp, poll_table *wait)
+{
+ struct msm_qca402_file_data_t *file_data =
+ (struct msm_qca402_file_data_t *)fp->private_data;
+ unsigned int mask = 0;
+
+ pr_debug("called %pK\n", &file_data->out_queue);
+ poll_wait(fp, &file_data->out_queue, wait);
+ if (!list_empty(&file_data->ready_ch_list))
+ mask = POLLIN | POLLRDNORM;
+ return mask;
+}
+
+static struct msm_qca_event_type *msm_qca402_alloc_get_evts(
+ struct msm_qca_event_list_type *evt_list)
+{
+ int len = sizeof(struct msm_qca_event_type) *
+ evt_list->num_events;
+ struct msm_qca_event_type *evts;
+
+ if (evt_list->num_events > QCA402_MAX_EVENTS_IN_MSG)
+ return NULL;
+ evts = kzalloc(len, GFP_KERNEL);
+ if (!evts)
+ return NULL;
+ if (copy_from_user((void *)evts,
+ (void __user *)(uintptr_t)evt_list->events,
+ len)) {
+ kfree(evts);
+ return NULL;
+ }
+ return evts;
+}
+
+static int msm_qca402_abort(struct msm_qca402_file_data_t *file_data,
+ int num_events, struct msm_qca_event_type *evts) {
+ return 0;
+}
+
+static int msm_qca402_flush(struct msm_qca402_file_data_t *file_data,
+ int num_events, struct msm_qca_event_type *evts) {
+ return 0;
+}
+
+static long msm_qca402_ioctl(struct file *file, unsigned int cmd,
+ void *arg)
+{
+ struct msm_qca402_file_data_t *file_data =
+ (struct msm_qca402_file_data_t *)file->private_data;
+ long ret = 0;
+
+ switch (cmd) {
+ case MSM_QCA402X_ENQUEUE_BUFFER: {
+ struct msm_qca_message_type *data =
+ (struct msm_qca_message_type *)arg;
+ struct msm_qca402_buffer_list_t *buff;
+ struct msm_qca402_channel_list_t *ch_data;
+
+ pr_debug("MSM_QCA402X_ENQUEUE_BUFFER\n");
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ ch_data = msm_qca402_find_channel(file_data->dev_data,
+ data->channel_id);
+ if (!ch_data) {
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ return -EINVAL;
+ }
+ ch_data->has_buff = 1;
+ buff = msm_qca402_deq_map_buff(file_data->dev_data, ch_data,
+ data);
+ if (!buff) {
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ return -ENOMEM;
+ }
+ list_add_tail(&buff->list, &ch_data->enqueued_list);
+ if (!ch_data->current_entry)
+ ch_data->current_entry = list_first_entry(
+ &ch_data->enqueued_list,
+ struct msm_qca402_buffer_list_t, list);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ }
+ break;
+ case MSM_QCA402X_SEND_MESSAGE: {
+ struct msm_qca_message_type *data =
+ (struct msm_qca_message_type *)arg;
+ struct msm_qca402_buffer_list_t *buff;
+ struct msm_qca402_channel_list_t *ch_data;
+ struct msm_qca402_ready_list_t *r_entry;
+
+ pr_debug("MSM_QCA402X_SEND_MESSAGE\n");
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ ch_data = msm_qca402_find_channel(file_data->dev_data,
+ data->channel_id);
+ if (!ch_data) {
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ return -EINVAL;
+ }
+ ch_data->has_buff = 0;
+ buff = msm_qca402_deq_map_buff(file_data->dev_data, ch_data,
+ data);
+ if (!buff) {
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ return -ENOMEM;
+ }
+ r_entry = kzalloc(sizeof(*r_entry), GFP_KERNEL);
+ if (!r_entry) {
+ list_add_tail(&buff->list, &ch_data->dequeued_list);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ return -ENOMEM;
+ }
+ ch_data->ref_cnt += 1;
+ list_add_tail(&buff->list, &ch_data->enqueued_list);
+ r_entry->ch_data = ch_data;
+ list_add_tail(&r_entry->list, &file_data->dev_data->in_list);
+ if (!ch_data->current_entry)
+ ch_data->current_entry = list_first_entry(
+ &ch_data->enqueued_list,
+ struct msm_qca402_buffer_list_t, list);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+
+ wake_up_interruptible(&file_data->dev_data->in_queue);
+ }
+ break;
+ case MSM_QCA402X_RECEIVE_MESSAGE: {
+ struct msm_qca_message_type *data =
+ (struct msm_qca_message_type *)arg;
+ pr_debug("MSM_QCA402X_RECEIVE_MESSAGE\n");
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ ret = msm_qca402_recv_message(file_data, data);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ }
+ break;
+ case MSM_QCA402X_REGISTER_EVENT: {
+ struct msm_qca_event_list_type *evt_list =
+ (struct msm_qca_event_list_type *)arg;
+ struct msm_qca_event_type *evts;
+
+ pr_debug("MSM_QCA402X_REGISTER_EVENT\n");
+
+ evts = msm_qca402_alloc_get_evts(evt_list);
+ if (!evts)
+ return -ENOMEM;
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ ret = msm_qca402_register_events(file_data,
+ evt_list->num_events,
+ evts);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ kfree(evts);
+ }
+ break;
+ case MSM_QCA402X_UNREGISTER_EVENT: {
+ struct msm_qca_event_list_type *evt_list =
+ (struct msm_qca_event_list_type *)arg;
+ struct msm_qca_event_type *evts;
+
+ pr_debug("MSM_QCA402X_UNREGISTER_EVENT\n");
+
+ evts = msm_qca402_alloc_get_evts(evt_list);
+ if (!evts)
+ return -ENOMEM;
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ msm_qca402_unregister_events(file_data, evt_list->num_events,
+ evts);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ kfree(evts);
+ }
+ break;
+ case MSM_QCA402X_FLUSH_BUFFERS: {
+ struct msm_qca_event_list_type *evt_list =
+ (struct msm_qca_event_list_type *)arg;
+ struct msm_qca_event_type *evts;
+
+ pr_debug("MSM_QCA402X_UNREGISTER_EVENT\n");
+
+ evts = msm_qca402_alloc_get_evts(evt_list);
+ if (!evts)
+ return -ENOMEM;
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ msm_qca402_flush(file_data, evt_list->num_events, evts);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ kfree(evts);
+ }
+ break;
+
+ case MSM_QCA402X_ABORT_MESSAGE: {
+ struct msm_qca_event_list_type *evt_list =
+ (struct msm_qca_event_list_type *)arg;
+ struct msm_qca_event_type *evts;
+
+ pr_debug("MSM_QCA402X_UNREGISTER_EVENT\n");
+
+ evts = msm_qca402_alloc_get_evts(evt_list);
+ if (!evts)
+ return -ENOMEM;
+ mutex_lock(&file_data->dev_data->dev_mutex);
+ msm_qca402_abort(file_data, evt_list->num_events, evts);
+ mutex_unlock(&file_data->dev_data->dev_mutex);
+ kfree(evts);
+ }
+ break;
+ default:
+ pr_debug("unhandled ioctl command: %d\n", cmd);
+ }
+ return ret;
+}
+static long msm_qca402_unlocked_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+ __u32 len = 0;
+
+ switch (cmd) {
+ case MSM_QCA402X_ENQUEUE_BUFFER:
+ case MSM_QCA402X_SEND_MESSAGE:
+ case MSM_QCA402X_RECEIVE_MESSAGE: {
+ struct msm_qca_message_type data;
+
+ len = sizeof(struct msm_qca_message_type);
+ if (copy_from_user(&data, (void __user *)arg, len))
+ return -EFAULT;
+ ret = msm_qca402_ioctl(file, cmd, (void *)&data);
+ if (copy_to_user((void __user *)arg, &data, len))
+ return -EFAULT;
+ }
+ break;
+ case MSM_QCA402X_FLUSH_BUFFERS:
+ case MSM_QCA402X_ABORT_MESSAGE:
+ case MSM_QCA402X_REGISTER_EVENT:
+ case MSM_QCA402X_UNREGISTER_EVENT: {
+ struct msm_qca_event_list_type data;
+
+ len = sizeof(struct msm_qca_event_list_type);
+ if (copy_from_user(&data, (void __user *)arg, len))
+ return -EFAULT;
+ ret = msm_qca402_ioctl(file, cmd, (void *)&data);
+ if (copy_to_user((void __user *)arg, &data, len))
+ return -EFAULT;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+#ifdef CONFIG_COMPAT
+struct msm_qca_message_type_32 {
+ __u64 header;
+ __u64 buff_addr;
+ __u32 header_size;
+ __u32 data_size;
+ int fd;
+ __u8 cmd;
+ __u8 channel_id;
+ __u8 is_ion_data;
+ __u8 last_data;
+};
+
+struct msm_qca_event_list_type_32 {
+ __u64 events;
+ __u32 num_events;
+};
+
+#define MSM_QCA402X_ENQUEUE_BUFFER_COMPAT \
+ _IOWR(0xdd, 1, struct msm_qca_message_type_32)
+#define MSM_QCA402X_SEND_MESSAGE_COMPAT \
+ _IOWR(0xdd, 2, struct msm_qca_message_type_32)
+#define MSM_QCA402X_RECEIVE_MESSAGE_COMPAT \
+ _IOWR(0xdd, 3, struct msm_qca_message_type_32)
+#define MSM_QCA402X_FLUSH_BUFFERS_COMPAT \
+ _IOWR(0xdd, 4, struct msm_qca_event_list_type_32)
+#define MSM_QCA402X_ABORT_MESSAGE_COMPAT \
+ _IOWR(0xdd, 5, struct msm_qca_event_list_type_32)
+#define MSM_QCA402X_REGISTER_EVENT_COMPAT \
+ _IOWR(0xdd, 6, struct msm_qca_event_list_type_32)
+#define MSM_QCA402X_UNREGISTER_EVENT_COMPAT \
+ _IOWR(0xdd, 7, struct msm_qca_event_list_type_32)
+
+static long msm_qca402_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ long ret = 0;
+
+ pr_debug("called\n");
+
+ switch (cmd) {
+ case MSM_QCA402X_ENQUEUE_BUFFER_COMPAT:
+ case MSM_QCA402X_SEND_MESSAGE_COMPAT:
+ case MSM_QCA402X_RECEIVE_MESSAGE_COMPAT: {
+ struct msm_qca_message_type_32 data32;
+ struct msm_qca_message_type data;
+ __u32 len = 0;
+
+ len = sizeof(struct msm_qca_message_type_32);
+ if (copy_from_user(&data32, (void __user *)arg, len))
+ return -EFAULT;
+ data.channel_id = data32.channel_id;
+ data.is_ion_data = data32.is_ion_data;
+ data.header_size = data32.header_size;
+ data.fd = data32.fd;
+ data.data_size = data32.data_size;
+ data.cmd = data32.cmd;
+ data.last_data = data32.last_data;
+ data.header = compat_ptr(data32.header);
+ data.buff_addr = compat_ptr(data32.buff_addr);
+
+ ret = msm_qca402_ioctl(file, cmd, (void *)&data);
+
+ data32.header_size = data.header_size;
+ data32.fd = data.fd;
+ data32.data_size = data.data_size;
+ if (copy_to_user((void __user *)arg, (void *)&data32, len))
+ return -EFAULT;
+ }
+ break;
+ case MSM_QCA402X_FLUSH_BUFFERS_COMPAT:
+ case MSM_QCA402X_ABORT_MESSAGE_COMPAT:
+ case MSM_QCA402X_REGISTER_EVENT_COMPAT:
+ case MSM_QCA402X_UNREGISTER_EVENT_COMPAT: {
+ struct msm_qca_event_list_type_32 data32;
+ struct msm_qca_event_list_type data;
+ int i;
+
+ len = sizeof(struct msm_qca_event_list_type_32);
+ if (copy_from_user(&data32, (void __user *)arg, len))
+ return -EFAULT;
+ data.num_events = data32.num_events;
+ for (i = 0; i < data.num_events; i++)
+ data.events[i] = data32.events[i];
+ ret = msm_qca402_ioctl(file, cmd, (void *)&data);
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+#endif
+
+static void msm_qca402_send_msg_hndl(void *target, __u8 epid,
+ __u8 eventid, struct htca_event_info *event_info,
+ void *context)
+{
+ struct msm_qca402_dev_data_t *dev_data =
+ (struct msm_qca402_dev_data_t *)context;
+ struct msm_qca402_workbuff_list_t *wb;
+
+ wb = (struct msm_qca402_workbuff_list_t *)event_info->cookie;
+ if ((!wb) || (!dev_data))
+ return;
+
+ wake_up_interruptible(&dev_data->in_queue);
+
+ mutex_lock(&dev_data->dev_mutex);
+ dev_data->sending--;
+ list_add_tail(&wb->list, &dev_data->work_list);
+ mutex_unlock(&dev_data->dev_mutex);
+
+}
+
+static void msm_qca402_recv_msg_hndl(void *target, __u8 epid,
+ __u8 eventid, struct htca_event_info *event_info,
+ void *context)
+{
+ struct msm_qca402_dev_data_t *dev_data =
+ (struct msm_qca402_dev_data_t *)context;
+ struct msm_qca402_workbuff_list_t *wb;
+
+ wb = (struct msm_qca402_workbuff_list_t *)event_info->cookie;
+ if ((!wb) || (!dev_data))
+ return;
+
+ mutex_lock(&dev_data->dev_mutex);
+ dev_data->receiving--;
+ wb->size = event_info->actual_length;
+ list_add_tail(&wb->list, &dev_data->recv_list);
+ mutex_unlock(&dev_data->dev_mutex);
+ if (dev_data->sending < dev_data->receiving)
+ wake_up_interruptible(&dev_data->in_queue);
+ wake_up_interruptible(&dev_data->recv_queue);
+}
+
+static void msm_qca402_data_avl_hndl(void *target, __u8 epid,
+ __u8 eventid, struct htca_event_info *event_info,
+ void *context)
+{
+ pr_debug("started\n");
+}
+
+static int msm_qca402_htca_recv_thread(void *hdl)
+{
+
+ int wait;
+ struct msm_qca402_dev_data_t *dev_data =
+ (struct msm_qca402_dev_data_t *)hdl;
+ struct msm_qca402_workbuff_list_t *wb_prev, *wb_curr;
+ int status;
+
+ pr_debug("start waiting\n");
+
+ while (!kthread_should_stop()) {
+ wait = wait_event_interruptible(dev_data->recv_queue,
+ !list_empty(&dev_data->recv_list) ||
+ kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ pr_debug("rcvd\n");
+ mutex_lock(&dev_data->dev_mutex);
+ wb_prev = list_first_entry(&dev_data->recv_list,
+ struct msm_qca402_workbuff_list_t, list);
+ list_del_init(&wb_prev->list);
+
+ wb_curr = msm_qca402_get_workbuff(dev_data);
+ status = htca_buffer_receive(dev_data->htca_target, 0,
+ (void *)&wb_curr->htca_msg, HTCA_MAX_BUFF_SIZE,
+ wb_curr);
+ dev_data->receiving++;
+
+ if (status)
+ pr_err("Receive error\n");
+
+ msm_qca402_process_htca_message(dev_data, wb_prev);
+ mutex_unlock(&dev_data->dev_mutex);
+
+ }
+
+ return 0;
+}
+
+
+static int msm_qca402_htca_user_thread(void *hdl)
+{
+ int ret, wait, i;
+ struct msm_qca402_dev_data_t *dev_data =
+ (struct msm_qca402_dev_data_t *)hdl;
+ struct msm_qca402_ready_list_t *r_entry;
+ struct msm_qca402_channel_list_t *ch_data = NULL;
+ struct msm_qca402_workbuff_list_t *wb;
+ int status;
+
+ pr_debug("started EP\n");
+ ret = htca_start(dev_data->htca_target);
+ WARN_ON(ret);
+ htca_event_reg(dev_data->htca_target, 0, HTCA_EVENT_BUFFER_SENT,
+ msm_qca402_send_msg_hndl, dev_data);
+ htca_event_reg(dev_data->htca_target, 0, HTCA_EVENT_BUFFER_RECEIVED,
+ msm_qca402_recv_msg_hndl, dev_data);
+ htca_event_reg(dev_data->htca_target, 0, HTCA_EVENT_DATA_AVAILABLE,
+ msm_qca402_data_avl_hndl, dev_data);
+ pr_debug("start waiting\n");
+
+
+ for (i = 0; i < QCA402_START_ENQ_BUFFS; i++) {
+ wb = msm_qca402_get_workbuff(dev_data);
+ status = htca_buffer_receive(dev_data->htca_target, 0,
+ (void *)&wb->htca_msg, HTCA_MAX_BUFF_SIZE, wb);
+ }
+
+ dev_data->receiving += QCA402_START_ENQ_BUFFS;
+
+ while (!kthread_should_stop()) {
+ wait = wait_event_interruptible(dev_data->in_queue,
+ ((!list_empty(&dev_data->in_list) || ch_data) &&
+ (dev_data->sending < dev_data->receiving)) ||
+ kthread_should_stop());
+
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&dev_data->dev_mutex);
+ if (!ch_data) {
+ r_entry = list_first_entry(&dev_data->in_list,
+ struct msm_qca402_ready_list_t, list);
+
+ ch_data = r_entry->ch_data;
+ list_del_init(&r_entry->list);
+ kfree(r_entry);
+ }
+ ret = msm_qca402_send_htca_message(dev_data, ch_data);
+ if (ret == -EINVAL) {
+ pr_err("Error during message send\n");
+ ch_data = NULL;
+ } else if (ret == 0) {
+ pr_debug("Message sent\n");
+ ch_data->ref_cnt--;
+ ch_data = NULL;
+ }
+ mutex_unlock(&dev_data->dev_mutex);
+ }
+
+ return 0;
+}
+
+static const struct file_operations msm_qca402_ops = {
+ .open = msm_qca402_open,
+ .poll = msm_qca402_poll,
+ .release = msm_qca402_release,
+ .unlocked_ioctl = msm_qca402_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = msm_qca402_compat_ioctl,
+#endif
+};
+
+static int msm_qca402_create_device(struct msm_qca402_dev_data_t **dv,
+ int minor)
+{
+ int ret;
+ char name[20];
+
+ *dv = kzalloc(sizeof(**dv), GFP_KERNEL);
+ if (!*dv)
+ return -ENOMEM;
+ snprintf(name, sizeof(name), "%s%d", DEVICE_NAME, minor);
+ pr_debug("called for device %s\n", name);
+ (*dv)->dev = device_create(msm_qca402_class, NULL,
+ MKDEV(msm_qca402_major, minor), NULL, name);
+ if (IS_ERR((*dv)->dev)) {
+ ret = PTR_ERR((*dv)->dev);
+ kfree(*dv);
+ *dv = NULL;
+ return ret;
+ }
+ cdev_init(&(*dv)->cdev, &msm_qca402_ops);
+ ret = cdev_add(&(*dv)->cdev, MKDEV(msm_qca402_major, minor), 1);
+ if (ret < 0) {
+ device_unregister((*dv)->dev);
+ kfree(*dv);
+ *dv = NULL;
+ }
+
+ return ret;
+}
+
+static void msm_qca402_destroy_device(struct msm_qca402_dev_data_t *dv)
+{
+ pr_debug("called\n");
+ cdev_del(&dv->cdev);
+ device_unregister(dv->dev);
+ kfree(dv);
+}
+
+static void msm_qca402_trgt_avail_hndl(void *target, __u8 epid,
+ __u8 eventid, struct htca_event_info *event_info,
+ void *context)
+{
+ struct msm_qca402_dev_data_t *dev_data;
+ dev_t devid;
+ int ret;
+ int i;
+
+ pr_debug("started\n");
+ /* get the actual number from dts */
+ ret = alloc_chrdev_region(&devid, 0, MAX_DEVICE_NUM, DEVICE_NAME);
+ if (ret < 0)
+ goto register_error;
+ msm_qca402_major = MAJOR(devid);
+ msm_qca402_class = class_create(THIS_MODULE, DEVICE_CLASS);
+ if (IS_ERR(msm_qca402_class)) {
+ ret = PTR_ERR(msm_qca402_class);
+ goto class_error;
+ }
+ for (i = 0; i < MAX_DEVICE_NUM; i++) {
+ ret = msm_qca402_create_device(&msm_qca402_device[i].dev,
+ i + MINOR(devid));
+ if (ret < 0)
+ goto device_error;
+ dev_data = msm_qca402_device[i].dev;
+ dev_data->dev_idx = i;
+ dev_data->ion_client =
+ msm_ion_client_create("qca_ion_client");
+ if (IS_ERR_OR_NULL(dev_data->ion_client)) {
+ msm_qca402_destroy_device(dev_data);
+ msm_qca402_device[i].dev = NULL;
+ goto device_error;
+ }
+
+ init_waitqueue_head(&dev_data->in_queue);
+ init_waitqueue_head(&dev_data->recv_queue);
+
+ pr_debug("ion done\n");
+ INIT_LIST_HEAD(&dev_data->file_list);
+ INIT_LIST_HEAD(&dev_data->channel_list);
+ INIT_LIST_HEAD(&dev_data->work_list);
+ INIT_LIST_HEAD(&dev_data->recv_list);
+ INIT_LIST_HEAD(&dev_data->in_list);
+ ret = msm_qca402_alloc_add_workbuffs(dev_data,
+ QCA402_MIN_NUM_WORKBUFS);
+ if (ret < 0)
+ goto device_error;
+ pr_debug("lists done\n");
+ mutex_init(&dev_data->dev_mutex);
+ spin_lock_init(&dev_data->lock);
+ pr_debug("device[%d] %pK\n", i, dev_data);
+ dev_data->htca_target = target;
+ }
+
+ for (i = 0; i < MAX_DEVICE_NUM; i++) {
+ msm_qca402_device[i].user_task = kthread_create(
+ msm_qca402_htca_user_thread, dev_data, "qca402_user");
+ msm_qca402_device[i].recv_task = kthread_create(
+ msm_qca402_htca_recv_thread, dev_data, "qca402_recv");
+ wake_up_process(msm_qca402_device[i].user_task);
+ wake_up_process(msm_qca402_device[i].recv_task);
+ }
+ return;
+
+device_error:
+ for (--i; i >= 0; i--) {
+ if (msm_qca402_device[i].dev) {
+ mutex_destroy(&msm_qca402_device[i].dev->dev_mutex);
+ msm_qca402_free_workbuffs(msm_qca402_device[i].dev);
+ ion_client_destroy(
+ msm_qca402_device[i].dev->ion_client);
+ msm_qca402_destroy_device(msm_qca402_device[i].dev);
+ msm_qca402_device[i].dev = NULL;
+ }
+ }
+ class_destroy(msm_qca402_class);
+class_error:
+ unregister_chrdev(msm_qca402_major, DEVICE_NAME);
+register_error:
+ pr_err("error: %d\n", ret);
+}
+
+static void msm_qca402_trgt_unavail_hndl(void *target, __u8 epid,
+ __u8 eventid, struct htca_event_info *event_info,
+ void *context)
+{
+ int i;
+
+ for (i = 0; i < MAX_DEVICE_NUM; i++) {
+ if (msm_qca402_device[i].dev) {
+ kthread_stop(msm_qca402_device[i].user_task);
+ kthread_stop(msm_qca402_device[i].recv_task);
+ htca_stop(msm_qca402_device[i].dev->htca_target);
+ mutex_destroy(&msm_qca402_device[i].dev->dev_mutex);
+ msm_qca402_free_workbuffs(msm_qca402_device[i].dev);
+ ion_client_destroy(
+ msm_qca402_device[i].dev->ion_client);
+ msm_qca402_destroy_device(msm_qca402_device[i].dev);
+ msm_qca402_device[i].dev = NULL;
+ }
+ }
+ class_unregister(msm_qca402_class);
+ class_destroy(msm_qca402_class);
+ unregister_chrdev(msm_qca402_major, DEVICE_NAME);
+}
+
+static int msm_qca402_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match_dev;
+ int status;
+
+ if (pdev->dev.of_node) {
+ pr_debug("device found\n");
+ match_dev = of_match_device(pdev->dev.driver->of_match_table,
+ &pdev->dev);
+ }
+
+ pr_debug("called\n");
+ if (htca_init())
+ return -EINVAL;
+
+ pr_debug("register\n");
+ status = htca_event_reg(NULL, 0, HTCA_EVENT_TARGET_AVAILABLE,
+ msm_qca402_trgt_avail_hndl, NULL);
+ if (status != HTCA_OK)
+ return -EINVAL;
+ status = htca_event_reg(NULL, 0, HTCA_EVENT_TARGET_UNAVAILABLE,
+ msm_qca402_trgt_unavail_hndl, NULL);
+ if (status != HTCA_OK)
+ return -EINVAL;
+ pr_debug("register_end\n");
+
+ return 0;
+}
+
+static int msm_qca402_remove(struct platform_device *pdev)
+{
+ int i, stop_flag = 0;
+
+ for (i = 0; i < MAX_DEVICE_NUM; i++) {
+ if (msm_qca402_device[i].dev) {
+ stop_flag = 1;
+ kthread_stop(msm_qca402_device[i].user_task);
+ kthread_stop(msm_qca402_device[i].recv_task);
+ htca_stop(msm_qca402_device[i].dev->htca_target);
+ mutex_destroy(&msm_qca402_device[i].dev->dev_mutex);
+ msm_qca402_free_workbuffs(msm_qca402_device[i].dev);
+ ion_client_destroy(
+ msm_qca402_device[i].dev->ion_client);
+ msm_qca402_destroy_device(msm_qca402_device[i].dev);
+ msm_qca402_device[i].dev = NULL;
+ }
+ }
+ if (stop_flag) {
+ class_unregister(msm_qca402_class);
+ class_destroy(msm_qca402_class);
+ unregister_chrdev(msm_qca402_major, DEVICE_NAME);
+ }
+ htca_shutdown();
+ return 0;
+}
+
+static struct platform_driver msm_qca402_driver = {
+ .probe = msm_qca402_probe,
+ .remove = msm_qca402_remove,
+ .driver = {
+ .name = "msm_qca402",
+ .owner = THIS_MODULE,
+ .of_match_table = msm_qca402_dt_match,
+ },
+};
+
+static int __init msm_qca402_init(void)
+{
+ platform_driver_register(&msm_qca402_driver);
+ return 0;
+}
+
+static void __exit msm_qca402_exit(void)
+{
+}
+
+module_init(msm_qca402_init);
+module_exit(msm_qca402_exit);
+
+MODULE_DESCRIPTION("Driver for QCA402x HTCA High level communication");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/qca402/msm_qca402.h b/drivers/media/platform/msm/qca402/msm_qca402.h
new file mode 100644
index 0000000..518ded7
--- /dev/null
+++ b/drivers/media/platform/msm/qca402/msm_qca402.h
@@ -0,0 +1,142 @@
+/* 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 _QCA402_H_
+#define _QCA402_H_
+#include <linux/types.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include <linux/msm_ion.h>
+#include "../drivers/net/wireless/qca402x/htca_mbox/htca.h"
+
+/* current htca buffer limitation */
+#define HTCA_MAX_BUFF_SIZE (2048)
+enum lpchtca_packet_type {
+ /* the below three types are for piece of data (i.e. frame) with
+ * known size
+ */
+ LPCHTCA_START_PACKET = 1,
+ LPCHTCA_MID_PACKET,
+ LPCHTCA_END_PACKET,
+
+ /* For piece of data (i.e. frame) with known size that fits in one
+ * packet
+ */
+ LPCHTCA_FULL_PACKET,
+
+ /* If data size is unknown/continuous - this case assumes no header or
+ * user space to take care of headers
+ */
+ LPCHTCA_UNSPEC_PACKET,
+
+};
+
+/* Message Flags */
+#define LPCHTCA_ASYNC_MESSAGE (1 << 7)
+/* this bit is added to one of the above to indicate the packet is last that
+ * will be received for this stream
+ */
+#define LPCHTCA_END_TRANSMISSON (1 << 6)
+#define LPCHTCA_PACKET_MASK ((1 << 6) - 1)
+#define QCA402_MIN_NUM_WORKBUFS (4)
+
+struct msm_qca402_file_data_t;
+
+struct __packed msm_qca402_htca_header_t {
+ __u8 channel_id;
+ __u8 msg_flags;
+ __u16 meta_size;
+};
+
+#define QCA_MSG_HEADER_SIZE (sizeof(struct msm_qca402_htca_header_t))
+#define QCA_MSG_PAYLOAD_SIZE (HTCA_MAX_BUFF_SIZE - QCA_MSG_HEADER_SIZE -\
+ HTCA_HEADER_LEN_MAX)
+
+struct __packed msm_qca402_htca_message_t {
+ __u8 htca_private[HTCA_HEADER_LEN_MAX];
+ struct msm_qca402_htca_header_t header;
+ __u8 payload[QCA_MSG_PAYLOAD_SIZE];
+};
+
+struct file_data_list_t {
+ struct msm_qca402_file_data_t *file_data;
+ struct list_head list;
+};
+
+struct msm_qca402_workbuff_list_t {
+ struct msm_qca402_htca_message_t htca_msg;
+ __u32 size;
+ struct list_head list;
+};
+
+struct msm_qca402_buffer_list_t {
+ struct msm_qca_message_type qca_msg;
+ struct msm_qca402_workbuff_list_t *wbb;
+ void *vaddr;
+ struct ion_handle *ih;
+ __u32 valid_size;
+ struct list_head list;
+};
+
+struct msm_qca402_evt_list_t {
+ __u8 channel_id;
+ __u8 cmd;
+ struct list_head list;
+};
+
+struct msm_qca402_channel_list_t {
+ struct msm_qca402_buffer_list_t *current_entry;
+ struct msm_qca402_workbuff_list_t *wbin;
+ struct msm_qca402_workbuff_list_t *wbout;
+ struct list_head enqueued_list;
+ struct list_head ready_list;
+ struct list_head dequeued_list;
+ __u32 ref_cnt;
+ __u8 channel_id;
+ __u8 has_buff;
+ struct list_head list;
+};
+
+struct msm_qca402_ready_list_t {
+ struct msm_qca402_channel_list_t *ch_data;
+ __u8 cmd;
+ struct list_head list;
+};
+
+struct msm_qca402_dev_data_t {
+ struct cdev cdev;
+ struct device *dev;
+ struct ion_client *ion_client;
+ __u8 endPointId;
+ void *htca_target;
+ struct list_head file_list;
+ struct list_head channel_list;
+ struct mutex dev_mutex;
+ struct list_head work_list;
+ wait_queue_head_t in_queue;
+ struct list_head in_list;
+ wait_queue_head_t recv_queue;
+ struct list_head recv_list;
+ spinlock_t lock;
+ __u8 dev_idx;
+ __u8 sending;
+ __u8 receiving;
+};
+
+struct msm_qca402_file_data_t {
+ struct msm_qca402_dev_data_t *dev_data;
+ wait_queue_head_t out_queue;
+ struct mutex file_mutex;
+ struct list_head evt_list;
+ struct list_head ready_ch_list;
+};
+
+#endif /* _QCA402_H_ */
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 ce50dcd..ca3b010 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 @@
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 a665978..c15a2e9 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 @@
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_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
index f80d9b0..f975409 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c
@@ -120,7 +120,7 @@
},
{
.key = "qcom,max-secure-instances",
- .value = 5,
+ .value = 2,
},
{
.key = "qcom,max-hw-load",
@@ -154,6 +154,10 @@
.key = "qcom,debug-timeout",
.value = 0,
},
+ {
+ .key = "qcom,enable-idle-indicator",
+ .value = 1,
+ },
};
static struct msm_vidc_common_data sdm670_common_data_v0[] = {
@@ -205,6 +209,10 @@
.key = "qcom,hw-resp-timeout",
.value = 1000,
},
+ {
+ .key = "qcom,enable-idle-indicator",
+ .value = 1,
+ },
};
static struct msm_vidc_common_data sdm670_common_data_v1[] = {
@@ -256,6 +264,10 @@
.key = "qcom,hw-resp-timeout",
.value = 1000,
},
+ {
+ .key = "qcom,enable-idle-indicator",
+ .value = 1,
+ },
};
static struct msm_vidc_efuse_data sdm670_efuse_data[] = {
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 79ed798..6975c13 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.c
@@ -2747,7 +2747,7 @@
{
int rc = 0;
u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
- int count = 0;
+ int pc_count = 0, idle_count = 0;
const int max_tries = 10;
struct venus_hfi_device *device = list_first_entry(
&hal_ctxt.dev_head, struct venus_hfi_device, list);
@@ -2796,8 +2796,16 @@
wfi_status);
goto skip_power_off;
}
- if (device->res->sys_idle_indicator &&
- !(idle_status & BIT(30))) {
+ while (device->res->sys_idle_indicator &&
+ idle_count < max_tries) {
+ if (idle_status & BIT(30))
+ break;
+ usleep_range(50, 100);
+ idle_status = __read_register(device,
+ VIDC_CPU_CS_SCIACMDARG0);
+ idle_count++;
+ }
+ if (idle_count == max_tries) {
dprintk(VIDC_WARN,
"Skipping PC as idle_status (%#x) bit not set\n",
idle_status);
@@ -2810,7 +2818,7 @@
goto skip_power_off;
}
- while (count < max_tries) {
+ while (pc_count < max_tries) {
wfi_status = __read_register(device,
VIDC_WRAPPER_CPU_STATUS);
pc_ready = __read_register(device,
@@ -2819,10 +2827,10 @@
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY))
break;
usleep_range(150, 250);
- count++;
+ pc_count++;
}
- if (count == max_tries) {
+ if (pc_count == max_tries) {
dprintk(VIDC_ERR,
"Skip PC. Core is not in right state (%#x, %#x)\n",
wfi_status, pc_ready);
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 921cf1e..69156aff 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -864,6 +864,9 @@
.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 d4e93f1..8618eba 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -870,7 +870,7 @@
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 70c646b..19ac8bc 100644
--- a/drivers/mfd/intel-lpss.c
+++ b/drivers/mfd/intel-lpss.c
@@ -275,11 +275,11 @@
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 bf87ed2..d0b5a0e 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -189,6 +189,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*/
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 @@
/* 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 @@
} 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 @@
__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 @@
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 @@
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 @@
/* 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 @@
} 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 @@
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 @@
mutex_lock(&app_access_lock);
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
}
+ ptr_app->check_block--;
}
}
@@ -2466,6 +2470,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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_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 @@
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 @@
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 1e688bf..fe90b7e 100644
--- a/drivers/misc/vmw_balloon.c
+++ b/drivers/misc/vmw_balloon.c
@@ -576,15 +576,9 @@
}
}
- 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 bool vmballoon_init_batching(struct vmballoon *b)
{
- b->page = alloc_page(VMW_PAGE_ALLOC_NOSLEEP);
- if (!b->page)
+ struct page *page;
+
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page)
return false;
- b->batch_page = vmap(&b->page, 1, VM_MAP, PAGE_KERNEL);
- if (!b->batch_page) {
- __free_page(b->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 f78b659..a1488fe 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -3994,6 +3994,7 @@
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 7d24213..1119292 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -5239,19 +5239,50 @@
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 @@
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 107c05b..de35a2a 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 @@
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 @@
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 @@
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 @@
unsigned long int adr;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
+ int retry_cnt = 0;
adr = cfi->addr_unlock1;
@@ -2254,6 +2255,7 @@
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 @@
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 @@
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 @@
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
+ int retry_cnt = 0;
adr += chip->start;
@@ -2344,6 +2351,7 @@
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 @@
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 @@
xip_enable(map, chip, adr);
printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
+ ret = -EIO;
break;
}
@@ -2396,12 +2405,15 @@
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 @@
struct ppb_lock {
struct flchip *chip;
- loff_t offset;
+ unsigned long adr;
int locked;
};
@@ -2549,8 +2561,9 @@
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 @@
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 @@
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 @@
* 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 @@
i++;
if (adr >> cfi->chipshift) {
+ if (offset >= (ofs + len))
+ break;
adr = 0;
chipnum++;
@@ -2710,7 +2725,7 @@
*/
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 0c84ee8..5c44eb5 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 @@
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 68902b8..541c179 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -1137,6 +1137,9 @@
*/
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 388e46b..d0884bd 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -490,6 +490,82 @@
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 @@
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
@@ -931,6 +1013,12 @@
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 668b462..23a6986 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1505,6 +1505,7 @@
}
dbg_wl("background thread \"%s\" is killed", ubi->bgt_name);
+ ubi->thread_enabled = 0;
return 0;
}
@@ -1514,9 +1515,6 @@
*/
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 1a139d0..f5fcc08 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -384,20 +384,15 @@
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 @@
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 @@
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 577e57c..473da3b 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1114,6 +1114,7 @@
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 c26debc..7152595 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1516,6 +1516,18 @@
.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",
.vlans = 4096,
@@ -1825,6 +1837,7 @@
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 477a16b..6f47ff1 100644
--- a/drivers/net/dsa/b53/b53_mdio.c
+++ b/drivers/net/dsa/b53/b53_mdio.c
@@ -285,6 +285,7 @@
#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 @@
*/
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 @@
{ .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 f192a67..68ab20b 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -47,6 +47,7 @@
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 1fb8010..912900d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c
@@ -594,7 +594,7 @@
* 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 dda63b2..99f593b 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -2541,11 +2541,11 @@
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 @@
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 bcbb80f..1a92cd7 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -142,16 +142,17 @@
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 (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 (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)
+ 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 @@
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 474ff36..71578d4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -392,11 +392,11 @@
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 d50350c..22a5916e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -4187,10 +4187,6 @@
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 @@
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 612c7a4..2382154 100644
--- a/drivers/net/ethernet/natsemi/sonic.c
+++ b/drivers/net/ethernet/natsemi/sonic.c
@@ -71,7 +71,7 @@
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 457e304..f1956c4 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 49bbc68..9a7dca2 100644
--- a/drivers/net/phy/bcm-cygnus.c
+++ b/drivers/net/phy/bcm-cygnus.c
@@ -61,17 +61,17 @@
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 b2091c8..ce16b26 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 <linux/brcmphy.h>
#include <linux/phy.h>
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 9636da0..caff474 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 2032a6d..707190d 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -801,9 +801,6 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 3696368..f9ec009 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1004,7 +1004,8 @@
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 8a6675d..f9f69d5 100644
--- a/drivers/net/usb/ax88179_178a.c
+++ b/drivers/net/usb/ax88179_178a.c
@@ -1435,7 +1435,8 @@
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 3a98f37..4c8baba 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_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 feb61ea..3086cae 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1124,7 +1124,7 @@
* 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 @@
/* 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 1d56c73..85bc0ca 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -808,6 +808,7 @@
{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 bb2270b..c915ded 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -114,3 +114,5 @@
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 917a876..6cf62b66 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -32,3 +32,4 @@
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 0b37af6..c18cea7 100644
--- a/drivers/net/wireless/cnss/Kconfig
+++ b/drivers/net/wireless/cnss/Kconfig
@@ -61,6 +61,19 @@
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 8797e68..b99a813 100644
--- a/drivers/net/wireless/cnss/cnss_pci.c
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -234,8 +234,11 @@
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 @@
{
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 @@
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 @@
if (ret) {
pr_err("%s: SMMU init failed, err = %d\n",
__func__, ret);
- goto smmu_init_fail;
}
}
@@ -1714,7 +1738,6 @@
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 @@
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 @@
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 @@
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 @@
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/pci.c b/drivers/net/wireless/cnss2/pci.c
index 161e68e..c1fc8ba 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -1357,6 +1357,61 @@
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 @@
&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 79f66ac..c8de4d7 100644
--- a/drivers/net/wireless/cnss2/pci.h
+++ b/drivers/net/wireless/cnss2/pci.h
@@ -63,6 +63,8 @@
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 3fbad1f..2c375bb 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 @@
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 @@
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 @@
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 @@
}
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 fe32de2..e7b8730 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1509,14 +1509,13 @@
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 @@
* 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 0000000..bae2a49
--- /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 0000000..c052f73
--- /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 0000000..50873a8
--- /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 0000000..56d3b95
--- /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 <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#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 0000000..924d2e4
--- /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 0000000..8b4c11e
--- /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 0000000..c325c06
--- /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 0000000..ce2e0eb
--- /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 0000000..fbf3549
--- /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 <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#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 0000000..c7f8e953
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..d034277
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..b1c7c6b
--- /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 0000000..0486f59
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..0d4eae8
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..ebccf72
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..6598cba
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/sched.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..4cf137c
--- /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 <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+
+#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 0000000..81ce632
--- /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 ec2ea56..fdbd359 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/rf.c
@@ -304,9 +304,6 @@
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 8311a93..c1a65ce 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -505,14 +505,18 @@
{
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 642ee00..a55d112 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1126,11 +1126,11 @@
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 @@
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 @@
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 f791d46..2caed28 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -166,11 +166,21 @@
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 @@
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 3a04492..64b40a1 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -743,9 +743,6 @@
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 @@
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 26b87dc..0bc530c 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -110,7 +110,6 @@
struct mutex lock;
u64 cap;
- u64 serial;
u32 cc;
u32 csts;
@@ -151,6 +150,7 @@
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 53c83d6..90b5a89 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -155,20 +155,20 @@
/* 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 @@
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 37d70b5..2bba848 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -134,7 +134,7 @@
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 7d32fa33..6620b10 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -297,7 +297,7 @@
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 d08dfc8..8d811ea 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -673,7 +673,7 @@
return handled;
}
-void pcie_enable_notification(struct controller *ctrl)
+static void pcie_enable_notification(struct controller *ctrl)
{
u16 cmd, mask;
@@ -711,6 +711,17 @@
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 b55f9179..a05d143 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -4225,11 +4225,29 @@
* 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 @@
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/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index f51ab9e..6909bd1 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -975,6 +975,59 @@
}
}
+static bool is_gpio_tlmm_dc(struct irq_data *d, u32 type)
+{
+ const struct msm_pingroup *g;
+ unsigned long flags;
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct msm_pinctrl *pctrl;
+ bool ret = false;
+ unsigned int polarity = 0, offset, val;
+ int i;
+
+ if (!gc)
+ return false;
+
+ pctrl = gpiochip_get_data(gc);
+
+ for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
+ struct msm_dir_conn *dir_conn = (struct msm_dir_conn *)
+ &pctrl->soc->dir_conn[i];
+
+ if (dir_conn->gpio == d->hwirq && dir_conn->tlmm_dc) {
+ ret = true;
+ offset = pctrl->soc->dir_conn_irq_base -
+ dir_conn->hwirq;
+ break;
+ }
+ }
+
+ if (!ret)
+ return ret;
+
+ if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_LEVEL_LOW))
+ return ret;
+
+ /*
+ * Since the default polarity is set to 0, change it to 1 for
+ * Rising edge and active high interrupt type such that the line
+ * is not inverted.
+ */
+ polarity = 1;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ g = &pctrl->soc->groups[d->hwirq];
+
+ val = readl_relaxed(pctrl->regs + g->dir_conn_reg + (offset * 4));
+ val |= polarity << 8;
+
+ writel_relaxed(val, pctrl->regs + g->dir_conn_reg + (offset * 4));
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return ret;
+}
+
static bool is_gpio_dual_edge(struct irq_data *d, irq_hw_number_t *dir_conn_irq)
{
struct irq_desc *desc = irq_data_to_desc(d);
@@ -1283,12 +1336,12 @@
if (!parent_data)
return 0;
- if (type == IRQ_TYPE_EDGE_BOTH) {
+ if (type == IRQ_TYPE_EDGE_BOTH)
add_dirconn_tlmm(d, irq);
- } else {
- if (is_gpio_dual_edge(d, &irq))
- remove_dirconn_tlmm(d, irq);
- }
+ else if (is_gpio_dual_edge(d, &irq))
+ remove_dirconn_tlmm(d, irq);
+ else if (is_gpio_tlmm_dc(d, type))
+ type = IRQ_TYPE_EDGE_RISING;
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
irq_set_handler_locked(d, handle_level_irq);
@@ -1366,9 +1419,28 @@
for (i = 0; i < pctrl->soc->n_dir_conns; i++) {
const struct msm_dir_conn *dirconn = &pctrl->soc->dir_conn[i];
+ struct irq_data *d;
request_dc_interrupt(pctrl->chip.irqdomain, pdc_domain,
dirconn->hwirq, dirconn->gpio);
+
+ if (!dirconn->gpio)
+ continue;
+
+ if (!dirconn->tlmm_dc)
+ continue;
+
+ /*
+ * If the gpio is routed through TLMM direct connect interrupts,
+ * program the TLMM registers for this setup.
+ */
+ d = irq_get_irq_data(irq_find_mapping(pctrl->chip.irqdomain,
+ dirconn->gpio));
+ if (!d)
+ continue;
+
+ msm_dirconn_cfg_reg(d, pctrl->soc->dir_conn_irq_base
+ - (u32)dirconn->hwirq);
}
for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
@@ -1383,7 +1455,7 @@
* Statically choose the GPIOs for mapping to PDC. Dynamic mux mapping
* is very difficult.
*/
- for (i = 0; i < pctrl->soc->n_pdc_mux_out; i++) {
+ for (i = 0; i < pctrl->soc->n_gpio_mux_in; i++) {
unsigned int irq;
struct irq_data *d;
struct msm_gpio_mux_input *gpio_in =
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index b8185ae..d0a0766 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -128,10 +128,12 @@
* struct msm_dir_conn - Direct GPIO connect configuration
* @gpio: GPIO pin number
* @hwirq: The GIC interrupt that the pin is connected to
+ * @tlmm_dc: indicates if the GPIO is routed to GIC directly
*/
struct msm_dir_conn {
unsigned int gpio;
irq_hw_number_t hwirq;
+ bool tlmm_dc;
};
/**
diff --git a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
index c5f1307..c3081cb 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdxpoorwills.c
@@ -50,6 +50,7 @@
.intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
.intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
.intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .dir_conn_reg = REG_BASE + 0xab000,\
.mux_bit = 2, \
.pull_bit = 0, \
.drv_bit = 6, \
@@ -64,6 +65,7 @@
.intr_polarity_bit = 1, \
.intr_detection_bit = 2, \
.intr_detection_width = 2, \
+ .dir_conn_en_bit = 8, \
}
#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
@@ -1151,7 +1153,7 @@
{42, 80},
{43, 82},
{44, 83},
- {45, 84},
+ {45, 84, 1},
{46, 86},
{47, 87},
{48, 88},
@@ -1196,6 +1198,17 @@
{0, 195},
};
+static struct msm_dir_conn sdxpoorwills_dir_conn[] = {
+ {0, 220},
+ {0, 219},
+ {0, 218},
+ {0, 217},
+ {0, 216},
+ {0, 215},
+ {0, 214},
+ {0, 213},
+};
+
static const struct msm_pinctrl_soc_data sdxpoorwills_pinctrl = {
.pins = sdxpoorwills_pins,
.npins = ARRAY_SIZE(sdxpoorwills_pins),
@@ -1209,6 +1222,9 @@
.n_pdc_mux_out = ARRAY_SIZE(sdxpoorwills_mux_out),
.n_pdc_mux_offset = 20,
.ngpios = 100,
+ .dir_conn_irq_base = 220,
+ .dir_conn = sdxpoorwills_dir_conn,
+ .n_dir_conns = ARRAY_SIZE(sdxpoorwills_dir_conn),
};
static int sdxpoorwills_pinctrl_probe(struct platform_device *pdev)
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index f9a2454..6a25bfd 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -49,7 +49,6 @@
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 @@
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 5d8b12b..c38f1be 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
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_gsb.c
index 5812d8d..4e3a565 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_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 @@
* @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 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
(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 @@
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_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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
index b4af0a09..5085d75 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
@@ -2146,6 +2146,15 @@
IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
return res;
}
+
+ res = ipa_mhi_suspend_dl(force);
+ if (res) {
+ IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res);
+ goto fail_suspend_dl_channel;
+ }
+
+ usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
+
res = ipa_mhi_suspend_ul(force, &empty, &force_clear);
if (res) {
IPA_MHI_ERR("ipa_mhi_suspend_ul failed %d\n", res);
@@ -2190,12 +2199,6 @@
#endif
usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
- res = ipa_mhi_suspend_dl(force);
- if (res) {
- IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res);
- goto fail_suspend_dl_channel;
- }
-
if (!empty)
ipa_set_tag_process_before_gating(false);
@@ -2209,7 +2212,6 @@
IPA_MHI_FUNC_EXIT();
return 0;
-fail_suspend_dl_channel:
fail_release_cons:
if (!ipa_pm_is_used())
ipa_mhi_request_prod();
@@ -2225,7 +2227,6 @@
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
fail_suspend_ul_channel:
ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels);
- ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
if (force_clear) {
if (
ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id)) {
@@ -2235,6 +2236,9 @@
IPA_MHI_DBG("force clear datapath disabled\n");
ipa_mhi_client_ctx->qmi_req_id++;
}
+fail_suspend_dl_channel:
+ ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->dl_channels);
+ ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
return res;
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index 10468f3..6f9afa6 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -3938,11 +3938,8 @@
}
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 @@
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 c2f7aae..0224f98 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 @@
__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 @@
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 130afc7..e7abbe9 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 @@
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 c7422c7..bc032d9 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -2536,6 +2536,9 @@
ipa3_q6_pipe_delay(true);
ipa3_q6_avoid_holb();
+ if (ipa3_ctx->ipa_config_is_mhi)
+ ipa3_set_reset_client_cons_pipe_sus_holb(true,
+ IPA_CLIENT_MHI_CONS);
if (ipa3_q6_clean_q6_tables()) {
IPAERR("Failed to clean Q6 tables\n");
BUG();
@@ -2548,8 +2551,11 @@
* on pipe reset procedure
*/
ipa3_q6_pipe_delay(false);
-
- ipa3_set_usb_prod_pipe_delay();
+ ipa3_set_reset_client_prod_pipe_delay(true,
+ IPA_CLIENT_USB_PROD);
+ if (ipa3_ctx->ipa_config_is_mhi)
+ ipa3_set_reset_client_prod_pipe_delay(true,
+ IPA_CLIENT_MHI_PROD);
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
IPADBG_LOW("Exit with success\n");
@@ -5018,7 +5024,7 @@
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 +6211,17 @@
}
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 5bcd49e..bbc3a4f 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 @@
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);
}
@@ -1323,27 +1331,32 @@
}
/*
- * Set USB PROD pipe delay for MBIM/RMNET config
+ * Set reset ep_delay for CLEINT PROD pipe
* Clocks, should be voted before calling this API
* locks should be taken before calling this API
*/
-void ipa3_set_usb_prod_pipe_delay(void)
+int ipa3_set_reset_client_prod_pipe_delay(bool set_reset,
+ enum ipa_client_type client)
{
- int result;
+ int result = 0;
int pipe_idx;
struct ipa3_ep_context *ep;
struct ipa_ep_cfg_ctrl ep_ctrl;
memset(&ep_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
- ep_ctrl.ipa_ep_delay = true;
+ ep_ctrl.ipa_ep_delay = set_reset;
+ if (IPA_CLIENT_IS_CONS(client)) {
+ IPAERR("client (%d) not PROD\n", client);
+ return -EINVAL;
+ }
- pipe_idx = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
+ pipe_idx = ipa3_get_ep_mapping(client);
if (pipe_idx == IPA_EP_NOT_ALLOCATED) {
- IPAERR("client (%d) not valid\n", IPA_CLIENT_USB_PROD);
- return;
+ IPAERR("client (%d) not valid\n", client);
+ return -EINVAL;
}
ep = &ipa3_ctx->ep[pipe_idx];
@@ -1360,6 +1373,59 @@
IPADBG("client (ep: %d) success\n", pipe_idx);
}
client_lock_unlock_cb(pipe_idx, false);
+ return result;
+}
+
+int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset,
+ enum ipa_client_type client)
+{
+ int pipe_idx;
+ struct ipa3_ep_context *ep;
+ struct ipa_ep_cfg_ctrl ep_suspend;
+ struct ipa_ep_cfg_holb ep_holb;
+
+ memset(&ep_suspend, 0, sizeof(ep_suspend));
+ memset(&ep_holb, 0, sizeof(ep_holb));
+
+ ep_suspend.ipa_ep_suspend = set_reset;
+ ep_holb.tmr_val = 0;
+ ep_holb.en = set_reset;
+
+ if (IPA_CLIENT_IS_PROD(client)) {
+ IPAERR("client (%d) not CONS\n", client);
+ return -EINVAL;
+ }
+
+ pipe_idx = ipa3_get_ep_mapping(client);
+
+ if (pipe_idx == IPA_EP_NOT_ALLOCATED) {
+ IPAERR("client (%d) not valid\n", client);
+ return -EINVAL;
+ }
+
+ ep = &ipa3_ctx->ep[pipe_idx];
+ /* Setting sus/holb on MHI_CONS with skip_ep_cfg */
+ client_lock_unlock_cb(pipe_idx, true);
+ if (ep->valid && ep->skip_ep_cfg) {
+ if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0)
+ ipahal_write_reg_n_fields(
+ IPA_ENDP_INIT_CTRL_n,
+ pipe_idx, &ep_suspend);
+ /*
+ * ipa3_cfg_ep_holb is not used here because we are
+ * setting HOLB on Q6 pipes, and from APPS perspective
+ * they are not valid, therefore, the above function
+ * will fail.
+ */
+ ipahal_write_reg_n_fields(
+ IPA_ENDP_INIT_HOL_BLOCK_TIMER_n,
+ pipe_idx, &ep_holb);
+ ipahal_write_reg_n_fields(
+ IPA_ENDP_INIT_HOL_BLOCK_EN_n,
+ pipe_idx, &ep_holb);
+ }
+ client_lock_unlock_cb(pipe_idx, false);
+ return 0;
}
void ipa3_xdci_ep_delay_rm(u32 clnt_hdl)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index 10abdcf..0925e8c 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 @@
__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 @@
"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_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 43f4c74..6dc2905 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1922,7 +1922,10 @@
void ipa3_xdci_ep_delay_rm(u32 clnt_hdl);
void ipa3_register_lock_unlock_callback(int (*client_cb)(bool), u32 ipa_ep_idx);
void ipa3_deregister_lock_unlock_callback(u32 ipa_ep_idx);
-void ipa3_set_usb_prod_pipe_delay(void);
+int ipa3_set_reset_client_prod_pipe_delay(bool set_reset,
+ enum ipa_client_type client);
+int ipa3_set_reset_client_cons_pipe_sus_holb(bool set_reset,
+ enum ipa_client_type client);
int ipa3_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl,
bool should_force_clear, u32 qmi_req_id, bool is_dpl);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
index dd97038..9075237 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
@@ -199,6 +199,7 @@
struct ipa3_ep_context *ep;
const struct ipa_gsi_ep_config *ep_cfg;
bool burst_mode_enabled = false;
+ struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
IPA_MHI_FUNC_ENTRY();
@@ -341,6 +342,20 @@
*params->mhi = ch_scratch.mhi;
+ if (IPA_CLIENT_IS_PROD(ep->client) && ep->skip_ep_cfg) {
+ memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_delay = true;
+ ep->ep_delay_set = true;
+ res = ipa3_cfg_ep_ctrl(ipa_ep_idx, &ep_cfg_ctrl);
+ if (res)
+ IPA_MHI_ERR("client (ep: %d) failed result=%d\n",
+ ipa_ep_idx, res);
+ else
+ IPA_MHI_DBG("client (ep: %d) success\n", ipa_ep_idx);
+ } else {
+ ep->ep_delay_set = false;
+ }
+
IPA_MHI_DBG("Starting channel\n");
res = gsi_start_channel(ep->gsi_chan_hdl);
if (res) {
@@ -524,6 +539,7 @@
{
struct ipa3_ep_context *ep;
int res;
+ struct ipa_ep_cfg_ctrl ep_cfg_ctrl;
IPA_MHI_FUNC_ENTRY();
@@ -538,6 +554,21 @@
}
ep = &ipa3_ctx->ep[clnt_hdl];
+ if (ep->ep_delay_set == true) {
+ memset(&ep_cfg_ctrl, 0, sizeof(struct ipa_ep_cfg_ctrl));
+ ep_cfg_ctrl.ipa_ep_delay = false;
+ res = ipa3_cfg_ep_ctrl(clnt_hdl,
+ &ep_cfg_ctrl);
+ if (res) {
+ IPAERR
+ ("client(ep:%d) failed to remove delay res=%d\n",
+ clnt_hdl, res);
+ } else {
+ IPADBG("client (ep: %d) delay removed\n",
+ clnt_hdl);
+ ep->ep_delay_set = false;
+ }
+ }
res = gsi_dealloc_channel(ep->gsi_chan_hdl);
if (res) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index 7065e2c..2716d4a 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 @@
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/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index 736c0fb..2212b00 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -908,6 +908,20 @@
return 0;
}
+static int __ipa_rt_validate_rule_id(u16 rule_id)
+{
+ if (!rule_id)
+ return 0;
+
+ if ((rule_id < ipahal_get_rule_id_hi_bit()) ||
+ (rule_id >= ((ipahal_get_rule_id_hi_bit()<<1)-1))) {
+ IPAERR_RL("Invalid rule_id provided 0x%x\n",
+ rule_id);
+ return -EPERM;
+ }
+
+ return 0;
+}
static int __ipa_rt_validate_hndls(const struct ipa_rt_rule *rule,
struct ipa3_hdr_entry **hdr,
struct ipa3_hdr_proc_ctx_entry **proc_ctx)
@@ -1023,6 +1037,8 @@
if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx))
goto error;
+ if (__ipa_rt_validate_rule_id(rule_id))
+ goto error;
tbl = __ipa_add_rt_tbl(ip, name);
if (tbl == NULL || (tbl->cookie != IPA_RT_TBL_COOKIE)) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c
index f1e2e6d..5ec331c 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 @@
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 3559021..6cb2d7d 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 <linux/msm_ep_pcie.h>
-#include <linux/types.h>
#include <linux/ipc_logging.h>
-#include <linux/dma-mapping.h>
+#include <linux/msm_mhi_dev.h>
/**
* MHI control data structures alloted by the host, including
@@ -276,8 +275,6 @@
#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 @@
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 @@
#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 @@
/* 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 @@
} \
} 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 @@
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_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_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 d6791ea..92b0616 100644
--- a/drivers/platform/msm/mhi_dev/mhi_ring.c
+++ b/drivers/platform/msm/mhi_dev/mhi_ring.c
@@ -278,11 +278,12 @@
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 @@
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 @@
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,
- NULL, MHI_DEV_DMA_SYNC);
+ 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,
+ 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 01e127b..4b9307d 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/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 8a1bfd4..ed27768 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -161,6 +161,16 @@
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 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 @@
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 8281c41..a0b9bca 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -339,6 +339,7 @@
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 b3bf42a..b0ff18c 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -134,6 +134,7 @@
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 @@
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 af8b158..711bd2b 100644
--- a/drivers/power/supply/qcom/qg-soc.c
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -17,15 +17,19 @@
#include <linux/module.h>
#include <linux/power_supply.h>
#include <uapi/linux/qg.h>
+#include <uapi/linux/qg-profile.h>
#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 @@
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 @@
/* 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 @@
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 @@
}
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 @@
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 3b4eb60..cd64bd5 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 85efdbf..a3e045e 100644
--- a/drivers/power/supply/qcom/qg-util.c
+++ b/drivers/power/supply/qcom/qg-util.c
@@ -367,3 +367,25 @@
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 2dbafe7..5dd6c85 100644
--- a/drivers/power/supply/qcom/qg-util.h
+++ b/drivers/power/supply/qcom/qg-util.h
@@ -26,5 +26,6 @@
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-linear-charger.c b/drivers/power/supply/qcom/qpnp-linear-charger.c
index aedc77a..7815eba 100644
--- a/drivers/power/supply/qcom/qpnp-linear-charger.c
+++ b/drivers/power/supply/qcom/qpnp-linear-charger.c
@@ -2877,7 +2877,8 @@
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 1);
REQUEST_IRQ(chip, USBIN_VALID, rc, usbin_valid, 1,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 1);
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+ | IRQF_ONESHOT, 1);
REQUEST_IRQ(chip, USB_CHG_GONE, rc, chg_gone, 0,
IRQF_TRIGGER_RISING, 1);
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 41b8d3c..fede66f 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -1029,11 +1029,23 @@
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) {
- chip->catch_up_soc = chip->udata.param[QG_SOC].data;
+ 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;
+ }
+
qg_scale_soc(chip, false);
/* update parameters to SDAM */
@@ -1500,28 +1512,6 @@
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
@@ -1868,9 +1858,11 @@
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;
@@ -1881,10 +1873,18 @@
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,
@@ -1892,23 +1892,33 @@
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;
@@ -2620,7 +2630,7 @@
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;
@@ -2875,10 +2885,6 @@
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 */
@@ -3436,7 +3442,7 @@
{
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)
@@ -3454,11 +3460,6 @@
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;
- }
/* Clear suspend data as there has been a GOOD OCV */
memset(&chip->kdata, 0, sizeof(chip->kdata));
@@ -3606,6 +3607,7 @@
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 53af341..6adc19a 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 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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
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-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c
index 56a09c6..e3e4f2b 100644
--- a/drivers/power/supply/qcom/qpnp-smb2.c
+++ b/drivers/power/supply/qcom/qpnp-smb2.c
@@ -985,6 +985,7 @@
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CURRENT_QNOVO,
POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+ POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED,
@@ -1076,6 +1077,10 @@
val->intval = get_client_vote(chg->fcc_votable,
BATT_PROFILE_VOTER);
break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ val->intval = get_client_vote(chg->fcc_votable,
+ FG_ESR_VOTER);
+ break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
break;
@@ -1183,6 +1188,12 @@
chg->batt_profile_fcc_ua = val->intval;
vote(chg->fcc_votable, BATT_PROFILE_VOTER, true, val->intval);
break;
+ case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+ if (val->intval)
+ vote(chg->fcc_votable, FG_ESR_VOTER, true, val->intval);
+ else
+ vote(chg->fcc_votable, FG_ESR_VOTER, false, 0);
+ break;
case POWER_SUPPLY_PROP_SET_SHIP_MODE:
/* Not in ship mode as long as the device is active */
if (!val->intval)
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index 122c0869..e56ecb0 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -283,6 +283,8 @@
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 @@
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 @@
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 @@
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,8 +1257,55 @@
POWER_SUPPLY_PROP_CHARGE_COUNTER,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_RECHARGE_SOC,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
};
+#define ITERM_SCALING_FACTOR_PMI632 1525
+#define ITERM_SCALING_FACTOR_PM855B 3050
+static int smb5_get_prop_batt_iterm(struct smb_charger *chg,
+ union power_supply_propval *val)
+{
+ int rc, temp, scaling_factor;
+ u8 stat, buf[2];
+
+ /*
+ * Currently, only ADC comparator-based termination is supported,
+ * hence read only the threshold corresponding to ADC source.
+ * Proceed only if CHGR_ITERM_USE_ANALOG_BIT is 0.
+ */
+ rc = smblib_read(chg, CHGR_ENG_CHARGING_CFG_REG, &stat);
+ if (rc < 0) {
+ pr_err("Couldn't read CHGR_ENG_CHARGING_CFG_REG rc=%d\n", rc);
+ return rc;
+ }
+
+ if (stat & CHGR_ITERM_USE_ANALOG_BIT) {
+ val->intval = -EINVAL;
+ return 0;
+ }
+
+ rc = smblib_batch_read(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG, buf, 2);
+
+ if (rc < 0) {
+ pr_err("Couldn't read CHGR_ADC_ITERM_UP_THD_MSB_REG rc=%d\n",
+ rc);
+ return rc;
+ }
+
+ temp = buf[1] | (buf[0] << 8);
+ temp = sign_extend32(temp, 15);
+
+ if (chg->smb_version == PMI632_SUBTYPE)
+ scaling_factor = ITERM_SCALING_FACTOR_PMI632;
+ else
+ scaling_factor = ITERM_SCALING_FACTOR_PM855B;
+
+ temp = div_s64(temp * scaling_factor, 10000);
+ val->intval = temp;
+
+ return rc;
+}
+
static int smb5_batt_get_prop(struct power_supply *psy,
enum power_supply_property psp,
union power_supply_propval *val)
@@ -1296,24 +1352,26 @@
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,
BATT_PROFILE_VOTER);
break;
case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT:
- rc = smblib_get_prop_batt_iterm(chg, val);
+ rc = smb5_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 +1400,20 @@
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 +1710,6 @@
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 +1748,37 @@
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;
}
@@ -1731,30 +1818,42 @@
return 0;
}
+#define RAW_TERM_CURR(conv_factor, scaled_ma) \
+ div_s64((int64_t)scaled_ma * 10000, conv_factor)
+#define ITERM_LIMITS_PMI632_MA 5000
+#define ITERM_LIMITS_PM855B_MA 10000
static int smb5_configure_iterm_thresholds_adc(struct smb5 *chip)
{
u8 *buf;
int rc = 0;
- s16 raw_hi_thresh, raw_lo_thresh;
+ int raw_hi_thresh, raw_lo_thresh, max_limit_ma, scaling_factor;
struct smb_charger *chg = &chip->chg;
- if (chip->dt.term_current_thresh_hi_ma < -10000 ||
- chip->dt.term_current_thresh_hi_ma > 10000 ||
- chip->dt.term_current_thresh_lo_ma < -10000 ||
- chip->dt.term_current_thresh_lo_ma > 10000) {
+ if (chip->chg.smb_version == PMI632_SUBTYPE) {
+ scaling_factor = ITERM_SCALING_FACTOR_PMI632;
+ max_limit_ma = ITERM_LIMITS_PMI632_MA;
+ } else {
+ scaling_factor = ITERM_SCALING_FACTOR_PM855B;
+ max_limit_ma = ITERM_LIMITS_PM855B_MA;
+ }
+
+ if (chip->dt.term_current_thresh_hi_ma < (-1 * max_limit_ma)
+ || chip->dt.term_current_thresh_hi_ma > max_limit_ma
+ || chip->dt.term_current_thresh_lo_ma < (-1 * max_limit_ma)
+ || chip->dt.term_current_thresh_lo_ma > max_limit_ma) {
dev_err(chg->dev, "ITERM threshold out of range rc=%d\n", rc);
return -EINVAL;
}
/*
* Conversion:
- * raw (A) = (scaled_mA * ADC_CHG_TERM_MASK) / (10 * 1000)
+ * raw (A) = (scaled_mA * (10000) / conv_factor)
* Note: raw needs to be converted to big-endian format.
*/
if (chip->dt.term_current_thresh_hi_ma) {
- raw_hi_thresh = ((chip->dt.term_current_thresh_hi_ma *
- ADC_CHG_TERM_MASK) / 10000);
+ raw_hi_thresh = RAW_TERM_CURR(scaling_factor,
+ chip->dt.term_current_thresh_hi_ma);
raw_hi_thresh = sign_extend32(raw_hi_thresh, 15);
buf = (u8 *)&raw_hi_thresh;
raw_hi_thresh = buf[1] | (buf[0] << 8);
@@ -1769,8 +1868,8 @@
}
if (chip->dt.term_current_thresh_lo_ma) {
- raw_lo_thresh = ((chip->dt.term_current_thresh_lo_ma *
- ADC_CHG_TERM_MASK) / 10000);
+ raw_lo_thresh = RAW_TERM_CURR(scaling_factor,
+ chip->dt.term_current_thresh_lo_ma);
raw_lo_thresh = sign_extend32(raw_lo_thresh, 15);
buf = (u8 *)&raw_lo_thresh;
raw_lo_thresh = buf[1] | (buf[0] << 8);
@@ -2397,6 +2496,7 @@
[TYPEC_ATTACH_DETACH_IRQ] = {
.name = "typec-attach-detach",
.handler = typec_attach_detach_irq_handler,
+ .wake = true,
},
[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
.name = "typec-legacy-cable-detect",
diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h
index 3b8bc1f..729118d 100644
--- a/drivers/power/supply/qcom/smb-lib.h
+++ b/drivers/power/supply/qcom/smb-lib.h
@@ -71,6 +71,7 @@
#define MOISTURE_VOTER "MOISTURE_VOTER"
#define HVDCP2_ICL_VOTER "HVDCP2_ICL_VOTER"
#define OV_VOTER "OV_VOTER"
+#define FG_ESR_VOTER "FG_ESR_VOTER"
#define VCONN_MAX_ATTEMPTS 3
#define OTG_MAX_ATTEMPTS 3
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index be0832e..f91d477 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -19,6 +19,7 @@
#include <linux/irq.h>
#include <linux/pmic-voter.h>
#include <linux/of_batterydata.h>
+#include <linux/alarmtimer.h>
#include "smb5-lib.h"
#include "smb5-reg.h"
#include "battery.h"
@@ -586,6 +587,21 @@
/********************
* 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 @@
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 @@
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 @@
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 @@
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 @@
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,84 +1598,6 @@
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)
-{
- int rc, temp;
- u8 stat, buf[2];
-
- /*
- * Currently, only ADC comparator-based termination is supported,
- * hence read only the threshold corresponding to ADC source.
- * Proceed only if CHGR_ITERM_USE_ANALOG_BIT is 0.
- */
- rc = smblib_read(chg, CHGR_ENG_CHARGING_CFG_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read CHGR_ENG_CHARGING_CFG_REG rc=%d\n",
- rc);
- return rc;
- }
-
- if (stat & CHGR_ITERM_USE_ANALOG_BIT) {
- val->intval = -EINVAL;
- return 0;
- }
-
- rc = smblib_batch_read(chg, CHGR_ADC_ITERM_UP_THD_MSB_REG, buf, 2);
-
- if (rc < 0) {
- smblib_err(chg, "Couldn't read CHGR_ADC_ITERM_UP_THD_MSB_REG rc=%d\n",
- rc);
- return rc;
- }
-
- temp = buf[1] | (buf[0] << 8);
- temp = sign_extend32(temp, 15);
- temp = DIV_ROUND_CLOSEST(temp * 10000, ADC_CHG_TERM_MASK);
- val->intval = temp;
-
- 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 +1616,6 @@
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 *
***********************/
@@ -1674,9 +1681,6 @@
return -EINVAL;
chg->system_temp_level = val->intval;
- /* disable parallel charge in case of system temp level */
- vote(chg->pl_disable_votable, THERMAL_DAEMON_VOTER,
- chg->system_temp_level ? true : false, 0);
if (chg->system_temp_level == chg->thermal_levels)
return vote(chg->chg_disable_votable,
@@ -3495,11 +3499,28 @@
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 +3888,96 @@
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 +4030,21 @@
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 +4188,21 @@
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 +4264,11 @@
{
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 5be985e..9afd7cd 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -18,6 +18,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/consumer.h>
#include <linux/extcon.h>
+#include <linux/alarmtimer.h>
#include "storm-watch.h"
enum print_reason {
@@ -68,6 +69,7 @@
#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
@@ -82,7 +84,6 @@
#define TYPEC_DEFAULT_CURRENT_UA 900000
#define TYPEC_MEDIUM_CURRENT_UA 1500000
#define TYPEC_HIGH_CURRENT_UA 3000000
-#define ADC_CHG_TERM_MASK 32767
enum smb_mode {
PARALLEL_MASTER = 0,
@@ -99,6 +100,7 @@
enum {
BOOST_BACK_WA = BIT(0),
WEAK_ADAPTER_WA = BIT(1),
+ MOISTURE_PROTECTION_WA = BIT(2),
};
enum {
@@ -339,6 +341,7 @@
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 +349,9 @@
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 +400,8 @@
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 +499,6 @@
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 +572,9 @@
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 e9c4a0f..57eb22a 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -126,6 +126,7 @@
#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 @@
#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 @@
#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 @@
#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 54433fc..e4eaefc 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -52,6 +52,10 @@
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 @@
.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 72c0bce..5208b3f 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 @@
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 @@
}
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 <mika.westerberg@linux.intel.com>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index 04766e0..27d5081 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -31,5 +31,7 @@
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 88c5697..d72af20 100644
--- a/drivers/regulator/qpnp-labibb-regulator.c
+++ b/drivers/regulator/qpnp-labibb-regulator.c
@@ -597,6 +597,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 1d4770c..fd3d941 100644
--- a/drivers/rpmsg/qcom_smd.c
+++ b/drivers/rpmsg/qcom_smd.c
@@ -1006,12 +1006,12 @@
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 @@
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 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 4534a7c..b6caad0 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -625,6 +625,46 @@
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 3b23d675..2abcd33 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -34,11 +34,28 @@
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 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 7a7984a..b326f05 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -52,10 +52,15 @@
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 bb99db2..3afb200 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -180,6 +180,7 @@
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 @@
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 @@
{
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 @@
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 4441a55..34bbcfc 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -3319,7 +3319,8 @@
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 e3cd3ec..c3d1891 100644
--- a/drivers/scsi/scsi_transport_srp.c
+++ b/drivers/scsi/scsi_transport_srp.c
@@ -52,6 +52,8 @@
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 @@
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 @@
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 15d5af0..0f657b8 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -51,6 +51,7 @@
#include <linux/atomic.h>
#include <linux/ratelimit.h>
#include <linux/uio.h>
+#include <linux/cred.h> /* for sg_check_file_access() */
#include "scsi.h"
#include <scsi/scsi_dbg.h>
@@ -210,6 +211,33 @@
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 @@
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 @@
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 447995a..4dfd8d3 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -727,6 +727,11 @@
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 @@
__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 c6cfd18..6c97870 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -8368,7 +8368,7 @@
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 @@
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 @@
__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 @@
* 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 @@
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 3ecca59..0e16501 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -52,6 +52,14 @@
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"
@@ -187,6 +195,43 @@
Client driver for the WCNSS_CTRL SMD channel, used to download nv
firmware to a newly booted WCNSS chip.
+config SETUP_SSR_NOTIF_TIMEOUTS
+ bool "Set timeouts on SSR sysmon notifications and notifier callbacks"
+ help
+ Setup timers prior to initiating communication between
+ subsystems through sysmon, and prior to sending notifications
+ to drivers in the kernel that have registered callbacks with the
+ subsystem notifier framework for a particular subsystem. This
+ is a debugging feature.
+
+config SSR_SYSMON_NOTIF_TIMEOUT
+ depends on SETUP_SSR_NOTIF_TIMEOUTS
+ int "SSR Sysmon notifications timeout in ms"
+ default 10000
+ help
+ The amount of time, in milliseconds, that should elapse between
+ the start and end of sysmon SSR notifications, before a warning
+ is emitted.
+
+config SSR_SUBSYS_NOTIF_TIMEOUT
+ depends on SETUP_SSR_NOTIF_TIMEOUTS
+ int "SSR Subsystem notifier timeout in ms"
+ default 10000
+ help
+ The amount of time, in milliseconds, that should elapse between
+ the start and end of SSR notifications through the subsystem
+ notifier, before a warning is emitted.
+
+config PANIC_ON_SSR_NOTIF_TIMEOUT
+ bool "Trigger kernel panic when notification timeout expires"
+ depends on SETUP_SSR_NOTIF_TIMEOUTS
+ help
+ Trigger a kernel panic when communication between subsystems
+ through sysmon is taking too long. Also trigger a kernel panic
+ if invoking the callbacks registered with a particular subsystem's
+ notifications by the subsystem notifier framework is taking too long.
+ This is a debugging feature.
+
config MSM_BOOT_STATS
bool "Use MSM boot stats reporting"
help
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 0b71121..1da8346 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -7,6 +7,7 @@
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 1cde8c6..75c9928 100644
--- a/drivers/soc/qcom/bgcom_interface.c
+++ b/drivers/soc/qcom/bgcom_interface.c
@@ -306,10 +306,23 @@
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 d2dc05f..d21e2e9 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 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 @@
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 @@
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 @@
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);
@@ -910,6 +928,8 @@
pr_debug("No callback registered\n");
return IRQ_HANDLED;
} else if (spi_state == BGCOM_SPI_BUSY) {
+ /* delay for SPI to be freed */
+ msleep(50);
return IRQ_HANDLED;
} else if (!bg_spi->irq_lock) {
bg_spi->irq_lock = 1;
@@ -943,6 +963,10 @@
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 +1030,9 @@
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.c b/drivers/soc/qcom/dcc.c
index bef0757..3f4ad5d 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -39,8 +39,6 @@
#define dcc_readl(drvdata, off) \
__raw_readl(drvdata->base + off)
-#define dcc_sram_writel(drvdata, val, off) \
- __raw_writel((val), drvdata->ram_base + off)
#define dcc_sram_readl(drvdata, off) \
__raw_readl(drvdata->ram_base + off)
@@ -129,6 +127,16 @@
uint64_t xpu_addr;
uint32_t xpu_unlock_count;
};
+static int dcc_sram_writel(struct dcc_drvdata *drvdata,
+ uint32_t val, uint32_t off)
+{
+ if (unlikely(off > (drvdata->ram_size - 4)))
+ return -EINVAL;
+
+ __raw_writel((val), drvdata->ram_base + off);
+
+ return 0;
+}
static int dcc_cfg_xpu(struct dcc_drvdata *drvdata, bool enable)
{
@@ -277,12 +285,17 @@
if (!prev_addr || prev_addr != addr || prev_off > off) {
/* Check if we need to write link of prev entry */
if (link) {
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
}
/* Write address */
- dcc_sram_writel(drvdata, addr, sram_offset);
+ ret = dcc_sram_writel(drvdata, addr, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
/* Reset link and prev_off */
@@ -322,7 +335,9 @@
((entry->len << 8) & BM(8, 14))) << pos;
if (pos) {
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata, link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
link = 0;
}
@@ -332,12 +347,16 @@
}
if (link) {
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata, link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
}
/* Setting zero to indicate end of the list */
- dcc_sram_writel(drvdata, 0, sram_offset);
+ ret = dcc_sram_writel(drvdata, 0, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
/* check if the data will overstep */
diff --git a/drivers/soc/qcom/dcc_v2.c b/drivers/soc/qcom/dcc_v2.c
index e641290..279461d 100644
--- a/drivers/soc/qcom/dcc_v2.c
+++ b/drivers/soc/qcom/dcc_v2.c
@@ -35,8 +35,6 @@
#define dcc_readl(drvdata, off) \
__raw_readl(drvdata->base + off)
-#define dcc_sram_writel(drvdata, val, off) \
- __raw_writel((val), drvdata->ram_base + off)
#define dcc_sram_readl(drvdata, off) \
__raw_readl(drvdata->ram_base + off)
@@ -153,6 +151,17 @@
uint8_t cti_trig;
};
+static int dcc_sram_writel(struct dcc_drvdata *drvdata,
+ uint32_t val, uint32_t off)
+{
+ if (unlikely(off > (drvdata->ram_size - 4)))
+ return -EINVAL;
+
+ __raw_writel((val), drvdata->ram_base + off);
+
+ return 0;
+}
+
static bool dcc_ready(struct dcc_drvdata *drvdata)
{
uint32_t val;
@@ -252,7 +261,10 @@
* processing the list
*/
link |= ((0x1 << 8) & BM(8, 14));
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
/* Reset link and prev_off */
addr = 0x00;
@@ -262,13 +274,21 @@
}
addr = DCC_RD_MOD_WR_DESCRIPTOR;
- dcc_sram_writel(drvdata, addr, sram_offset);
+ ret = dcc_sram_writel(drvdata, addr, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
- dcc_sram_writel(drvdata, entry->mask, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ entry->mask, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
- dcc_sram_writel(drvdata, entry->write_val, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ entry->write_val, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
addr = 0;
break;
@@ -278,7 +298,10 @@
{
/* Check if we need to write link of prev entry */
if (link) {
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
}
@@ -288,7 +311,10 @@
loop |= DCC_LOOP_DESCRIPTOR;
total_len += (total_len - loop_len) * loop_cnt;
- dcc_sram_writel(drvdata, loop, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ loop, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
loop_start = false;
@@ -317,7 +343,10 @@
* processing the list
*/
link |= ((0x1 << 8) & BM(8, 14));
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
/* Reset link and prev_off */
addr = 0x00;
@@ -340,13 +369,20 @@
addr |= DCC_ADDR_DESCRIPTOR | DCC_WRITE_IND
| DCC_AHB_IND;
- dcc_sram_writel(drvdata, addr, sram_offset);
+ ret = dcc_sram_writel(drvdata, addr, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata, link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
- dcc_sram_writel(drvdata, entry->write_val, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ entry->write_val, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
addr = 0x00;
link = 0;
@@ -370,8 +406,10 @@
if (!prev_addr || prev_addr != addr || prev_off > off) {
/* Check if we need to write prev link entry */
if (link) {
- dcc_sram_writel(drvdata,
+ ret = dcc_sram_writel(drvdata,
link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
}
dev_dbg(drvdata->dev,
@@ -379,7 +417,10 @@
sram_offset);
/* Write address */
- dcc_sram_writel(drvdata, addr, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ addr, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
/* Reset link and prev_off */
@@ -422,7 +463,10 @@
link |= DCC_LINK_DESCRIPTOR;
if (pos) {
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata,
+ link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
link = 0;
}
@@ -434,7 +478,9 @@
}
if (link) {
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata, link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
}
@@ -450,13 +496,17 @@
addr = (0xC105E) & BM(0, 27);
addr |= DCC_ADDR_DESCRIPTOR;
- dcc_sram_writel(drvdata, addr, sram_offset);
+ ret = dcc_sram_writel(drvdata, addr, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
}
/* Setting zero to indicate end of the list */
link = DCC_LINK_DESCRIPTOR;
- dcc_sram_writel(drvdata, link, sram_offset);
+ ret = dcc_sram_writel(drvdata, link, sram_offset);
+ if (ret)
+ goto overstep;
sram_offset += 4;
/* Update ram_cfg and check if the data will overstep */
@@ -990,6 +1040,14 @@
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/glink_bgcom_xprt.c b/drivers/soc/qcom/glink_bgcom_xprt.c
index 3c3923c..290d667 100644
--- a/drivers/soc/qcom/glink_bgcom_xprt.c
+++ b/drivers/soc/qcom/glink_bgcom_xprt.c
@@ -324,25 +324,22 @@
uint32_t size)
{
int ret;
- DEFINE_WAIT(wait);
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
mutex_lock(&einfo->write_lock);
+ add_wait_queue(&einfo->tx_blocked_queue, &wait);
while (glink_bgcom_get_tx_avail(einfo) < (size/WORD_SIZE)) {
send_tx_blocked_signal(einfo);
- prepare_to_wait(&einfo->tx_blocked_queue, &wait,
- TASK_UNINTERRUPTIBLE);
- if (glink_bgcom_get_tx_avail(einfo) < (size/WORD_SIZE)
- && !einfo->in_ssr) {
- mutex_unlock(&einfo->write_lock);
- schedule();
- mutex_lock(&einfo->write_lock);
- }
- finish_wait(&einfo->tx_blocked_queue, &wait);
if (einfo->in_ssr) {
+ remove_wait_queue(&einfo->tx_blocked_queue, &wait);
mutex_unlock(&einfo->write_lock);
return -EFAULT;
}
+ mutex_unlock(&einfo->write_lock);
+ wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+ mutex_lock(&einfo->write_lock);
}
+ remove_wait_queue(&einfo->tx_blocked_queue, &wait);
ret = glink_bgcom_xprt_tx_cmd_safe(einfo, src, size);
mutex_unlock(&einfo->write_lock);
return ret;
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index b8e9268..5278345 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -284,6 +284,8 @@
ICNSS_HOST_TRIGGERED_PDR,
ICNSS_FW_DOWN,
ICNSS_DRIVER_UNLOADING,
+ ICNSS_REJUVENATE,
+ ICNSS_MODE_ON,
};
struct ce_irq_list {
@@ -1172,6 +1174,14 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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);
@@ -3500,7 +3529,6 @@
goto out;
}
- WARN_ON(1);
icnss_pr_warn("Initiate PD restart at WLAN FW, state: 0x%lx\n",
priv->state);
@@ -3525,6 +3553,7 @@
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 +3597,16 @@
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 +4028,14 @@
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 0000000..d3d3390
--- /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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/soc/qcom/llcc-qcom.h>
+
+/*
+ * 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 a292879..4559f11 100644
--- a/drivers/soc/qcom/msm_glink_pkt.c
+++ b/drivers/soc/qcom/msm_glink_pkt.c
@@ -398,7 +398,10 @@
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 @@
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 675551a..aff0389 100644
--- a/drivers/soc/qcom/rpm-smd.c
+++ b/drivers/soc/qcom/rpm-smd.c
@@ -747,23 +747,69 @@
{
int ret;
char buf[MAX_ERR_BUFFER_SIZE] = {0};
+ uint32_t msg_id;
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)
+ return -EAGAIN;
+
ret = msm_rpm_read_smd_data(buf);
- if (!ret)
+ if (!ret) {
+ /* Mimic Glink behavior to ensure that the
+ * data is read and the msg is removed from
+ * the wait list. We should have gotten here
+ * only when there are no drivers waiting on
+ * ACKs. msm_rpm_get_entry_from_msg_id()
+ * return non-NULL only then.
+ */
+ msg_id = msm_rpm_get_msg_id_from_ack(buf);
+ msm_rpm_process_ack(msg_id, 0);
ret = smd_is_pkt_avail(msm_rpm_data.ch_info);
+ }
}
return ret;
}
+static void msm_rpm_flush_noack_messages(void)
+{
+ while (!list_empty(&msm_rpm_wait_list)) {
+ if (!msm_rpm_read_sleep_ack())
+ break;
+ }
+}
+
static int msm_rpm_flush_requests(bool print)
{
struct rb_node *t;
int ret;
int count = 0;
+ msm_rpm_flush_noack_messages();
+
for (t = rb_first(&tr_root); t; t = rb_next(t)) {
struct slp_buf *s = rb_entry(t, struct slp_buf, node);
@@ -800,8 +846,10 @@
if (ret >= 0)
count--;
- else
+ else {
+ pr_err("Timed out waiting for RPM ACK\n");
return ret;
+ }
}
}
return 0;
@@ -1030,14 +1078,18 @@
bool msm_rpm_waiting_for_ack(void)
{
- bool ret;
+ bool ret = false;
unsigned long flags;
+ struct msm_rpm_wait_data *elem = NULL;
spin_lock_irqsave(&msm_rpm_list_lock, flags);
- ret = list_empty(&msm_rpm_wait_list);
+ elem = list_first_entry_or_null(&msm_rpm_wait_list,
+ struct msm_rpm_wait_data, list);
+ if (elem)
+ ret = !elem->delete_on_ack;
spin_unlock_irqrestore(&msm_rpm_list_lock, flags);
- return !ret;
+ return ret;
}
static struct msm_rpm_wait_data *msm_rpm_get_entry_from_msg_id(uint32_t msg_id)
diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c
index 110cdf7..f20eda2 100644
--- a/drivers/soc/qcom/subsystem_restart.c
+++ b/drivers/soc/qcom/subsystem_restart.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
@@ -38,6 +38,7 @@
#include <trace/events/trace_msm_pil_event.h>
#include <asm/current.h>
+#include <linux/timer.h>
#include "peripheral-loader.h"
@@ -53,6 +54,35 @@
#define SHUTDOWN_ACK_MAX_LOOPS 100
#define SHUTDOWN_ACK_DELAY_MS 100
+#ifdef CONFIG_SETUP_SSR_NOTIF_TIMEOUTS
+/* Timeout used for detection of notification hangs. In seconds.*/
+#define SYSMON_COMM_TIMEOUT CONFIG_SSR_SYSMON_NOTIF_TIMEOUT
+#define SUBSYS_NOTIF_TIMEOUT CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT
+
+#define setup_timeout(dest_ss, source_ss, comm_type) \
+ _setup_timeout(dest_ss, source_ss, comm_type)
+#define cancel_timeout(subsys) del_timer(&subsys->timeout_data.timer)
+#define init_subsys_timer(subsys) _init_subsys_timer(subsys)
+
+/* Timeout values */
+static unsigned long timeout_vals[NUM_SSR_COMMS] = {
+ [SUBSYS_TO_SUBSYS_SYSMON] = SYSMON_COMM_TIMEOUT,
+ [SUBSYS_TO_HLOS] = SUBSYS_NOTIF_TIMEOUT,
+ [HLOS_TO_SUBSYS_SYSMON_SHUTDOWN] = SYSMON_COMM_TIMEOUT,
+};
+
+#ifdef CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT
+#define SSR_NOTIF_TIMEOUT_WARN(fmt...) panic(fmt)
+#else /* CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT */
+#define SSR_NOTIF_TIMEOUT_WARN(fmt...) WARN(1, fmt)
+#endif /* CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT */
+
+#else /* CONFIG_SETUP_SSR_NOTIF_TIMEOUTS */
+#define setup_timeout(dest_ss, source_ss, sysmon_comm)
+#define cancel_timeout(subsys)
+#define init_subsys_timer(subsys)
+#endif /* CONFIG_SETUP_SSR_NOTIF_TIMEOUTS */
+
/**
* enum p_subsys_state - state of a subsystem (private)
* @SUBSYS_NORMAL: subsystem is operating normally
@@ -470,15 +500,89 @@
return enable_ramdumps;
}
+#ifdef CONFIG_SETUP_SSR_NOTIF_TIMEOUTS
+static void notif_timeout_handler(unsigned long data)
+{
+ char *sysmon_msg = "Sysmon communication from %s to %s taking too long";
+ char *subsys_notif_msg = "Subsys notifier chain for %s taking too long";
+ char *sysmon_shutdwn_msg = "sysmon_send_shutdown to %s taking too long";
+ char *unknown_err_msg = "Unknown communication occurred";
+ struct subsys_notif_timeout *timeout_data =
+ (struct subsys_notif_timeout *) data;
+ enum ssr_comm comm_type = timeout_data->comm_type;
+
+ switch (comm_type) {
+ case SUBSYS_TO_SUBSYS_SYSMON:
+ SSR_NOTIF_TIMEOUT_WARN(sysmon_msg, timeout_data->source_name,
+ timeout_data->dest_name);
+ break;
+ case SUBSYS_TO_HLOS:
+ SSR_NOTIF_TIMEOUT_WARN(subsys_notif_msg,
+ timeout_data->source_name);
+ break;
+ case HLOS_TO_SUBSYS_SYSMON_SHUTDOWN:
+ SSR_NOTIF_TIMEOUT_WARN(sysmon_shutdwn_msg,
+ timeout_data->dest_name);
+ break;
+ default:
+ SSR_NOTIF_TIMEOUT_WARN(unknown_err_msg);
+ }
+
+}
+
+static void _setup_timeout(struct subsys_desc *source_ss,
+ struct subsys_desc *dest_ss, enum ssr_comm comm_type)
+{
+ struct subsys_notif_timeout *timeout_data;
+ unsigned long timeout;
+
+ switch (comm_type) {
+ case SUBSYS_TO_SUBSYS_SYSMON:
+ timeout_data = &source_ss->timeout_data;
+ timeout_data->dest_name = dest_ss->name;
+ timeout_data->source_name = source_ss->name;
+ break;
+ case SUBSYS_TO_HLOS:
+ timeout_data = &source_ss->timeout_data;
+ timeout_data->dest_name = NULL;
+ timeout_data->source_name = source_ss->name;
+ break;
+ case HLOS_TO_SUBSYS_SYSMON_SHUTDOWN:
+ timeout_data = &dest_ss->timeout_data;
+ timeout_data->dest_name = dest_ss->name;
+ timeout_data->source_name = NULL;
+ break;
+ default:
+ return;
+ }
+
+ timeout_data->timer.data = (unsigned long) timeout_data;
+ timeout_data->comm_type = comm_type;
+ timeout = jiffies + msecs_to_jiffies(timeout_vals[comm_type]);
+ mod_timer(&timeout_data->timer, timeout);
+}
+
+static void _init_subsys_timer(struct subsys_desc *subsys)
+{
+ init_timer(&subsys->timeout_data.timer);
+ subsys->timeout_data.timer.function = notif_timeout_handler;
+}
+
+#endif /* CONFIG_SETUP_SSR_NOTIF_TIMEOUTS */
+
static void send_sysmon_notif(struct subsys_device *dev)
{
struct subsys_device *subsys;
mutex_lock(&subsys_list_lock);
list_for_each_entry(subsys, &subsys_list, list)
- if ((subsys->notif_state > 0) && (subsys != dev))
+ if ((subsys->notif_state > 0) && (subsys != dev)) {
+ setup_timeout(subsys->desc, dev->desc,
+ SUBSYS_TO_SUBSYS_SYSMON);
sysmon_send_event(dev->desc, subsys->desc,
subsys->notif_state);
+ cancel_timeout(subsys->desc);
+ }
mutex_unlock(&subsys_list_lock);
}
@@ -520,9 +624,13 @@
mutex_lock(&subsys_list_lock);
list_for_each_entry(subsys, &subsys_list, list)
if (dev != subsys &&
- subsys->track.state == SUBSYS_ONLINE)
+ subsys->track.state == SUBSYS_ONLINE) {
+ setup_timeout(dev->desc, subsys->desc,
+ SUBSYS_TO_SUBSYS_SYSMON);
sysmon_send_event(subsys->desc, dev->desc,
- notif);
+ notif);
+ cancel_timeout(dev->desc);
+ }
mutex_unlock(&subsys_list_lock);
if (notif == SUBSYS_AFTER_POWERUP &&
@@ -536,8 +644,10 @@
notif_data.pdev = pdev;
trace_pil_notif("before_send_notif", notif, dev->desc->fw_name);
+ setup_timeout(dev->desc, NULL, SUBSYS_TO_HLOS);
subsys_notif_queue_notification(dev->notify, notif,
¬if_data);
+ cancel_timeout(dev->desc);
trace_pil_notif("after_send_notif", notif, dev->desc->fw_name);
}
}
@@ -750,8 +860,11 @@
if (!of_property_read_bool(subsys->desc->dev->of_node,
"qcom,pil-force-shutdown")) {
subsys_set_state(subsys, SUBSYS_OFFLINING);
+ setup_timeout(NULL, subsys->desc,
+ HLOS_TO_SUBSYS_SYSMON_SHUTDOWN);
subsys->desc->sysmon_shutdown_ret =
sysmon_send_shutdown(subsys->desc);
+ cancel_timeout(subsys->desc);
if (subsys->desc->sysmon_shutdown_ret)
pr_debug("Graceful shutdown failed for %s\n", name);
}
@@ -1639,6 +1752,7 @@
INIT_WORK(&subsys->work, subsystem_restart_wq_func);
INIT_WORK(&subsys->device_restart_work, device_restart_work_hdlr);
spin_lock_init(&subsys->track.s_lock);
+ init_subsys_timer(desc);
subsys->id = ida_simple_get(&subsys_ida, 0, 0, GFP_KERNEL);
if (subsys->id < 0) {
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 6000707..9995a84 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -279,8 +279,11 @@
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 @@
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 802f51e..1719605 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -642,7 +642,7 @@
/* 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 7398b7b..e8a8907 100644
--- a/drivers/thermal/qpnp-temp-alarm.c
+++ b/drivers/thermal/qpnp-temp-alarm.c
@@ -586,6 +586,20 @@
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 @@
},
.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 1c70541..0475f96 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -126,6 +126,8 @@
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 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 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,13 +620,20 @@
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
* op code or a control character value.
@@ -636,6 +644,8 @@
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 @@
/* 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 @@
tail++;
}
+ not_yet_stored:
ldata->echo_tail = tail;
return old_space - space;
}
@@ -750,6 +762,7 @@
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 @@
* 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 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 @@
}
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 @@
* 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 @@
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 @@
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 @@
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 e8b34f1..a3adf21 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -1078,13 +1078,14 @@
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 @@
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 b42d7f1..41b0dd6 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -1726,10 +1726,26 @@
*/
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 @@
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,<addr>[,<options>]
+ * console=pl011,0x<addr>[,<options>]
+ * 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 <options> 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 addb287..5a341b1 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1803,7 +1803,6 @@
{
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 @@
* 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 f2ab6d8a..5609305 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -866,15 +866,12 @@
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 107f0d1..6ff53b6 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -2626,8 +2626,8 @@
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 @@
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 @@
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 9e1ac58..9d3e413 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -785,7 +785,7 @@
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 @@
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 fe22ac7..08bef18 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1712,6 +1712,9 @@
{ 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 876679a..f794741 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -763,18 +763,21 @@
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 a9b3bbd..771efc9 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -4522,7 +4522,9 @@
* 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 1375435..9669184 100644
--- a/drivers/usb/dwc2/hcd_queue.c
+++ b/drivers/usb/dwc2/hcd_queue.c
@@ -479,7 +479,7 @@
/* 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/core.h b/drivers/usb/dwc3/core.h
index 0963aa3..10ae7eb 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -256,6 +256,7 @@
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
#define DWC3_GUSB3PIPECTL_UX_EXIT_PX (1 << 27)
#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
+#define DWC3_GUSB3PIPECTL_DISRXDETU3 (1 << 22)
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1)
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 2c30660..9bcfa38 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -255,6 +255,7 @@
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 @@
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);
/**
*
@@ -2344,6 +2347,12 @@
/* Suspend SS PHY */
if (dwc->maximum_speed == USB_SPEED_SUPER) {
+ if (mdwc->in_host_mode) {
+ u32 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+ reg |= DWC3_GUSB3PIPECTL_DISRXDETU3;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ }
/* indicate phy about SS mode */
if (dwc3_msm_is_superspeed(mdwc))
mdwc->ss_phy->flags |= DEVICE_IN_SS_MODE;
@@ -2528,6 +2537,13 @@
usb_phy_set_suspend(mdwc->ss_phy, 0);
mdwc->ss_phy->flags &= ~DEVICE_IN_SS_MODE;
mdwc->lpm_flags &= ~MDWC3_SS_PHY_SUSPEND;
+
+ if (mdwc->in_host_mode) {
+ u32 reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+ reg &= ~DWC3_GUSB3PIPECTL_DISRXDETU3;
+ dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+ }
}
mdwc->hs_phy->flags &= ~(PHY_HSFS_MODE | PHY_LS_MODE);
@@ -3041,12 +3057,19 @@
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 +4171,28 @@
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 6f8a04e..32729c6 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -594,6 +594,10 @@
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/function/u_bam_dmux.c b/drivers/usb/gadget/function/u_bam_dmux.c
index 78dfe7b..7cb90e4 100644
--- a/drivers/usb/gadget/function/u_bam_dmux.c
+++ b/drivers/usb/gadget/function/u_bam_dmux.c
@@ -102,8 +102,6 @@
enum u_bam_event_type {
U_BAM_DISCONNECT_E = 0,
U_BAM_CONNECT_E,
- U_BAM_SUSPEND_E,
- U_BAM_RESUME_E
};
struct bam_ch_info {
@@ -121,9 +119,6 @@
struct work_struct write_tobam_w;
struct work_struct write_tohost_w;
- struct usb_request *rx_req;
- struct usb_request *tx_req;
-
/* stats */
unsigned int pending_pkts_with_bam;
unsigned int pending_bytes_with_bam;
@@ -143,7 +138,6 @@
};
struct gbam_port {
- bool is_connected;
enum u_bam_event_type last_event;
unsigned int port_num;
spinlock_t port_lock_ul;
@@ -164,12 +158,6 @@
struct platform_driver pdrv;
} bam_ports[BAM_DMUX_NUM_FUNCS];
-struct u_bam_data_connect_info {
- u32 usb_bam_pipe_idx;
- u32 peer_pipe_idx;
- unsigned long usb_bam_handle;
-};
-
static void gbam_start_rx(struct gbam_port *port);
static void gbam_notify(void *p, int event, unsigned long data);
static void gbam_data_write_tobam(struct work_struct *w);
@@ -1057,7 +1045,6 @@
port->port_num = func;
/* port initialization */
- port->is_connected = false;
spin_lock_init(&port->port_lock_ul);
spin_lock_init(&port->port_lock_dl);
spin_lock_init(&port->port_lock);
@@ -1355,10 +1342,6 @@
if (ret) {
pr_err("%s: usb_ep_enable failed eptype:IN ep:%pK",
__func__, gr->in);
- usb_ep_free_request(port->port_usb->out, d->rx_req);
- d->rx_req = NULL;
- usb_ep_free_request(port->port_usb->in, d->tx_req);
- d->tx_req = NULL;
goto exit;
}
gr->in->driver_data = port;
@@ -1375,10 +1358,6 @@
__func__, gr->out);
gr->in->driver_data = NULL;
usb_ep_disable(gr->in);
- usb_ep_free_request(port->port_usb->out, d->rx_req);
- d->rx_req = NULL;
- usb_ep_free_request(port->port_usb->in, d->tx_req);
- d->tx_req = NULL;
goto exit;
}
gr->out->driver_data = port;
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 2197a50..b1ae944 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -521,6 +521,13 @@
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 e2bc915..19b5f08 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2554,8 +2554,11 @@
{
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 7bbf01b..54d02ed 100644
--- a/drivers/usb/musb/musb_host.h
+++ b/drivers/usb/musb/musb_host.h
@@ -92,7 +92,7 @@
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_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 61b5f1c..71678a4 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -73,14 +73,14 @@
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 @@
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 @@
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 2c0c0ed..a9adf0b 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -533,6 +533,22 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
@@ -2302,6 +2339,7 @@
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);
@@ -2752,6 +2790,7 @@
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);
@@ -2783,6 +2822,7 @@
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);
@@ -2843,7 +2883,6 @@
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) {
@@ -3991,6 +4030,8 @@
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,
EXTCON_PROP_USB_TYPEC_POLARITY);
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 6dfca9c..a17974c 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -76,6 +76,12 @@
/* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
#define BANDGAP_BYPASS BIT(0)
+/* DEBUG_CTRL2 register value to program VSTATUS MUX for PHY status */
+#define DEBUG_CTRL2_MUX_PLL_LOCK_STATUS 0x4
+
+/* STAT5 register bits */
+#define VSTATUS_PLL_LOCK_STATUS_MASK BIT(0)
+
enum qusb_phy_reg {
PORT_TUNE1,
PLL_COMMON_STATUS_ONE,
@@ -87,6 +93,8 @@
SQ_CTRL1,
SQ_CTRL2,
DEBUG_CTRL1,
+ DEBUG_CTRL2,
+ STAT5,
USB2_PHY_REG_MAX,
};
@@ -470,6 +478,18 @@
__func__);
}
+static bool qusb_phy_pll_locked(struct qusb_phy *qphy)
+{
+ u32 val;
+
+ writel_relaxed(DEBUG_CTRL2_MUX_PLL_LOCK_STATUS,
+ qphy->base + qphy->phy_reg[DEBUG_CTRL2]);
+
+ val = readl_relaxed(qphy->base + qphy->phy_reg[STAT5]);
+
+ return (val & VSTATUS_PLL_LOCK_STATUS_MASK);
+}
+
static void qusb_phy_host_init(struct usb_phy *phy)
{
u8 reg;
@@ -748,18 +768,12 @@
writel_relaxed(intr_mask,
qphy->base + qphy->phy_reg[INTR_CTRL]);
- /* hold core PLL into reset */
- writel_relaxed(CORE_PLL_EN_FROM_RESET |
- CORE_RESET | CORE_RESET_MUX,
- qphy->base +
- qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
-
if (linestate & (LINESTATE_DP | LINESTATE_DM)) {
/* enable phy auto-resume */
writel_relaxed(0x91,
qphy->base + qphy->phy_reg[TEST1]);
- /* flush the previous write before next write */
- wmb();
+ /* Delay recommended between TEST1 writes */
+ usleep_range(10, 20);
writel_relaxed(0x90,
qphy->base + qphy->phy_reg[TEST1]);
}
@@ -788,12 +802,26 @@
writel_relaxed(0x00,
qphy->base + qphy->phy_reg[INTR_CTRL]);
- /* bring core PLL out of reset */
- writel_relaxed(CORE_PLL_EN_FROM_RESET, qphy->base +
- qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+ /* Reset PLL if needed */
+ if (!qusb_phy_pll_locked(qphy)) {
+ dev_dbg(phy->dev, "%s: reset PLL\n", __func__);
+ /* hold core PLL into reset */
+ writel_relaxed(CORE_PLL_EN_FROM_RESET |
+ CORE_RESET | CORE_RESET_MUX,
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
- /* Makes sure that above write goes through */
- wmb();
+ /* Wait for PLL to get reset */
+ usleep_range(10, 20);
+
+ /* bring core PLL out of reset */
+ writel_relaxed(CORE_PLL_EN_FROM_RESET,
+ qphy->base +
+ qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+
+ /* Makes sure that above write goes through */
+ wmb();
+ }
} else { /* Cable connect case */
qusb_phy_enable_clocks(qphy, true);
}
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 90d7c6e..71a8ede 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -33,7 +33,7 @@
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 @@
{ 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 @@
{ 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 @@
{ 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 @@
{ 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 @@
&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 @@
* 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 a96dcc6..8dd200f 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -836,6 +836,12 @@
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 ca3a5d4..fc5ed35 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -2340,6 +2340,15 @@
"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 <agk@godking.net>
+ */
+UNUSUAL_DEV(0x4971, 0x8024, 0x0000, 0x9999,
+ "SimpleTech",
+ "External HDD",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_ALWAYS_SYNC),
+
/*
* Nick Bowler <nbowler@elliptictech.com>
* SCSI stack spams (otherwise harmless) error messages.
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index 719ec68..f15aa47 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -183,3 +183,12 @@
"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 <agk@godking.net>
+ */
+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 c287ccc..e8a008d 100644
--- a/drivers/usb/usbip/vhci_sysfs.c
+++ b/drivers/usb/usbip/vhci_sysfs.c
@@ -24,6 +24,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
+/* Hardening for Spectre-v1 */
+#include <linux/nospec.h>
+
#include "usbip_common.h"
#include "vhci.h"
@@ -181,16 +184,20 @@
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 @@
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 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 @@
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 fce49eb..8b6489a 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -938,6 +938,7 @@
{
int ret = 0;
+ mutex_lock(&dev->mutex);
vhost_dev_lock_vqs(dev);
switch (msg->type) {
case VHOST_IOTLB_UPDATE:
@@ -967,6 +968,8 @@
}
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 *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 734a915..e55304d 100644
--- a/drivers/video/backlight/as3711_bl.c
+++ b/drivers/video/backlight/as3711_bl.c
@@ -262,10 +262,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* 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 7b738d6..f3aa608 100644
--- a/drivers/video/backlight/max8925_bl.c
+++ b/drivers/video/backlight/max8925_bl.c
@@ -116,7 +116,7 @@
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 @@
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 fd524ad..f45d0c9 100644
--- a/drivers/video/backlight/tps65217_bl.c
+++ b/drivers/video/backlight/tps65217_bl.c
@@ -184,11 +184,11 @@
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 2ef33d4..52bbbc4 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1219,8 +1219,6 @@
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 @@
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 a81f149..23d4a27 100644
--- a/drivers/video/fbdev/msm/mdss_compat_utils.c
+++ b/drivers/video/fbdev/msm/mdss_compat_utils.c
@@ -2879,26 +2879,28 @@
*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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 __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 @@
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 @@
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 @@
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 @@
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 @@
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_dba_utils.c b/drivers/video/fbdev/msm/mdss_dba_utils.c
index 2758a5a..f904ace 100644
--- a/drivers/video/fbdev/msm/mdss_dba_utils.c
+++ b/drivers/video/fbdev/msm/mdss_dba_utils.c
@@ -734,7 +734,6 @@
struct mdss_dba_utils_data *udata = NULL;
struct msm_dba_reg_info info;
struct cec_abstract_init_data cec_abst_init_data;
- void *cec_abst_data;
int ret = 0;
if (!uid) {
@@ -823,7 +822,7 @@
udata->cec_abst_data = cec_abstract_init(&cec_abst_init_data);
if (IS_ERR_OR_NULL(udata->cec_abst_data)) {
pr_err("error initializing cec abstract module\n");
- ret = PTR_ERR(cec_abst_data);
+ ret = PTR_ERR(udata->cec_abst_data);
goto error;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 751a463..25a2600 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -1462,6 +1462,11 @@
(mipi->vc << 8) | DTYPE_DCS_LWRITE;
stream_total = pinfo->roi.h << 16 | pinfo->roi.w;
} else {
+ width = width + pdata->panel_info.lcdc.border_left +
+ pdata->panel_info.lcdc.border_right;
+ height = height + pdata->panel_info.lcdc.border_top +
+ pdata->panel_info.lcdc.border_bottom;
+ ystride = width * bpp + 1;
stream_ctrl = (ystride << 16) | (mipi->vc << 8) |
DTYPE_DCS_LWRITE;
stream_total = height << 16 | width;
@@ -2218,7 +2223,7 @@
/* 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 78ee489..e72a315 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_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 4cfb48d..bbffc06 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -960,7 +960,7 @@
{
u32 prefill_us = 0;
u32 prefill_amortized = 0;
- struct mdss_data_type *mdata;
+ struct mdss_data_type *mdata = mdss_mdp_get_mdata();
struct mdss_mdp_mixer *mixer;
struct mdss_panel_info *pinfo;
u32 fps, v_total;
@@ -1506,7 +1506,7 @@
* 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 @@
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 @@
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 bd4ee23..e7bd94a 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_debug.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_debug.c
@@ -1140,7 +1140,7 @@
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 947a3fe..0ffe89c 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 @@
/* 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 @@
/* 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 dba3b0d..7837559 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 @@
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 @@
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 @@
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 @@
* 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 af6e4ce..7c8a273 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1754,7 +1754,7 @@
int mdss_mode_switch(struct msm_fb_data_type *mfd, u32 mode)
{
- struct mdss_rect l_roi, r_roi;
+ struct mdss_rect l_roi = {0}, r_roi = {0};
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *sctl;
@@ -3760,8 +3760,7 @@
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 @@
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 @@
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 de69d63..4e61fd8 100644
--- a/drivers/video/fbdev/msm/mdss_panel.c
+++ b/drivers/video/fbdev/msm/mdss_panel.c
@@ -633,6 +633,7 @@
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 c66d5ab..be6d44f 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -289,6 +289,7 @@
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;
@@ -927,6 +928,23 @@
}
/*
+ * 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 98af9e0..9fe0d0b 100644
--- a/drivers/video/fbdev/uvesafb.c
+++ b/drivers/video/fbdev/uvesafb.c
@@ -1059,7 +1059,8 @@
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 a462175..dacb591 100644
--- a/drivers/w1/masters/mxc_w1.c
+++ b/drivers/w1/masters/mxc_w1.c
@@ -113,6 +113,10 @@
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 @@
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 @@
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 ab0931e..aa458f2 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -741,7 +741,7 @@
/* 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 6d3b32c..1435d8c 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -637,8 +637,6 @@
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 42d8c09..b1170a7 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -636,9 +636,8 @@
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 9b4688a..f842261 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -384,8 +384,13 @@
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 @@
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 9557a31..8dc7034 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 f073de6..bd03655 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1230,6 +1230,8 @@
list_del(&sums->list);
kfree(sums);
}
+ if (ret < 0)
+ return ret;
return 1;
}
@@ -1381,10 +1383,23 @@
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 @@
* 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 @@
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 @@
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 d3dd631..cbf512b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2708,8 +2708,10 @@
}
/* 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 @@
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 @@
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 fffb9ab..16c0585 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -2519,7 +2519,7 @@
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 d572228..8407b07 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -150,8 +150,14 @@
* 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 44b7ccb..4ded64b 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -155,7 +155,7 @@
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 @@
* 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 @@
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 @@
}
if (!tcon->ses->need_reconnect && !tcon->need_reconnect)
- return rc;
+ return 0;
nls_codepage = load_nls_default();
@@ -1004,6 +1010,7 @@
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/crypto/fscrypt_ice.h b/fs/crypto/fscrypt_ice.h
index c540506..d448eae 100644
--- a/fs/crypto/fscrypt_ice.h
+++ b/fs/crypto/fscrypt_ice.h
@@ -21,7 +21,7 @@
{
if (!inode->i_sb->s_cop)
return 0;
- if (!inode->i_sb->s_cop->is_encrypted((struct inode *)inode))
+ if (!IS_ENCRYPTED((struct inode *)inode))
return 0;
return fscrypt_using_hardware_encryption(inode);
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 03ff3aa..6563f88 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -105,7 +105,8 @@
filenames_mode == FS_ENCRYPTION_MODE_SPECK128_256_CTS)
return true;
- if (contents_mode == FS_ENCRYPTION_MODE_PRIVATE)
+ if (contents_mode == FS_ENCRYPTION_MODE_PRIVATE &&
+ filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
return true;
return false;
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index 737b6fc..1866733 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -267,7 +267,7 @@
static int fscrypt_data_encryption_mode(struct inode *inode)
{
- return fscrypt_should_be_processed_by_ice(inode) ?
+ return fscrypt_is_ice_capable(inode->i_sb) ?
FS_ENCRYPTION_MODE_PRIVATE : FS_ENCRYPTION_MODE_AES_256_XTS;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 5ff9b41..3c8c1a1 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1412,7 +1412,7 @@
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 6776f4a..ad13f07 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -183,7 +183,6 @@
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 @@
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 @@
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 c175391..0647538 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -1533,11 +1533,6 @@
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 8ecf84b..a284fb2 100644
--- a/fs/ext4/ext4_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -103,6 +103,7 @@
};
#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 fb9ae76..054c385 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -881,6 +881,12 @@
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 1ee26da..6941365 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -152,7 +152,16 @@
}
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 @@
/* 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));
@@ -1307,7 +1317,10 @@
ext4_itable_unused_count(sb, gdp)),
sbi->s_inodes_per_block);
- if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) {
+ if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group) ||
+ ((group == 0) && ((EXT4_INODES_PER_GROUP(sb) -
+ ext4_itable_unused_count(sb, gdp)) <
+ EXT4_FIRST_INO(sb)))) {
ext4_error(sb, "Something is wrong with group %u: "
"used itable blocks: %d; "
"itable unused count: %u",
diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c
index bc15c2c..58229c1 100644
--- a/fs/ext4/indirect.c
+++ b/fs/ext4/indirect.c
@@ -560,10 +560,16 @@
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 4d78b93..6fde321 100644
--- a/fs/ext4/inline.c
+++ b/fs/ext4/inline.c
@@ -435,6 +435,7 @@
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 ecee29a..af9b5f6 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -379,9 +379,9 @@
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 @@
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) {
+ 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);
+
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);
-
- up_write(&EXT4_I(inode)->i_data_sem);
if (IS_SYNC(inode))
ext4_handle_sync(handle);
@@ -4311,7 +4311,8 @@
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 4beca06..0fcc336 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2444,7 +2444,8 @@
* 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 @@
#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 95bf466..eb720d9 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -1903,7 +1903,7 @@
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 23c5716..ab72207 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1180,11 +1180,6 @@
EXT4_NAME_LEN;
}
-static inline bool ext4_is_encrypted(struct inode *inode)
-{
- return ext4_encrypted_inode(inode);
-}
-
static const struct fscrypt_operations ext4_cryptops = {
.key_prefix = "ext4:",
.get_context = ext4_get_context,
@@ -1192,7 +1187,6 @@
.dummy_context = ext4_dummy_context,
.empty_dir = ext4_empty_dir,
.max_namelen = ext4_max_namelen,
- .is_encrypted = ext4_is_encrypted,
};
#endif
@@ -2247,6 +2241,7 @@
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 +2274,14 @@
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 +2296,14 @@
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 +2318,14 @@
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,6 +3033,9 @@
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)
@@ -3638,6 +3660,13 @@
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 +3724,11 @@
} 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 +3805,6 @@
"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 +3825,10 @@
}
} 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 +3882,13 @@
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 +3924,14 @@
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 +4630,14 @@
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/data.c b/fs/f2fs/data.c
index 9efe77e..062529c 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1548,9 +1548,9 @@
bio = NULL;
goto set_error_page;
}
+ if (bio_encrypted)
+ fscrypt_set_ice_dun(inode, bio, dun);
}
- if (bio_encrypted)
- fscrypt_set_ice_dun(inode, bio, dun);
if (bio_add_page(bio, page, blocksize, 0) < blocksize)
goto submit_and_realloc;
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 98fe1ed..f04781b 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -2439,9 +2439,18 @@
__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/f2fs/super.c b/fs/f2fs/super.c
index a7711d7..c850618 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1344,6 +1344,8 @@
seq_printf(seq, ",fsync_mode=%s", "posix");
else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
seq_printf(seq, ",fsync_mode=%s", "strict");
+ else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_NOBARRIER)
+ seq_printf(seq, ",fsync_mode=%s", "nobarrier");
return 0;
}
@@ -1940,11 +1942,6 @@
inode->i_sb->s_blocksize : F2FS_NAME_LEN;
}
-static inline bool f2fs_is_encrypted(struct inode *inode)
-{
- return f2fs_encrypted_file(inode);
-}
-
static const struct fscrypt_operations f2fs_cryptops = {
.key_prefix = "f2fs:",
.get_context = f2fs_get_context,
@@ -1952,7 +1949,6 @@
.dummy_context = f2fs_dummy_context,
.empty_dir = f2fs_empty_dir,
.max_namelen = f2fs_max_namelen,
- .is_encrypted = f2fs_is_encrypted,
};
#endif
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 6e22748..e25c40c 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -211,10 +211,11 @@
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 @@
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 @@
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 1693308..5dcba9e 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1682,8 +1682,19 @@
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 8aa98b1..c506fa9 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -1190,6 +1190,7 @@
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 9e9e093..b320c1b 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -1353,6 +1353,13 @@
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 @@
* 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 e9aa235e..2e7ebd9 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -402,11 +402,8 @@
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 eaac878..b5f02f1 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -343,7 +343,7 @@
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 @@
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 2c4f7a2..bdbd9e6 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -3638,7 +3638,8 @@
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 @@
/* 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 561497a..5fe4586 100644
--- a/fs/orangefs/namei.c
+++ b/fs/orangefs/namei.c
@@ -312,6 +312,13 @@
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 fafc09c..30d4db2 100644
--- a/fs/sdcardfs/inode.c
+++ b/fs/sdcardfs/inode.c
@@ -270,6 +270,7 @@
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 @@
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 7d764e3..504658f 100644
--- a/fs/ubifs/journal.c
+++ b/fs/ubifs/journal.c
@@ -1265,7 +1265,7 @@
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 988d535..48ef184 100644
--- a/fs/udf/directory.c
+++ b/fs/udf/directory.c
@@ -150,6 +150,9 @@
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 c3702cd..e567551 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -2035,6 +2035,93 @@
}
/*
+ * 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 @@
}
}
+ /* 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 @@
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 @@
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 @@
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 5415f90..7cb099e 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -368,6 +368,7 @@
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 bdf69e1..42a7c0d 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1516,7 +1516,7 @@
__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 @@
__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 d3052b4..9f91d48 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -916,8 +916,8 @@
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 eba9285..a6d1bf2 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 81bcdca..7385c7f 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -113,7 +113,7 @@
#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 a9a16f2..94c7be2 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/fscrypt.h b/include/linux/fscrypt.h
index 8f4e90c..7a7fce9 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -19,12 +19,9 @@
struct fscrypt_ctx;
-/* iv sector for security/pfe/pfk_fscrypt.c and f2fs. sizeof is required
- * to accommodate 32 bit targets.
- */
+/* iv sector for security/pfe/pfk_fscrypt.c and f2fs */
#define PG_DUN(i, p) \
- ((((i)->i_ino & 0xffffffff) << (sizeof((i)->i_ino)/2)) | \
- ((p)->index & 0xffffffff))
+ (((((u64)(i)->i_ino) & 0xffffffff) << 32) | ((p)->index & 0xffffffff))
struct fscrypt_info;
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
index 32e2b6c..2f62d5b 100644
--- a/include/linux/fscrypt_supp.h
+++ b/include/linux/fscrypt_supp.h
@@ -29,7 +29,6 @@
bool (*dummy_context)(struct inode *);
bool (*empty_dir)(struct inode *);
unsigned (*max_namelen)(struct inode *);
- bool (*is_encrypted)(struct inode *);
};
struct fscrypt_ctx {
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index 70a5164..821965c 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -61,7 +61,7 @@
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 @@
* @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 44fda64..d0826f1 100644
--- a/include/linux/kernel_stat.h
+++ b/include/linux/kernel_stat.h
@@ -33,6 +33,7 @@
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 9d5d808..e7b9652 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -269,6 +269,11 @@
/* 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 @@
/*
* 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 6fe4a4e..08e34b6 100644
--- a/include/linux/msm_gpi.h
+++ b/include/linux/msm_gpi.h
@@ -151,6 +151,12 @@
#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 0000000..b96591b
--- /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 <linux/types.h>
+#include <linux/dma-mapping.h>
+
+#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 9412480..4c07788 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -302,6 +302,7 @@
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/skbuff.h b/include/linux/skbuff.h
index 3fbfe96..6b20f91 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2986,6 +2986,8 @@
return __skb_grow(skb, len);
}
+#define rb_to_skb(rb) rb_entry_safe(rb, struct sk_buff, rbnode)
+
#define skb_queue_walk(queue, skb) \
for (skb = (queue)->next; \
skb != (struct sk_buff *)(queue); \
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index fc11641..b8ea15a 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -338,7 +338,7 @@
/* 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 3f3a7e4..0267bed 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -539,6 +539,7 @@
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 7734cc9..714428c 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -277,6 +277,11 @@
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 368d01e..3b864fc 100644
--- a/include/net/cnss.h
+++ b/include/net/cnss.h
@@ -102,11 +102,14 @@
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 @@
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 342907d..c5ccee4 100644
--- a/include/net/cnss2.h
+++ b/include/net/cnss2.h
@@ -159,6 +159,9 @@
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 31b4cce..7ef3db4 100644
--- a/include/soc/qcom/icnss.h
+++ b/include/soc/qcom/icnss.h
@@ -142,5 +142,6 @@
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/soc/qcom/subsystem_restart.h b/include/soc/qcom/subsystem_restart.h
index 9a0a53e..c1c1386 100644
--- a/include/soc/qcom/subsystem_restart.h
+++ b/include/soc/qcom/subsystem_restart.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,6 +35,30 @@
struct device;
struct module;
+enum ssr_comm {
+ SUBSYS_TO_SUBSYS_SYSMON,
+ SUBSYS_TO_HLOS,
+ HLOS_TO_SUBSYS_SYSMON_SHUTDOWN,
+ NUM_SSR_COMMS,
+};
+
+/**
+ * struct subsys_notif_timeout - timeout data used by notification timeout hdlr
+ * @comm_type: Specifies if the type of communication being tracked is
+ * through sysmon between two subsystems, subsystem notifier call chain, or
+ * sysmon shutdown.
+ * @dest_name: subsystem to which sysmon notification is being sent to
+ * @source_name: subsystem which generated event that notification is being sent
+ * for
+ * @timer: timer for scheduling timeout
+ */
+struct subsys_notif_timeout {
+ enum ssr_comm comm_type;
+ const char *dest_name;
+ const char *source_name;
+ struct timer_list timer;
+};
+
/**
* struct subsys_desc - subsystem descriptor
* @name: name of subsystem
@@ -95,6 +119,9 @@
bool system_debug;
bool ignore_ssr_failure;
const char *edge;
+#ifdef CONFIG_SETUP_SSR_NOTIF_TIMEOUTS
+ struct subsys_notif_timeout timeout_data;
+#endif /* CONFIG_SETUP_SSR_NOTIF_TIMEOUTS */
};
/**
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index b355ebf..b3ec962 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -657,6 +657,10 @@
__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 @@
__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 @@
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 @@
__field( int, best_idle )
__field( int, best_active )
__field( int, target )
+ __field( int, backup_cpu )
),
TP_fast_assign(
@@ -1662,14 +1672,16 @@
__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 d5ad15a..c794c9a 100644
--- a/include/uapi/linux/btrfs_tree.h
+++ b/include/uapi/linux/btrfs_tree.h
@@ -452,6 +452,7 @@
#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 be4cb02..bd9836c 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -520,7 +520,13 @@
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)
/**
@@ -580,6 +586,9 @@
* @IPA_HW_v3_5: IPA hardware version 3.5
* @IPA_HW_v3_5_1: IPA hardware version 3.5.1
* @IPA_HW_v4_0: IPA hardware version 4.0
+ * @IPA_HW_v4_1: IPA hardware version 4.1
+ * @IPA_HW_v4_2: IPA hardware version 4.2
+ * @IPA_HW_v4_5: IPA hardware version 4.5
*/
enum ipa_hw_type {
IPA_HW_None = 0,
@@ -595,10 +604,16 @@
IPA_HW_v3_5 = 12,
IPA_HW_v3_5_1 = 13,
IPA_HW_v4_0 = 14,
+ IPA_HW_v4_1 = 15,
+ IPA_HW_v4_2 = 16,
+ IPA_HW_v4_5 = 17,
};
-#define IPA_HW_MAX (IPA_HW_v4_0 + 1)
+#define IPA_HW_MAX (IPA_HW_v4_5 + 1)
#define IPA_HW_v4_0 IPA_HW_v4_0
+#define IPA_HW_v4_1 IPA_HW_v4_1
+#define IPA_HW_v4_2 IPA_HW_v4_2
+#define IPA_HW_v4_5 IPA_HW_v4_5
/**
* struct ipa_rule_attrib - attributes of a routing/filtering
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 20a01ca..8143af6 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2603,7 +2603,7 @@
#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 40882a7..54aa362 100644
--- a/include/uapi/linux/qg.h
+++ b/include/uapi/linux/qg.h
@@ -20,7 +20,7 @@
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 @@
#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 1aa2a19..7f93c1c 100644
--- a/include/uapi/media/Kbuild
+++ b/include/uapi/media/Kbuild
@@ -26,5 +26,6 @@
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/msmb_qca.h b/include/uapi/media/msmb_qca.h
new file mode 100644
index 0000000..22b1006
--- /dev/null
+++ b/include/uapi/media/msmb_qca.h
@@ -0,0 +1,49 @@
+#ifndef __UAPI_LINUX_MSMB_QCA402X_H
+#define __UAPI_LINUX_MSMB_QCA402X_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#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 13ad2f8..8a84031 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2156,6 +2156,11 @@
/* 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 @@
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 16bab47..5fa65aa 100644
--- a/kernel/printk/nmi.c
+++ b/kernel/printk/nmi.c
@@ -63,6 +63,7 @@
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 @@
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 b71f116..dc9518b 100644
--- a/kernel/sched/cpufreq_schedutil.c
+++ b/kernel/sched/cpufreq_schedutil.c
@@ -365,11 +365,10 @@
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 @@
* 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 @@
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 50f2ea8..a7c4b4c 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -84,12 +84,19 @@
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 77d8361..01daf82 100644
--- a/kernel/sched/energy.c
+++ b/kernel/sched/energy.c
@@ -25,6 +25,7 @@
#include <linux/sched_energy.h>
#include <linux/stddef.h>
#include <linux/cpu.h>
+#include <linux/cpuset.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
@@ -49,6 +50,17 @@
}
}
+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 @@
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 38fed13..335b40e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6194,13 +6194,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
? 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 @@
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 @@
&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 @@
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 @@
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 @@
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 @@
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) {
@@ -10522,8 +10540,12 @@
rcu_read_lock();
sd = rcu_dereference_check_sched_domain(rq->sd);
if (sd) {
- cpumask_and(&cpumask, nohz.idle_cpus_mask,
- sched_domain_span(sd));
+ if (energy_aware() && rq->misfit_task)
+ cpumask_andnot(&cpumask, nohz.idle_cpus_mask,
+ sched_domain_span(sd));
+ else
+ cpumask_and(&cpumask, nohz.idle_cpus_mask,
+ sched_domain_span(sd));
cpumask_andnot(&cpumask, &cpumask,
cpu_isolated_mask);
ilb = cpumask_first(&cpumask);
@@ -10534,7 +10556,7 @@
if (!energy_aware() ||
(capacity_orig_of(cpu) ==
cpu_rq(cpu)->rd->max_cpu_capacity.val ||
- cpu_overutilized(cpu))) {
+ (cpu_overutilized(cpu) && rq->nr_running > 1))) {
cpumask_andnot(&cpumask, nohz.idle_cpus_mask,
cpu_isolated_mask);
ilb = cpumask_first(&cpumask);
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 44c767a..95b68bd 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1805,7 +1805,6 @@
}
}
} while (sg = sg->next, sg != sd->groups);
- rcu_read_unlock();
if (sg_target) {
cpumask_and(&search_cpu, lowest_mask,
@@ -1894,6 +1893,7 @@
}
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 @@
placement_boost = SCHED_BOOST_NONE;
goto retry;
}
+ rcu_read_unlock();
}
noea:
diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c
index 192e8c7..a8fab0c 100644
--- a/kernel/sched/tune.c
+++ b/kernel/sched/tune.c
@@ -110,6 +110,64 @@
/*
* 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 @@
* 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 @@
/* 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 @@
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 @@
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 @@
{ } /* 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 @@
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 @@
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 @@
{
struct schedtune *st = css_st(css);
+ /* Release per CPUs boost group support */
schedtune_boostgroup_release(st);
kfree(st);
}
@@ -930,6 +1000,7 @@
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 4fe1181..4afefd6 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -87,11 +87,16 @@
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 @@
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 @@
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 1b2d209..15f3487 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -28,6 +28,7 @@
*/
#include <linux/export.h>
+#include <linux/kernel.h>
#include <linux/timex.h>
#include <linux/capability.h>
#include <linux/timekeeper_internal.h>
@@ -258,9 +259,10 @@
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/time/timekeeping.c b/kernel/time/timekeeping.c
index 427e33d..5659b40 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -1511,8 +1511,20 @@
ts->tv_nsec = 0;
}
-/* Flag for if timekeeping_resume() has injected sleeptime */
-static bool sleeptime_injected;
+/*
+ * Flag reflecting whether timekeeping_resume() has injected sleeptime.
+ *
+ * The flag starts of false and is only set when a suspend reaches
+ * timekeeping_suspend(), timekeeping_resume() sets it to false when the
+ * timekeeper clocksource is not stopping across suspend and has been
+ * used to update sleep time. If the timekeeper clocksource has stopped
+ * then the flag stays true and is used by the RTC resume code to decide
+ * whether sleeptime must be injected and if so the flag gets false then.
+ *
+ * If a suspend fails before reaching timekeeping_resume() then the flag
+ * stays false and prevents erroneous sleeptime injection.
+ */
+static bool suspend_timing_needed;
/* Flag for if there is a persistent clock on this platform */
static bool persistent_clock_exists;
@@ -1611,7 +1623,7 @@
*/
bool timekeeping_rtc_skipresume(void)
{
- return sleeptime_injected;
+ return !suspend_timing_needed;
}
/**
@@ -1647,6 +1659,8 @@
raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq);
+ suspend_timing_needed = false;
+
timekeeping_forward_now(tk);
__timekeeping_inject_sleeptime(tk, delta);
@@ -1671,8 +1685,8 @@
unsigned long flags;
struct timespec64 ts_new, ts_delta;
cycle_t cycle_now, cycle_delta;
+ bool inject_sleeptime = false;
- sleeptime_injected = false;
read_persistent_clock64(&ts_new);
clockevents_resume();
@@ -1718,14 +1732,16 @@
nsec += ((u64) cycle_delta * mult) >> shift;
ts_delta = ns_to_timespec64(nsec);
- sleeptime_injected = true;
+ inject_sleeptime = true;
} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
- sleeptime_injected = true;
+ inject_sleeptime = true;
}
- if (sleeptime_injected)
+ if (inject_sleeptime) {
+ suspend_timing_needed = false;
__timekeeping_inject_sleeptime(tk, &ts_delta);
+ }
/* Re-base the last cycle value */
tk->tkr_mono.cycle_last = cycle_now;
@@ -1760,6 +1776,8 @@
if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
persistent_clock_exists = true;
+ suspend_timing_needed = true;
+
raw_spin_lock_irqsave(&timekeeper_lock, flags);
write_seqcount_begin(&tk_core.seq);
timekeeping_forward_now(tk);
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 6721a1e8..88f398a 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -481,9 +481,10 @@
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 3cb38f1..7461d51 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -835,6 +835,7 @@
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 @@
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 @@
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 59b482f..de63dab 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -804,10 +804,9 @@
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 640818c..4fc6d8f 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -113,6 +113,18 @@
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 0967771..79ba3cc 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -1391,9 +1391,6 @@
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 e97ad01..1ccfaa1 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -466,7 +466,8 @@
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 6ff65c4..f9e7355 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2171,6 +2171,7 @@
*/
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 f549597..9ba15d8 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1398,6 +1398,35 @@
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 @@
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 1345072..c9f73d6 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3778,7 +3778,6 @@
* 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 7b3865c..6b5f0bc 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -543,7 +543,7 @@
}
}
- if (printk_ratelimit())
+ if (!(gfp_mask & __GFP_NOWARN) && printk_ratelimit())
pr_warn("vmap allocation for size %lu failed: use vmalloc=<size> to increase size\n",
size);
kfree(va);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 4daac9a..abcc8be 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1455,7 +1455,7 @@
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 0a9222e..da3d373 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -1923,7 +1923,8 @@
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/neighbour.c b/net/core/neighbour.c
index 59c1581..340a3db 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -889,12 +889,9 @@
now = jiffies;
next = now + HZ;
- if (!(state & NUD_IN_TIMER)) {
- if (neigh_probe_enable && (state & NUD_STALE))
- neigh_dbg(2, "neigh %pK is still alive\n", neigh);
- else
- goto out;
- }
+ if (!(state & NUD_IN_TIMER))
+ goto out;
+
if (state & NUD_REACHABLE) {
if (time_before_eq(now,
neigh->confirmed + neigh->parms->reachable_time)) {
@@ -1185,10 +1182,7 @@
neigh_del_timer(neigh);
if (new & NUD_PROBE)
atomic_set(&neigh->probes, 0);
- if (new & NUD_IN_TIMER || (
- neigh_probe_enable &&
- (neigh->tbl->family == AF_INET6) &&
- (new & NUD_STALE)))
+ if (new & NUD_IN_TIMER)
neigh_add_timer(neigh, (jiffies +
((new & NUD_REACHABLE) ?
neigh->parms->reachable_time :
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index c2339b8..f3a0ad1 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1914,6 +1914,10 @@
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 @@
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 ff3b058..936dab1 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -280,9 +280,7 @@
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_socket.c b/net/ipc_router/ipc_router_socket.c
index a758a09..4e53861 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 @@
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 @@
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 e1be244..a88dab3 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -979,6 +979,8 @@
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 5ddd649..dd80276 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -503,8 +503,6 @@
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 c2ad59d..c244b72 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -582,8 +582,8 @@
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 @@
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 @@
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;
@@ -4907,6 +4909,7 @@
static void tcp_collapse_ofo_queue(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
+ u32 range_truesize, sum_tiny = 0;
struct sk_buff *skb, *head;
struct rb_node *p;
u32 start, end;
@@ -4925,6 +4928,7 @@
}
start = TCP_SKB_CB(skb)->seq;
end = TCP_SKB_CB(skb)->end_seq;
+ range_truesize = skb->truesize;
for (head = skb;;) {
skb = tcp_skb_next(skb, NULL);
@@ -4935,11 +4939,20 @@
if (!skb ||
after(TCP_SKB_CB(skb)->seq, end) ||
before(TCP_SKB_CB(skb)->end_seq, start)) {
- tcp_collapse(sk, NULL, &tp->out_of_order_queue,
- head, skb, start, end);
+ /* Do not attempt collapsing tiny skbs */
+ if (range_truesize != head->truesize ||
+ end - start >= SKB_WITH_OVERHEAD(SK_MEM_QUANTUM)) {
+ tcp_collapse(sk, NULL, &tp->out_of_order_queue,
+ head, skb, start, end);
+ } else {
+ sum_tiny += range_truesize;
+ if (sum_tiny > sk->sk_rcvbuf >> 3)
+ return;
+ }
goto new_range;
}
+ range_truesize += skb->truesize;
if (unlikely(before(TCP_SKB_CB(skb)->seq, start)))
start = TCP_SKB_CB(skb)->seq;
if (after(TCP_SKB_CB(skb)->end_seq, end))
@@ -4954,6 +4967,7 @@
* 2) not add too big latencies if thousands of packets sit there.
* (But if application shrinks SO_RCVBUF, we could still end up
* freeing whole queue here)
+ * 3) Drop at least 12.5 % of sk_rcvbuf to avoid malicious attacks.
*
* Return true if queue has shrunk.
*/
@@ -4961,20 +4975,26 @@
{
struct tcp_sock *tp = tcp_sk(sk);
struct rb_node *node, *prev;
+ int goal;
if (RB_EMPTY_ROOT(&tp->out_of_order_queue))
return false;
NET_INC_STATS(sock_net(sk), LINUX_MIB_OFOPRUNED);
+ goal = sk->sk_rcvbuf >> 3;
node = &tp->ooo_last_skb->rbnode;
do {
prev = rb_prev(node);
rb_erase(node, &tp->out_of_order_queue);
+ goal -= rb_to_skb(node)->truesize;
tcp_drop(sk, rb_entry(node, struct sk_buff, rbnode));
- sk_mem_reclaim(sk);
- if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
- !tcp_under_memory_pressure(sk))
- break;
+ if (!prev || goal <= 0) {
+ sk_mem_reclaim(sk);
+ if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf &&
+ !tcp_under_memory_pressure(sk))
+ break;
+ goal = sk->sk_rcvbuf >> 3;
+ }
node = prev;
} while (node);
tp->ooo_last_skb = rb_entry(prev, struct sk_buff, rbnode);
@@ -5009,6 +5029,9 @@
else if (tcp_under_memory_pressure(sk))
tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss);
+ if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf)
+ return 0;
+
tcp_collapse_ofo_queue(sk);
if (!skb_queue_empty(&sk->sk_receive_queue))
tcp_collapse(sk, &sk->sk_receive_queue, NULL,
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 71335ac..0f457be 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1669,6 +1669,10 @@
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 0b5a75b..ae5e38b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -496,7 +496,8 @@
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 a30e7e9..4b93ad4 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1789,7 +1789,8 @@
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 52236be..984d48b 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1540,6 +1540,12 @@
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 0fbc5ba..efe939d 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1364,9 +1364,6 @@
{
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 ae0485d..fc7ca1e 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -659,7 +659,6 @@
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 8efeff6..ed5d635 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1436,6 +1436,10 @@
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 4003b28..d82f427 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -124,7 +124,7 @@
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 cc306de..553d0ad 100644
--- a/net/kcm/kcmsock.c
+++ b/net/kcm/kcmsock.c
@@ -1671,7 +1671,7 @@
__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 15150b4..3ba903f 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -437,6 +437,24 @@
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 @@
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 @@
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 c5f2350..079b3c4 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2390,8 +2390,10 @@
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 @@
}
}
+ 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_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 @@
[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 ffb9e8a..e02fed7 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -444,14 +444,17 @@
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 0dd5c69..9d593ec 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -185,7 +185,8 @@
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 d2141a6..7f51f6d 100644
--- a/net/netfilter/xt_qtaguid.c
+++ b/net/netfilter/xt_qtaguid.c
@@ -1191,11 +1191,6 @@
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 3ec89bb..8ab2b53 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -4299,7 +4299,7 @@
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 289af6f..8b2e87e 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -55,22 +55,22 @@
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 @@
struct tcf_defact *d;
bool exists = false;
int ret = 0, err;
- char *defdata;
if (nla == NULL)
return -EINVAL;
@@ -112,8 +111,6 @@
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 @@
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 @@
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 ce54dce..03d71cd 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -608,7 +608,7 @@
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/db.txt b/net/wireless/db.txt
index d82f8b4..38fbe09 100644
--- a/net/wireless/db.txt
+++ b/net/wireless/db.txt
@@ -653,7 +653,7 @@
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)
@@ -1043,6 +1043,7 @@
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
(5490 - 5710 @ 160), (30), DFS
+ (5735 - 5835 @ 80), (30)
country SE: DFS-ETSI
(2402 - 2482 @ 40), (20)
@@ -1138,10 +1139,11 @@
(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), AUTO-BW
+ (5250 - 5330 @ 80), (24), DFS, AUTO-BW
+ (5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
# 60 gHz band channels 1-3, FCC
(57240 - 63720 @ 2160), (40)
@@ -1214,7 +1216,7 @@
(5735 - 5875 @ 80), (14)
country VE: DFS-FCC
- (2402 - 2482 @ 40), (20)
+ (2402 - 2482 @ 40), (30)
(5170 - 5250 @ 80), (23), AUTO-BW
(5250 - 5330 @ 80), (23), DFS, AUTO-BW
(5735 - 5835 @ 80), (30)
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 0f101f7..b1cdd50 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -8,6 +8,7 @@
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 @@
# 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 a9c1da5..fcffce4 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -296,6 +296,9 @@
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 297b079..27aac27 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -745,7 +745,7 @@
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 7bf8b00..1e6f23f7 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -389,14 +389,10 @@
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 e1d0100..a86042c 100644
--- a/security/pfe/pfk_ice.c
+++ b/security/pfe/pfk_ice.c
@@ -138,9 +138,10 @@
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 0af1132..56af730 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -748,8 +748,10 @@
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 b3851b9..6b5804e 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -851,6 +851,8 @@
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 39cd35f..f03a143 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -333,6 +333,7 @@
case 0x10ec0236:
case 0x10ec0255:
case 0x10ec0256:
+ case 0x10ec0257:
case 0x10ec0282:
case 0x10ec0283:
case 0x10ec0286:
@@ -2447,6 +2448,7 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
},
[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 @@
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 @@
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 85962657..517963e 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -67,7 +67,7 @@
.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 934f8ae..0dc3852 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 @@
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 @@
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 98089df..c6737a5 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -72,7 +72,7 @@
.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 a086c35..79a9fdf 100644
--- a/sound/soc/intel/common/sst-firmware.c
+++ b/sound/soc/intel/common/sst-firmware.c
@@ -274,7 +274,6 @@
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 @@
* 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 172af54..682c207 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -427,6 +427,8 @@
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/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h
index c278f27..aea30af 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 1dcb95e..b816554 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 @@
###
# 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 d3102c8..914cff1 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 e6acc28..8ae824d 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -35,7 +35,7 @@
LDFLAGS += -lelf $(LIBSUBCMD)
# Allow old libelf to be used:
-elfshdr := $(shell echo '\#include <libelf.h>' | $(CC) $(CFLAGS) -x c -E - | grep elf_getshdr)
+elfshdr := $(shell echo '$(pound)include <libelf.h>' | $(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 d2c6cdd..8bec053 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -253,6 +253,8 @@
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 cac3953..d27715f 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
{
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 @@
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 @@
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 9ae4df1..2fe8f4c 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 @@
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 @@
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 7528ae4..e5c6caf 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 @@
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 b1161d7..d40ab4c 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -752,6 +752,7 @@
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 @@
}
}
+ 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 @@
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 19edc1a..7ea4438 100644
--- a/tools/scripts/Makefile.include
+++ b/tools/scripts/Makefile.include
@@ -92,3 +92,5 @@
QUIET_INSTALL = @printf ' INSTALL %s\n' $1;
endif
endif
+
+pound := \#