Merge "arm64: Silence first allocation with CONFIG_ARM64_MODULE_PLTS=y"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..4341e3a
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,27 @@
+cc_binary_host {
+ name: "unifdef",
+ srcs: ["scripts/unifdef.c"],
+ sanitize: {
+ never: true,
+ }
+}
+
+gensrcs {
+ name: "qseecom-kernel-includes",
+
+ // move to out/ as root for header generation because of scripts/unifdef
+ // storage - at the expense of extra ../ references
+ cmd: "pushd out && mkdir -p scripts && rm -f scripts/unifdef && ln -s ../../$(location unifdef) scripts/unifdef && ../$(location scripts/headers_install.sh) `dirname ../$(out)` ../ $(in) && popd",
+
+ tools: ["unifdef"],
+ tool_files: ["scripts/headers_install.sh"],
+ export_include_dirs: ["include/uapi"],
+ srcs: ["include/uapi/linux/qseecom.h"],
+ output_extension: "h",
+}
+
+cc_library_headers {
+ name: "qseecom-kernel-headers",
+ generated_headers: ["qseecom-kernel-includes"],
+ export_generated_headers: ["qseecom-kernel-includes"],
+}
diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs
index db7aab1..b8d0a30 100644
--- a/Documentation/ABI/testing/sysfs-fs-f2fs
+++ b/Documentation/ABI/testing/sysfs-fs-f2fs
@@ -192,3 +192,14 @@
Contact: "Sheng Yong" <shengyong1@huawei.com>
Description:
Controls readahead inode block in readdir.
+
+What: /sys/fs/f2fs/<disk>/extension_list
+Date: Feburary 2018
+Contact: "Chao Yu" <yuchao0@huawei.com>
+Description:
+ Used to control configure extension list:
+ - Query: cat /sys/fs/f2fs/<disk>/extension_list
+ - Add: echo '[h/c]extension' > /sys/fs/f2fs/<disk>/extension_list
+ - Del: echo '[h/c]!extension' > /sys/fs/f2fs/<disk>/extension_list
+ - [h] means add/del hot file extension
+ - [c] means add/del cold file extension
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
index 89fd8f9..b3d2e4a 100644
--- a/Documentation/device-mapper/verity.txt
+++ b/Documentation/device-mapper/verity.txt
@@ -109,6 +109,17 @@
This is the offset, in <data_block_size> blocks, from the start of the
FEC device to the beginning of the encoding data.
+check_at_most_once
+ 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.
Theory of operation
===================
diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt
index bda03f0..3a96610 100644
--- a/Documentation/devicetree/bindings/arm/coresight.txt
+++ b/Documentation/devicetree/bindings/arm/coresight.txt
@@ -1,222 +1,12 @@
* CoreSight Components:
CoreSight components are compliant with the ARM CoreSight architecture
-specification and can be connected in various topologies to suite a particular
-SoCs tracing needs. These trace components can generally be classified as sinks,
-links and sources. Trace data produced by one or more sources flows through the
-intermediate links connecting the source to the currently selected sink. Each
-CoreSight component device should use these properties to describe its hardware
-characteristcs.
-
-Required properties:
-
-- compatible : name of the component used for driver matching, should be one of
- the following:
- "arm,coresight-tmc" for coresight tmc-etr or tmc-etf device,
- "arm,coresight-tpiu" for coresight tpiu device,
- "qcom,coresight-replicator" for coresight replicator device,
- "arm,coresight-funnel" for coresight funnel devices,
- "qcom,coresight-tpda" for coresight tpda device,
- "qcom,coresight-tpdm" for coresight tpdm device,
- "qcom,coresight-dbgui" for coresight dbgui device
- "arm,coresight-stm" for coresight stm trace device,
- "arm,coresight-etm" for coresight etm trace devices,
- "arm,coresight-etmv4" for coresight etmv4 trace devices,
- "qcom,coresight-csr" for coresight csr device,
- "arm,coresight-cti" for coresight cti devices,
- "qcom,coresight-hwevent" for coresight hardware event devices
- "arm,coresight-fuse" for coresight fuse v1 device,
- "arm,coresight-fuse-v2" for coresight fuse v2 device,
- "arm,coresight-fuse-v3" for coresight fuse v3 device,
- "qcom,coresight-remote-etm" for coresight remote processor etm trace device,
- "qcom,coresight-qpdi" for coresight qpdi device
-- reg : physical base address and length of the register set(s) of the component.
- Not required for the following compatible string:
- - "qcom,coresight-remote-etm"
-- reg-names : names corresponding to each reg property value.
- Not required for the following compatible string:
- - "qcom,coresight-remote-etm"
- The reg-names that need to be used with corresponding compatible string
- for a coresight device are:
- - for coresight tmc-etr or tmc-etf device:
- compatible : should be "arm,coresight-tmc"
- reg-names : should be:
- "tmc-base" - physical base address of tmc configuration
- registers
- "bam-base" - physical base address of tmc-etr bam registers
- - for coresight tpiu device:
- compatible : should be "arm,coresight-tpiu"
- reg-names : should be:
- "tpiu-base" - physical base address of tpiu registers
- - for coresight replicator device
- compatible : should be "qcom,coresight-replicator"
- reg-names : should be:
- "replicator-base" - physical base address of replicator
- registers
- - for coresight funnel devices
- compatible : should be "arm,coresight-funnel"
- reg-names : should be:
- "funnel-base" - physical base address of funnel registers
- - for coresight tpda trace device
- compatible : should be "qcom,coresight-tpda"
- reg-names : should be:
- "tpda-base" - physical base address of tpda registers
- - for coresight tpdm trace device
- compatible : should be "qcom,coresight-tpdm"
- reg-names : should be:
- "tpdm-base" - physical base address of tpdm registers
- - for coresight dbgui device:
- compatible : should be "qcom,coresight-dbgui"
- reg-names : should be:
- "dbgui-base" - physical base address of dbgui registers
- - for coresight stm trace device
- compatible : should be "arm,coresight-stm"
- reg-names : should be:
- "stm-base" - physical base address of stm configuration
- registers
- "stm-data-base" - physical base address of stm data registers
- - for coresight etm trace devices
- compatible : should be "arm,coresight-etm"
- reg-names : should be:
- "etm-base" - physical base address of etm registers
- - for coresight etmv4 trace devices
- compatible : should be "arm,coresight-etmv4"
- reg-names : should be:
- "etm-base" - physical base address of etmv4 registers
- - for coresight csr device:
- compatible : should be "qcom,coresight-csr"
- reg-names : should be:
- "csr-base" - physical base address of csr registers
- - for coresight cti devices:
- compatible : should be "arm,coresight-cti"
- reg-names : should be:
- "cti<num>-base" - physical base address of cti registers
- - for coresight hardware event devices:
- compatible : should be "qcom,coresight-hwevent"
- reg-names : should be:
- "<ss-mux>" - physical base address of hardware event mux
- control registers where <ss-mux> is subsystem mux it
- represents
- - for coresight fuse device:
- compatible : should be "arm,coresight-fuse"
- reg-names : should be:
- "fuse-base" - physical base address of fuse registers
- "nidnt-fuse-base" - physical base address of nidnt fuse registers
- "qpdi-fuse-base" - physical base address of qpdi fuse registers
- - for coresight qpdi device:
- compatible : should be "qcom,coresight-qpdi"
- reg-names : should be:
- "qpdi-base" - physical base address of qpdi registers
-- coresight-id : unique integer identifier for the component
-- coresight-name : unique descriptive name of the component
-- coresight-nr-inports : number of input ports on the component
-
-Optional properties:
-
-- coresight-outports : list of output port numbers of this component
-- coresight-child-list : list of phandles pointing to the children of this
- component
-- coresight-child-ports : list of input port numbers of the children
-- coresight-default-sink : represents the default compile time CoreSight sink
-- coresight-ctis : list of ctis that this component interacts with
-- qcom,cti-save : boolean, indicating cti context needs to be saved and restored
-- qcom,cti-hwclk : boolean, indicating support of hardware clock to access cti
- registers to be saved and restored
-- qcom,cti-gpio-trigin : cti trigger input driven by gpio
-- qcom,cti-gpio-trigout : cti trigger output sent to gpio
-- qcom,pc-save : program counter save implemented
-- qcom,blk-size : block size for tmc-etr to usb transfers
-- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer
-- qcom,round-robin : indicates if per core etms are allowed round-robin access
- by the funnel
-- qcom,write-64bit : only 64bit data writes supported by stm
-- qcom,data-barrier : barrier required for every stm data write to channel space
-- <supply-name>-supply: phandle to the regulator device tree node. The required
- <supply-name> is "vdd" for SD card and "vdd-io" for SD
- I/O supply. Used for tpiu component
-- qcom,<supply>-voltage-level : specifies voltage level for vdd supply. Should
- be specified in pairs (min, max) with units
- being uV. Here <supply> can be "vdd" for SD card
- vdd supply or "vdd-io" for SD I/O vdd supply.
-- qcom,<supply>-current-level : specifies current load levels for vdd supply.
- Should be specified in pairs (lpm, hpm) with
- units being uA. Here <supply> can be "vdd" for
- SD card vdd supply or "vdd-io" for SD I/O vdd
- supply.
-- qcom,hwevent-clks : list of clocks required by hardware event driver
-- qcom,hwevent-regs : list of regulators required by hardware event driver
-- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on
- the device. Only relevant in case of tmc-etr device.
-- interrupts : <a b c> where a is 0 or 1 depending on if the interrupt is
- spi/ppi, b is the interrupt number and c is the mask,
-- interrupt-names : a list of strings that map in order to the list of
- interrupts specified in the 'interrupts' property.
-- qcom,sg-enable : indicates whether scatter gather feature is supported for TMC
- ETR configuration.
-- qcom,force-reg-dump : boolean, indicate whether TMC register need to be dumped.
- Used for TMC component
-- qcom,nidntsw : boolean, indicating NIDnT software debug or trace support
- present. Used for tpiu component
-- qcom,nidnthw : boolean, indicating NIDnT hardware sensing support present.
- Used for tpiu component
- qcom,nidntsw and qcom,nidnthw are mutually exclusive properties, either of
- these may specified for tpiu component
-- qcom,nidnt-swduart : boolean, indicating NIDnT swd uart support present. Used
- for tpiu component
-- qcom,nidnt-swdtrc : boolean, indicating NIDnT swd trace support present. Used
- for tpiu component
-- qcom,nidnt-jtag : boolean, indicating NIDnT jtag debug support present. Used
- for tpiu component
-- qcom,nidnt-spmi : boolean, indicating NIDnT spmi debug support present. Used
- for tpiu component
-- nidnt-gpio : specifies gpio for NIDnT hardware detection
-- nidnt-gpio-polarity : specifies gpio polarity for NIDnT hardware detection
-- pinctrl-names : names corresponding to the numbered pinctrl. The allowed
- names are subset of the following: cti-trigin-pctrl,
- cti-trigout-pctrl. Used for cti component
-- pinctrl-<n>: list of pinctrl phandles for the different pinctrl states. Refer
- to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt".
-- qcom,funnel-save-restore : boolean, indicating funnel port needs to be disabled
- for the ETM whose CPU is being powered down. The port
- state is restored when CPU is powered up. Used for
- funnel component.
-- qcom,tmc-flush-powerdown : boolean, indicating trace data needs to be flushed before
- powering down CPU. Used for TMC component.
-- qcom,bc-elem-size : specifies the BC element size supported by each monitor
- connected to the aggregator on each port. Should be specified
- in pairs (port, bc element size).
-- qcom,tc-elem-size : specifies the TC element size supported by each monitor
- connected to the aggregator on each port. Should be specified
- in pairs (port, tc element size).
-- qcom,dsb-elem-size : specifies the DSB element size supported by each monitor
- connected to the aggregator on each port. Should be specified
- in pairs (port, dsb element size).
-- qcom,cmb-elem-size : specifies the CMB element size supported by each monitor
- connected to the aggregator on each port. Should be specified
- in pairs (port, cmb element size).
-- qcom,clk-enable: specifies whether additional clock bit needs to be set for
- M4M TPDM.
-- qcom,tpda-atid : specifies the ATID for TPDA.
-- qcom,inst-id : QMI instance id for remote ETMs.
-- qcom,noovrflw-enable : boolean, indicating whether no overflow bit needs to be
- set in ETM stall control register.
-- coresight-cti-cpu : cpu phandle for cpu cti, required when qcom,cti-save is true
-- coresight-etm-cpu : specifies phandle for the cpu associated with the ETM device
-- qcom,dbgui-addr-offset : indicates the offset of dbgui address registers
-- qcom,dbgui-data-offset : indicates the offset of dbgui data registers
-- qcom,dbgui-size : indicates the size of dbgui address and data registers
-- qcom,pmic-carddetect-gpio : indicates the hotplug capabilities of the qpdi driver
-- qcom,cpuss-debug-cgc: debug clock gating phandle for etm
- reg : the clock gating register for each cluster
- cluster : indicate the cluster number
-
-coresight-outports, coresight-child-list and coresight-child-ports lists will
-be of the same length and will have a one to one correspondence among the
-elements at the same list index.
-
-coresight-default-sink must be specified for one of the sink devices that is
-intended to be made the default sink. Other sink devices must not have this
-specified. Not specifying this property on any of the sinks is invalid.
+specification and can be connected in various topologies to suit a particular
+SoCs tracing needs. These trace components can generally be classified as
+sinks, links and sources. Trace data produced by one or more sources flows
+through the intermediate links connecting the source to the currently selected
+sink. Each CoreSight component device should use these properties to describe
+its hardware characteristcs.
* Required properties for all components *except* non-configurable replicators:
diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
deleted file mode 100644
index 0304035..0000000
--- a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt
+++ /dev/null
@@ -1,55 +0,0 @@
-* LPM Workarounds
-
-The required properties are:
-
-- compatible: "qcom,lpm-workarounds"
-
-The optional properties are:
-- reg: The physical address and the size of the l1_l2_gcc and l2_pwr_sts
- regitsters of performance cluster.
-
-- reg-names: "l2_pwr_sts" - string to identify l2_pwr_sts physical address.
- "l1_l2_gcc" - string to identify l1_l2_gcc physical address.
-
-- qcom,lpm-wa-cx-turbo-unvote: Indicates the workaround to unvote CX turbo
- vote when system is coming out of rpm assisted power collaspe.
- lpm-cx-supply is required if this is present.
-
-- lpm-cx-supply: will hold handle for CX regulator supply which is used
- to unvote.
-
-- qcom,lpm-wa-skip-l2-spm: Due to a hardware bug on 8939 and 8909, secure
- world needs to disable and enable L2 SPM to get the proper context
- in secure watchdog bite cases. With this workaround there is a race
- in programming L2 SPM between HLOS and secure world. This leads to
- stability issues. To avoid this program L2 SPM only in secure world
- based on the L2 mode flag passed. Set lpm-wa-skip-l2-spm node if this
- is required.
-
-- qcom,lpm-wa-dynamic-clock-gating: Due to a hardware bug on 8952, L1/L2 dynamic
- clock gating needs to be enabled by software for performance cluster
- cores and L2. Set lpm-wa-dynamic-clock-gating node if this workaround is
- required.
-
-- qcom,cpu-offline-mask: Dynamic clock gating should be enabled when cluster is
- in L2 PC. Each bit of cpu-offline-mask lists the cpu no. to hotplug by KTM
- driver.
-
-- qcom,non-boot-cpu-index: will hold index of non boot cluster cpu.
-
-- qcom,l1-l2-gcc-secure: indicates L1/L2 clock enabling register is secure.
-
-Example:
-
-qcom,lpm-workarounds {
- compatible = "qcom,lpm-workarounds";
- reg = <0x0B011018 0x4>,
- <0x0B011088 0x4>;
- reg-names = "l2-pwr-sts", "l1-l2-gcc";
- lpm-cx-supply = <&pm8916_s2_corner>;
- qcom,lpm-wa-cx-turbo-unvote;
- qcom,lpm-wa-skip-l2-spm;
- qcom,lpm-wa-dynamic-clock-gating;
- qcom,cpu-offline-mask = "0xF";
- qcom,non-boot-cpu-index = <4>;
-}
diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
index 2b7b3fa..606da38 100644
--- a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
+++ b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt
@@ -1,11 +1,14 @@
-* Amlogic Meson8b Clock and Reset Unit
+* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit
-The Amlogic Meson8b clock controller generates and supplies clock to various
-controllers within the SoC.
+The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and
+supplies clock to various controllers within the SoC.
Required Properties:
-- compatible: should be "amlogic,meson8b-clkc"
+- compatible: must be one of:
+ - "amlogic,meson8-clkc" for Meson8 (S802) SoCs
+ - "amlogic,meson8b-clkc" for Meson8 (S805) SoCs
+ - "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs
- reg: it must be composed by two tuples:
0) physical base address of the xtal register and length of memory
mapped region.
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index 4f7ae75..bda9d6f 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -47,10 +47,13 @@
Documentation/devicetree/bindings/media/video-interfaces.txt. The
first port should be the input endpoint, the second one the output
- The output should have two endpoints. The first is the block
- connected to the TCON channel 0 (usually a panel or a bridge), the
- second the block connected to the TCON channel 1 (usually the TV
- encoder)
+ The output may have multiple endpoints. The TCON has two channels,
+ usually with the first channel being used for the panels interfaces
+ (RGB, LVDS, etc.), and the second being used for the outputs that
+ require another controller (TV Encoder, HDMI, etc.). The endpoints
+ will take an extra property, allwinner,tcon-channel, to specify the
+ channel the endpoint is associated to. If that property is not
+ present, the endpoint number will be used as the channel number.
On SoCs other than the A33, there is one more clock required:
- 'tcon-ch1': The clock driving the TCON channel 1
diff --git a/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt
new file mode 100644
index 0000000..27c304e
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt
@@ -0,0 +1,28 @@
+The ICM20602 sensor is 6-axis gyroscope+accelerometer combo
+device which is made by InvenSense Inc.
+
+Required properties:
+
+ - compatible : Should be "invensense,icm20602".
+ - reg : the I2C address which depends on the AD0 pin.
+ - interrupt-parent : should be the phandle for the interrupt controller
+ - interrupts : interrupt mapping for GPIO IRQ
+
+Optional properties:
+ - invensense,icm20602-gpio: the irq gpio. This is not used if
+ using SMD to trigger. this is needed only if using the
+ device IRQ to trigger. Only using SMD to trigger can
+ support 8K sample rate.
+
+Example:
+ icm20602-i2c@068 {
+ compatible = "invensense,icm20602";
+ reg = <0x68>;
+ interrupt-parent = <&msm_gpio>;
+ interrupts = <13 0>;
+ invensense,icm20602-gpio = <&msm_gpio 13 0x0>;
+ pinctrl-names = "imu_active","imu_suspend";
+ pinctrl-0 = <&imu_int_active>;
+ pinctrl-1 = <&imu_int_suspend>;
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt
new file mode 100644
index 0000000..bf10122
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt
@@ -0,0 +1,36 @@
+STM VL53L0X Time-of-Flight ranging and gesture detection sensor driver
+
+Description:
+
+The VL53L0X is a new generation Time-of-Flight
+(ToF) laser-ranging module housed in the
+smallest package on the market today, providing
+accurate distance measurement whatever the
+target reflectances unlike conventional
+technologies. It can measure absolute distances
+up to 2m, setting a new benchmark in ranging
+performance levels, opening the door to various
+new applications.
+The VL53L0X integrates a leading-edge SPAD
+array (Single Photon Avalanche Diodes) and
+embeds ST’s second generation FlightSenseTM
+patented technology.
+The VL53L0X’s 940 nm VCSEL emitter (Vertical
+Cavity Surface-Emitting Laser), is totally invisible
+to the human eye, coupled with internal physical
+infrared filters, it enables longer ranging
+distances, higher immunity to ambient light, and
+better robustness to cover glass optical crosstalk.
+
+Required properties:
+
+ - compatible : Should be "st,stmvl53l0".
+ - reg : i2c slave address of the device.
+
+Example:
+ i2c@f9925000 {
+ vl53l0x@52 {
+ compatible = "st,stmvl53l0";
+ reg = <0x52>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
index 258ffec..b54c859 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/himax.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt
@@ -3,3 +3,20 @@
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/leds/leds-qpnp-haptics.txt b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
index 1a76d5d..258504e 100644
--- a/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
+++ b/Documentation/devicetree/bindings/leds/leds-qpnp-haptics.txt
@@ -116,6 +116,11 @@
Definition: Short circuit debounce cycles for internal PWM.
Allowed values: 0, 8, 16 or 32.
+- vcc_pon-supply
+ Usage: optional
+ Value type: <phandle>
+ Definition: PON driver regulator required to force MBG_ON
+
Following properties are specific only to LRA vibrators.
- qcom,lra-auto-mode
diff --git a/Documentation/devicetree/bindings/mcd/mcd.txt b/Documentation/devicetree/bindings/mcd/mcd.txt
deleted file mode 100644
index 4077ee2..0000000
--- a/Documentation/devicetree/bindings/mcd/mcd.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-* MCD (MobiCore Driver)
-
-t-base is an operating system running in the secure world (TrustZone).
-The t-base implementation consists of several components in the
-secure world and the non-secure world (kernel and user space). The
-MobiCore driver communicates with the t-base operating system that
-exists in TrustZone.
-
-Required properties:
- - compatible: Should be "qcom,mcd"
- - qcom,ce-hw-instance: should contain crypto HW instance
- - qcom,ce-device: Device number
- - clocks: Array of <clock_controller_phandle clock_reference> listing
- all the clocks that are accesed by this subsystem.
- - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target.
-
-Example:
- mcd {
- compatible = "qcom,mcd";
- qcom,ce-hw-instance = <0>;
- qcom,ce-device = <0>;
- clocks = <&clock_gcc clk_crypto_clk_src>,
- <&clock_gcc clk_gcc_crypto_clk>,
- <&clock_gcc clk_gcc_crypto_ahb_clk>,
- <&clock_gcc clk_gcc_crypto_axi_clk>;
- clock-names = "core_clk_src", "core_clk",
- "iface_clk", "bus_clk";
- qcom,ce-opp-freq = <100000000>;
- };
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
index caf297b..c28d4eb8 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt
@@ -35,6 +35,15 @@
- ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode.
Selection primary or secondary function associated to GPADC_START
and SYSEN2 pin/pad for DVFS2 interface
+- ti,palmas-override-powerhold: This is applicable for PMICs for which
+ GPIO7 is configured in POWERHOLD mode which has higher priority
+ over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON
+ bit is turned off. This property enables driver to over ride the
+ POWERHOLD value to GPIO7 so as to turn off the PMIC in power off
+ scenarios. So for GPIO7 if ti,palmas-override-powerhold is set
+ then the GPIO_7 field should never be muxed to anything else.
+ It should be set to POWERHOLD by default and only in case of
+ power off scenarios the driver will over ride the mux value.
This binding uses the following generic properties as defined in
pinctrl-bindings.txt:
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index efa67f5..afeb65d 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -191,6 +191,77 @@
temperature specific configuration as applied. If not
specified, the default value is 0 degree centigrade.
+- qcom,cl-disable
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property to disable the battery capacity
+ learning when charging.
+
+- qcom,cl-feedback-on
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property to feedback the learned capacity into
+ the capacity lerning algorithm. This has to be used only if the
+ property "qcom,cl-disable" is not specified.
+
+- qcom,cl-max-start-soc
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery SOC has to be below or equal to this value at the
+ start of a charge cycle to start the capacity learning.
+ If this is not specified, then the default value used
+ will be 15. Unit is in percentage.
+
+- qcom,cl-min-start-soc
+ Usage: optional
+ Value type: <u32>
+ Definition: Battery SOC has to be above or equal to this value at the
+ start of a charge cycle to start the capacity learning.
+ If this is not specified, then the default value used
+ will be 10. Unit is in percentage.
+
+- qcom,cl-min-temp
+ Usage: optional
+ Value type: <u32>
+ Definition: Lower limit of battery temperature to start the capacity
+ learning. If this is not specified, then the default value
+ used will be 150 (15 C). Unit is in decidegC.
+
+- qcom,cl-max-temp
+ Usage: optional
+ Value type: <u32>
+ Definition: Upper limit of battery temperature to start the capacity
+ learning. If this is not specified, then the default value
+ used will be 500 (50 C). Unit is in decidegC.
+
+- qcom,cl-max-increment
+ Usage: optional
+ Value type: <u32>
+ Definition: Maximum capacity increment allowed per capacity learning
+ cycle. If this is not specified, then the default value
+ used will be 5 (0.5%). Unit is in decipercentage.
+
+- qcom,cl-max-decrement
+ Usage: optional
+ Value type: <u32>
+ Definition: Maximum capacity decrement allowed per capacity learning
+ cycle. If this is not specified, then the default value
+ used will be 100 (10%). Unit is in decipercentage.
+
+- qcom,cl-min-limit
+ Usage: optional
+ Value type: <u32>
+ Definition: Minimum limit that the capacity cannot go below in a
+ capacity learning cycle. If this is not specified, then
+ the default value is 0. Unit is in decipercentage.
+
+- qcom,cl-max-limit
+ Usage: optional
+ Value type: <u32>
+ Definition: Maximum limit that the capacity cannot go above in a
+ capacity learning cycle. If this is not specified, then
+ the default value is 0. Unit is in decipercentage.
+
==========================================================
Second Level Nodes - Peripherals managed by QGAUGE driver
==========================================================
diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
index 846bd22..b02d759 100644
--- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt
@@ -241,6 +241,15 @@
time in order to allow hardware closed-loop CPR voltage
change requests to reach the PMIC regulator.
+- qcom,cpr-thread-has-always-vote-en
+ Usage: optional; only meaningful for CPR4 controller
+ Value type: <empty>
+ Definition: Boolean value which indicates that the CPR controller should
+ be configured to keep thread vote always enabled. This
+ configuration allows the CPR controller to not consider
+ MID/DN recommendations from other thread when all sensors
+ mapped to a thread collapsed.
+
=================================================
Second Level Nodes - CPR Threads for a Controller
=================================================
diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
index 7b8ae6f..1e4d2c1 100644
--- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
+++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt
@@ -434,6 +434,9 @@
Required properties:
- compatible : "qcom,wcd-dsp-glink"
+ - qcom,msm-codec-glink-edge: Name of the glink edge which is used
+ for IPC.
+ If no name is set, it defaults to "wdsp"
* msm_ext_disp_audio_codec_rx
@@ -722,6 +725,7 @@
wcd_dsp_glink {
compatible = "qcom,wcd-dsp-glink";
+ qcom,msm-codec-glink-edge = "bg";
};
msm_ext_disp_audio_codec_rx {
@@ -1180,6 +1184,18 @@
When clock rate is set to zero,
then external clock is assumed.
+ - qcom,msm-cpudai-tdm-afe-ebit-unsupported: Notify if ebit
+ setting is needed.When this is
+ set, along with clock rate as
+ zero, then afe is not configured
+ for clock.
+
+ - qcom,msm-cpudai-tdm-sec-port-enable: For chipsets with the
+ limitation where we need to enable
+ both RX and TX AFE ports, this flag
+ is used to enable TX/RX port for
+ RX/TX streams.
+
- qcom,msm-cpudai-tdm-clk-internal: Clock Source.
0 - EBIT clock from clk tree
1 - IBIT clock from clk tree
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
index e7fb61e..e85f9e1 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -171,6 +171,23 @@
offprjjquota Turn off project journelled quota.
quota Enable plain user disk quota accounting.
noquota Disable all plain disk quota option.
+whint_mode=%s Control which write hints are passed down to block
+ layer. This supports "off", "user-based", and
+ "fs-based". In "off" mode (default), f2fs does not pass
+ down hints. In "user-based" mode, f2fs tries to pass
+ down hints given by users. And in "fs-based" mode, f2fs
+ passes down hints with its policy.
+alloc_mode=%s Adjust block allocation policy, which supports "reuse"
+ and "default".
+fsync_mode=%s Control the policy of fsync. Currently supports "posix"
+ and "strict". In "posix" mode, which is default, fsync
+ will follow POSIX semantics and does a light operation
+ to improve the filesystem performance. In "strict" mode,
+ fsync will be heavy and behaves in line with xfs, ext4
+ and btrfs, where xfstest generic/342 will pass, but the
+ performance will regress.
+test_dummy_encryption Enable dummy encryption, which provides a fake fscrypt
+ context. The fake fscrypt context is used by xfstests.
================================================================================
DEBUGFS ENTRIES
diff --git a/Makefile b/Makefile
index 41cc032..bf5ea11 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
VERSION = 4
PATCHLEVEL = 9
-SUBLEVEL = 92
+SUBLEVEL = 96
EXTRAVERSION =
NAME = Roaring Lionus
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 04b1c06..54e93a0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -574,6 +574,7 @@
select PINCTRL
select ARCH_WANT_KMAP_ATOMIC_FLUSH
select SND_SOC_COMPRESS
+ select SND_HWDEP
help
Support for Qualcomm MSM/QSD based systems. This runs on the
apps processor of the MSM/QSD and depends on a shared memory
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index a6d5794..f66f377 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -13,6 +13,10 @@
# Ensure linker flags are correct
LDFLAGS :=
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+export DTC_FLAGS := -@
+endif
+
LDFLAGS_vmlinux :=-p --no-undefined -X --pic-veneer
ifeq ($(CONFIG_CPU_ENDIAN_BE8),y)
LDFLAGS_vmlinux += --be8
diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
index 2fa123e..52e8c50 100644
--- a/arch/arm/boot/Makefile
+++ b/arch/arm/boot/Makefile
@@ -34,10 +34,10 @@
DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES))
ifneq ($(DTB_NAMES),)
DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES))
-else
-DTB_LIST := $(dtb-y)
-endif
DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST))
+else
+DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb)
+endif
ifeq ($(CONFIG_XIP_KERNEL),y)
diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts
index 42b62f5..30e2f87 100644
--- a/arch/arm/boot/dts/am335x-pepper.dts
+++ b/arch/arm/boot/dts/am335x-pepper.dts
@@ -139,7 +139,7 @@
&audio_codec {
status = "okay";
- reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
+ gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>;
AVDD-supply = <&ldo3_reg>;
IOVDD-supply = <&ldo3_reg>;
DRVDD-supply = <&ldo3_reg>;
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
index 6df7829..78bee26 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi
@@ -204,6 +204,7 @@
interrupt-controller;
ti,system-power-controller;
+ ti,palmas-override-powerhold;
tps659038_pmic {
compatible = "ti,tps659038-pmic";
diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi
index db858ff..1cc6272 100644
--- a/arch/arm/boot/dts/am57xx-idk-common.dtsi
+++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi
@@ -57,6 +57,7 @@
#interrupt-cells = <2>;
interrupt-controller;
ti,system-power-controller;
+ ti,palmas-override-powerhold;
tps659038_pmic {
compatible = "ti,tps659038-pmic";
diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi
index a7da0dd..0898213 100644
--- a/arch/arm/boot/dts/at91sam9g25.dtsi
+++ b/arch/arm/boot/dts/at91sam9g25.dtsi
@@ -21,7 +21,7 @@
atmel,mux-mask = <
/* A B C */
0xffffffff 0xffe0399f 0xc000001c /* pioA */
- 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */
+ 0x0007ffff 0x00047e3f 0x00000000 /* pioB */
0x80000000 0x07c0ffff 0xb83fffff /* pioC */
0x003fffff 0x003f8000 0x00000000 /* pioD */
>;
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index 132f2be..56311fd 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -398,6 +398,8 @@
tps659038: tps659038@58 {
compatible = "ti,tps659038";
reg = <0x58>;
+ ti,palmas-override-powerhold;
+ ti,system-power-controller;
tps659038_pmic {
compatible = "ti,tps659038-pmic";
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index f7357d9..64de33d 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -640,7 +640,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL0>;
clock-names = "gscl";
- iommu = <&sysmmu_gsc0>;
+ iommus = <&sysmmu_gsc0>;
};
gsc_1: gsc@13e10000 {
@@ -650,7 +650,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL1>;
clock-names = "gscl";
- iommu = <&sysmmu_gsc1>;
+ iommus = <&sysmmu_gsc1>;
};
gsc_2: gsc@13e20000 {
@@ -660,7 +660,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL2>;
clock-names = "gscl";
- iommu = <&sysmmu_gsc2>;
+ iommus = <&sysmmu_gsc2>;
};
gsc_3: gsc@13e30000 {
@@ -670,7 +670,7 @@
power-domains = <&pd_gsc>;
clocks = <&clock CLK_GSCL3>;
clock-names = "gscl";
- iommu = <&sysmmu_gsc3>;
+ iommus = <&sysmmu_gsc3>;
};
hdmi: hdmi@14530000 {
diff --git a/arch/arm/boot/dts/imx53-qsrb.dts b/arch/arm/boot/dts/imx53-qsrb.dts
index 96d7eed..036c9bd 100644
--- a/arch/arm/boot/dts/imx53-qsrb.dts
+++ b/arch/arm/boot/dts/imx53-qsrb.dts
@@ -23,7 +23,7 @@
imx53-qsrb {
pinctrl_pmic: pmicgrp {
fsl,pins = <
- MX53_PAD_CSI0_DAT5__GPIO5_23 0x1e4 /* IRQ */
+ MX53_PAD_CSI0_DAT5__GPIO5_23 0x1c4 /* IRQ */
>;
};
};
diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
index 2b9c2be..47c9554 100644
--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
@@ -88,6 +88,7 @@
clocks = <&clks IMX6QDL_CLK_CKO>;
VDDA-supply = <®_2p5v>;
VDDIO-supply = <®_3p3v>;
+ lrclk-strength = <3>;
};
};
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 368e219..825f6ea 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -146,7 +146,7 @@
};
esdhc: esdhc@1560000 {
- compatible = "fsl,esdhc";
+ compatible = "fsl,ls1021a-esdhc", "fsl,esdhc";
reg = <0x0 0x1560000 0x0 0x10000>;
interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
clock-frequency = <0>;
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index 6003b29..4d448f1 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -510,7 +510,7 @@
tlv320aic3x: tlv320aic3x@18 {
compatible = "ti,tlv320aic3x";
reg = <0x18>;
- reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */
+ gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */
ai3x-gpio-func = <
0 /* AIC3X_GPIO1_FUNC_DISABLED */
5 /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */
@@ -527,7 +527,7 @@
tlv320aic3x_aux: tlv320aic3x@19 {
compatible = "ti,tlv320aic3x";
reg = <0x19>;
- reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */
+ gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */
AVDD-supply = <&vmmc2>;
DRVDD-supply = <&vmmc2>;
diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi
index b7a24af..4b7d972 100644
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -154,10 +154,10 @@
i2c_0: i2c@78b7000 {
compatible = "qcom,i2c-qup-v2.2.1";
- reg = <0x78b7000 0x6000>;
+ reg = <0x78b7000 0x600>;
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&gcc GCC_BLSP1_AHB_CLK>,
- <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>;
+ <&gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>;
clock-names = "iface", "core";
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile
index 4642d0d..e6af69d 100644
--- a/arch/arm/boot/dts/qcom/Makefile
+++ b/arch/arm/boot/dts/qcom/Makefile
@@ -21,14 +21,18 @@
mdm9607-ttp.dtb
targets += dtbs
-targets += $(addprefix ../, $(dtb-y))
-
-$(obj)/../%.dtb: $(src)/%.dts FORCE
- $(call if_changed_dep,dtc)
include $(srctree)/arch/arm64/boot/dts/qcom/Makefile
-$(obj)/../%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE
+$(obj)/%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE
$(call if_changed_dep,dtc)
-dtbs: $(addprefix $(obj)/../,$(dtb-y))
+ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y)
+$(obj)/%.dtbo:$(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE
+ $(call if_changed_dep,dtc)
+ $(call if_changed,dtbo_verify)
+
+dtbs: $(addprefix $(obj)/,$(dtb-y)) $(addprefix $(obj)/,$(dtbo-y))
+else
+dtbs: $(addprefix $(obj)/,$(dtb-y))
+endif
clean-files := *.dtb
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
index 77fc533..505f242 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi
@@ -98,4 +98,9 @@
reg = <0xC300000 0x1000>, <0xC370004 0x4>;
reg-names = "phys_addr_base", "offset_addr";
};
+
+ qcom,rpmh-master-stats@b211200 {
+ compatible = "qcom,rpmh-master-stats-v1";
+ reg = <0xb211200 0x60>;
+ };
};
diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
index 8ded625..d2178cb 100644
--- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
+++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi
@@ -19,6 +19,8 @@
#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
#include <dt-bindings/clock/qcom,aop-qmp.h>
+#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024))
+
/ {
model = "Qualcomm Technologies, Inc. SDX POORWILLS";
compatible = "qcom,sdxpoorwills";
@@ -218,6 +220,31 @@
< 1497600 >;
};
+ cpubw: qcom,cpubw {
+ compatible = "qcom,devbw";
+ governor = "cpufreq";
+ qcom,src-dst-ports = <1 512>;
+ qcom,active-only;
+ qcom,bw-tbl =
+ < MHZ_TO_MBPS(200, 2) >, /* 381 MB/s */
+ < MHZ_TO_MBPS(470, 2) >, /* 896 MB/s */
+ < MHZ_TO_MBPS(547, 2) >, /* 1043 MB/s */
+ < MHZ_TO_MBPS(691, 2) >, /* 1317 MB/s */
+ < MHZ_TO_MBPS(806, 2) >, /* 1537 MB/s */
+ < MHZ_TO_MBPS(940, 2) >, /* 1792 MB/s */
+ < MHZ_TO_MBPS(1383, 2) >; /* 2637 MB/s */
+ };
+
+ devfreq_compute: qcom,devfreq-compute {
+ compatible = "qcom,arm-cpu-mon";
+ qcom,cpulist = <&CPU0>;
+ qcom,target-dev = <&cpubw>;
+ qcom,core-dev-table =
+ < 153600 MHZ_TO_MBPS(200, 2) >,
+ < 576000 MHZ_TO_MBPS(691, 2) >,
+ < 1497600 MHZ_TO_MBPS(1383, 2)>;
+ };
+
clock_gcc: qcom,gcc@100000 {
compatible = "qcom,gcc-sdxpoorwills", "syscon";
reg = <0x100000 0x1f0000>;
@@ -906,24 +933,24 @@
<1 676 0 0>,
<143 777 0 0>,
/* SVS2 */
- <90 512 3616000 7232000>,
+ <90 512 900000 1800000>,
<90 585 300000 600000>,
- <1 676 90000 180000>, /*gcc_config_noc_clk_src */
+ <1 676 90000 179000>, /*gcc_config_noc_clk_src */
<143 777 0 120>, /* IB defined for IPA2X_clk in MHz*/
/* SVS */
- <90 512 6640000 13280000>,
+ <90 512 1530000 3060000>,
<90 585 400000 800000>,
- <1 676 100000 200000>,
+ <1 676 100000 199000>,
<143 777 0 250>, /* IB defined for IPA2X_clk in MHz*/
/* NOMINAL */
- <90 512 10400000 20800000>,
+ <90 512 2592000 5184000>,
<90 585 800000 1600000>,
- <1 676 200000 400000>,
+ <1 676 200000 399000>,
<143 777 0 440>, /* IB defined for IPA2X_clk in MHz*/
/* TURBO */
- <90 512 10400000 20800000>,
+ <90 512 2592000 5184000>,
<90 585 960000 1920000>,
- <1 676 266000 532000>,
+ <1 676 266000 531000>,
<143 777 0 500>; /* IB defined for IPA clk in MHz*/
qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL",
"TURBO";
@@ -1075,6 +1102,12 @@
#mbox-cells = <1>;
};
+ aop-msg-client {
+ compatible = "qcom,debugfs-qmp-client";
+ mboxes = <&qmp_aop 0>;
+ mbox-names = "aop";
+ };
+
vbus_detect: qcom,pmd-vbus-det {
compatible = "qcom,pmd-vbus-det";
interrupt-parent = <&spmi_bus>;
@@ -1252,13 +1285,14 @@
"rx-ch0-intr", "rx-ch1-intr",
"rx-ch2-intr", "rx-ch3-intr";
qcom,msm-bus,name = "emac";
- qcom,msm-bus,num-cases = <3>;
+ qcom,msm-bus,num-cases = <4>;
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 */
- qcom,bus-vector-names = "10", "100", "1000";
+ qcom,bus-vector-names = "0", "10", "100", "1000";
clocks = <&clock_gcc GCC_ETH_AXI_CLK>,
<&clock_gcc GCC_ETH_PTP_CLK>,
<&clock_gcc GCC_ETH_RGMII_CLK>,
@@ -1278,7 +1312,6 @@
emac_emb_smmu: emac_emb_smmu {
compatible = "qcom,emac-smmu-embedded";
- qcom,smmu-s1-bypass;
iommus = <&apps_smmu 0x220 0xf>;
qcom,iova-mapping = <0x80000000 0x40000000>;
};
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index 7885075..1788e18 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -266,7 +266,9 @@
lcd0_pins: lcd0 {
groups = "lcd0_data24_0", "lcd0_lclk_1", "lcd0_sync";
function = "lcd0";
+ };
+ lcd0_mux {
/* DBGMD/LCDC0/FSIA MUX */
gpio-hog;
gpios = <176 0>;
diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index 9e6bf0e..2679dc8 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -617,9 +617,9 @@
<0 12 RK_FUNC_1 &pcfg_pull_none>,
<0 13 RK_FUNC_1 &pcfg_pull_none>,
<0 14 RK_FUNC_1 &pcfg_pull_none>,
- <1 2 RK_FUNC_1 &pcfg_pull_none>,
- <1 4 RK_FUNC_1 &pcfg_pull_none>,
- <1 5 RK_FUNC_1 &pcfg_pull_none>;
+ <1 2 RK_FUNC_2 &pcfg_pull_none>,
+ <1 4 RK_FUNC_2 &pcfg_pull_none>,
+ <1 5 RK_FUNC_2 &pcfg_pull_none>;
};
};
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 65e725f..de0e189 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -1362,7 +1362,7 @@
pinctrl@fc06a000 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus";
+ compatible = "atmel,sama5d3-pinctrl", "atmel,at91sam9x5-pinctrl", "simple-bus";
ranges = <0xfc068000 0xfc068000 0x100
0xfc06a000 0xfc06a000 0x4000>;
/* WARNING: revisit as pin spec has changed */
diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig
index aee8104..9f5001f 100644
--- a/arch/arm/configs/msm8909-perf_defconfig
+++ b/arch/arm/configs/msm8909-perf_defconfig
@@ -259,7 +259,9 @@
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
-CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CLD_HL_SDIO_CORE=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_JOYSTICK=y
@@ -423,6 +425,7 @@
CONFIG_MSM_EVENT_TIMER=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_CNSS_CRYPTO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_QTI_MPM=y
diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig
index b82c3fd..c8087ad 100644
--- a/arch/arm/configs/msm8909_defconfig
+++ b/arch/arm/configs/msm8909_defconfig
@@ -253,7 +253,9 @@
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
-CONFIG_CLD_LL_CORE=y
+CONFIG_CNSS=y
+CONFIG_CNSS_SDIO=y
+CONFIG_CLD_HL_SDIO_CORE=y
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_INPUT_JOYSTICK=y
@@ -418,6 +420,7 @@
CONFIG_MSM_EVENT_TIMER=y
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
+CONFIG_CNSS_CRYPTO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_QTI_MPM=y
diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig
index 9b55740..5a56d63 100644
--- a/arch/arm/configs/msm8909w-perf_defconfig
+++ b/arch/arm/configs/msm8909w-perf_defconfig
@@ -1,9 +1,13 @@
+# CONFIG_FHANDLE is not set
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
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
@@ -30,7 +34,7 @@
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
-CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -132,6 +136,7 @@
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -213,6 +218,7 @@
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_HDCP_QSEECOM=y
CONFIG_QSEECOM=y
+CONFIG_UID_SYS_STATS=y
CONFIG_MEMORY_STATE_TIME=y
CONFIG_QPNP_MISC=y
CONFIG_SCSI=y
@@ -259,6 +265,8 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_MSM_HS=y
CONFIG_SERIAL_MSM_SMD=y
CONFIG_DIAG_CHAR=y
@@ -310,6 +318,8 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
@@ -354,9 +364,12 @@
CONFIG_USB_CONFIGFS_EEM=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
@@ -498,6 +511,7 @@
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_CRYPTO_DEV_QCE=y
CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y
+CONFIG_CRYPTO_DEV_QCRYPTO=y
CONFIG_CRYPTO_DEV_QCEDEV=y
CONFIG_CRYPTO_DEV_OTA_CRYPTO=y
CONFIG_CRYPTO_DEV_QCOM_ICE=y
diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig
index bb6bc88..af47269 100644
--- a/arch/arm/configs/msm8909w_defconfig
+++ b/arch/arm/configs/msm8909w_defconfig
@@ -1,3 +1,4 @@
+# CONFIG_FHANDLE is not set
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
CONFIG_NO_HZ=y
@@ -34,7 +35,7 @@
CONFIG_EMBEDDED=y
CONFIG_PROFILING=y
CONFIG_OPROFILE=y
-CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_CC_STACKPROTECTOR_REGULAR=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
@@ -141,6 +142,7 @@
CONFIG_NETFILTER_XT_MATCH_QTAGUID=y
CONFIG_NETFILTER_XT_MATCH_QUOTA=y
CONFIG_NETFILTER_XT_MATCH_QUOTA2=y
+CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y
CONFIG_NETFILTER_XT_MATCH_SOCKET=y
CONFIG_NETFILTER_XT_MATCH_STATE=y
CONFIG_NETFILTER_XT_MATCH_STATISTIC=y
@@ -269,6 +271,8 @@
CONFIG_INPUT_MISC=y
CONFIG_INPUT_QPNP_POWER_ON=y
CONFIG_INPUT_UINPUT=y
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_CONSOLE=y
CONFIG_SERIAL_MSM_HS=y
@@ -322,6 +326,8 @@
CONFIG_MEDIA_CONTROLLER=y
CONFIG_VIDEO_V4L2_SUBDEV_API=y
CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_MSM_VIDC_3X_V4L2=y
+CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_QCOM_KGSL=y
CONFIG_FB=y
CONFIG_FB_VIRTUAL=y
@@ -375,6 +381,7 @@
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
diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig
index 09b6f05..11308ba 100644
--- a/arch/arm/configs/msm8937-perf_defconfig
+++ b/arch/arm/configs/msm8937-perf_defconfig
@@ -17,7 +17,6 @@
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_RT_GROUP_SCHED=y
@@ -223,6 +222,8 @@
CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -241,7 +242,6 @@
CONFIG_HDCP_QSEECOM=y
CONFIG_QSEECOM=y
CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -253,10 +253,8 @@
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_DEBUG=y
CONFIG_DM_CRYPT=y
CONFIG_DM_REQ_CRYPT=y
CONFIG_DM_UEVENT=y
@@ -308,6 +306,10 @@
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26=y
+CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26=y
CONFIG_TOUCHSCREEN_FT5X06=y
CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_INPUT_MISC=y
@@ -341,7 +343,6 @@
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
@@ -357,11 +358,19 @@
CONFIG_MSM_APM=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_VIRTUAL_SENSOR=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -411,7 +420,6 @@
CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
CONFIG_MSM_VIDC_3X_V4L2=y
CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_RADIO_IRIS=y
@@ -424,7 +432,7 @@
CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
@@ -485,11 +493,12 @@
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
CONFIG_MMC_PARANOID_SD_INIT=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
@@ -583,6 +592,8 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -590,8 +601,6 @@
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
CONFIG_SDCARD_FS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig
index 1fefcc616..2f7941f 100644
--- a/arch/arm/configs/msm8937_defconfig
+++ b/arch/arm/configs/msm8937_defconfig
@@ -18,7 +18,6 @@
CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_SCHEDTUNE=y
CONFIG_RT_GROUP_SCHED=y
@@ -228,6 +227,8 @@
CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -246,7 +247,6 @@
CONFIG_HDCP_QSEECOM=y
CONFIG_QSEECOM=y
CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -258,10 +258,8 @@
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_DEBUG=y
CONFIG_DM_CRYPT=y
CONFIG_DM_REQ_CRYPT=y
CONFIG_DM_UEVENT=y
@@ -313,6 +311,10 @@
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26=y
+CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26=y
CONFIG_TOUCHSCREEN_FT5X06=y
CONFIG_TOUCHSCREEN_GEN_VKEYS=y
CONFIG_INPUT_MISC=y
@@ -348,7 +350,6 @@
CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
@@ -364,11 +365,19 @@
CONFIG_MSM_APM=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_VIRTUAL_SENSOR=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -418,7 +427,6 @@
CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
CONFIG_MSM_VIDC_3X_V4L2=y
CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_RADIO_IRIS=y
@@ -432,7 +440,7 @@
CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
@@ -493,12 +501,13 @@
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
CONFIG_MMC_RING_BUFFER=y
CONFIG_MMC_PARANOID_SD_INIT=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
@@ -599,6 +608,8 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -606,8 +617,6 @@
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
CONFIG_SDCARD_FS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig
new file mode 100644
index 0000000..a006ee1
--- /dev/null
+++ b/arch/arm/configs/msm8953-batcam-perf_defconfig
@@ -0,0 +1,265 @@
+CONFIG_LOCALVERSION="-perf"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SCHED_WALT=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_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=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_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_STRONG=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_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8953=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_NR_CPUS=8
+CONFIG_ARM_PSCI=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_IMG_DTB=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_MSM=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_HIBERNATION=y
+CONFIG_HIBERNATION_IMAGE_REUSE=y
+CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49"
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DMA_CMA=y
+CONFIG_QSEECOM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+CONFIG_INPUT_EVDEV=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_SMD=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8917=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_QPNP_SMB5=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_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_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_MMC=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
+CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_SYNC_FILE=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_IPA=y
+CONFIG_RNDIS_IPA=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_TZ_SMMU=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_ICNSS=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=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_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=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_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=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_DEBUG_INFO_DWARF4=y
+CONFIG_FRAME_WARN=2048
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_STACKTRACE=y
+# CONFIG_FTRACE is not set
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_CRYPTO_USER_API_HASH=m
+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/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig
new file mode 100644
index 0000000..4a0c147
--- /dev/null
+++ b/arch/arm/configs/msm8953-batcam_defconfig
@@ -0,0 +1,266 @@
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_SCHED_WALT=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_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=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_BLK_DEV_INITRD=y
+# CONFIG_RD_XZ is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_RD_LZ4 is not set
+CONFIG_BPF_SYSCALL=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_CC_STACKPROTECTOR_STRONG=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_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_DEADLINE is not set
+CONFIG_ARCH_QCOM=y
+CONFIG_ARCH_MSM8953=y
+# CONFIG_VDSO is not set
+CONFIG_SMP=y
+CONFIG_SCHED_MC=y
+CONFIG_VMSPLIT_3G_OPT=y
+CONFIG_NR_CPUS=8
+CONFIG_ARM_PSCI=y
+CONFIG_PREEMPT=y
+CONFIG_AEABI=y
+CONFIG_CMA=y
+CONFIG_CMA_DEBUGFS=y
+CONFIG_ZSMALLOC=y
+CONFIG_BALANCE_ANON_FILE_RECLAIM=y
+CONFIG_SECCOMP=y
+CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y
+CONFIG_IMG_DTB=y
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_BOOST=y
+CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
+CONFIG_CPU_FREQ_MSM=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_HIBERNATION=y
+CONFIG_HIBERNATION_IMAGE_REUSE=y
+CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49"
+CONFIG_PM_AUTOSLEEP=y
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_NET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_DMA_CMA=y
+CONFIG_QSEECOM=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_NETDEVICES=y
+CONFIG_INPUT_EVDEV=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=y
+CONFIG_SERIAL_MSM_CONSOLE=y
+CONFIG_SERIAL_MSM_SMD=y
+CONFIG_HW_RANDOM=y
+CONFIG_HW_RANDOM_MSM_LEGACY=y
+CONFIG_MSM_SMD_PKT=y
+CONFIG_MSM_ADSPRPC=y
+CONFIG_MSM_RDBG=m
+CONFIG_I2C_CHARDEV=y
+CONFIG_SPI=y
+CONFIG_SPI_QUP=y
+CONFIG_SPI_SPIDEV=y
+CONFIG_SPMI=y
+CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y
+CONFIG_PINCTRL_MSM8953=y
+CONFIG_PINCTRL_MSM8917=y
+CONFIG_PINCTRL_QCOM_SPMI_PMIC=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_QPNP_PIN=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_QCOM=y
+CONFIG_QCOM_DLOAD_MODE=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_QPNP_FG=y
+CONFIG_SMB135X_CHARGER=y
+CONFIG_QPNP_SMB5=y
+CONFIG_QPNP_SMBCHARGER=y
+CONFIG_QPNP_TYPEC=y
+CONFIG_QPNP_QG=y
+CONFIG_MSM_APM=y
+CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y
+CONFIG_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_MFD_SPMI_PMIC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_PROXY_CONSUMER=y
+CONFIG_REGULATOR_CPR=y
+CONFIG_REGULATOR_CPR4_APSS=y
+CONFIG_REGULATOR_CPRH_KBSS=y
+CONFIG_REGULATOR_MEM_ACC=y
+CONFIG_REGULATOR_MSM_GFX_LDO=y
+CONFIG_REGULATOR_QPNP_LABIBB=y
+CONFIG_REGULATOR_QPNP_LCDB=y
+CONFIG_REGULATOR_QPNP=y
+CONFIG_REGULATOR_RPM_SMD=y
+CONFIG_REGULATOR_SPM=y
+CONFIG_REGULATOR_STUB=y
+CONFIG_MEDIA_SUPPORT=y
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_CONTROLLER=y
+CONFIG_VIDEO_V4L2_SUBDEV_API=y
+CONFIG_V4L_PLATFORM_DRIVERS=y
+CONFIG_FB=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SOC=y
+CONFIG_UHID=y
+CONFIG_MMC=y
+CONFIG_MMC_PARANOID_SD_INIT=y
+CONFIG_MMC_CLKGATE=y
+CONFIG_MMC_BLOCK_MINORS=32
+CONFIG_MMC_BLOCK_DEFERRED_RESUME=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_MSM=y
+CONFIG_MMC_CQ_HCI=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_QTI_TRI_LED=y
+CONFIG_LEDS_QPNP=y
+CONFIG_LEDS_QPNP_FLASH=y
+CONFIG_LEDS_QPNP_FLASH_V2=y
+CONFIG_LEDS_QPNP_WLED=y
+CONFIG_LEDS_QPNP_HAPTICS=y
+CONFIG_LEDS_QPNP_VIBRATOR_LDO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_EDAC=y
+CONFIG_EDAC_MM_EDAC=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_QPNP=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_SPS_DMA=y
+CONFIG_SYNC_FILE=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_IPA=y
+CONFIG_RNDIS_IPA=y
+CONFIG_SPS=y
+CONFIG_SPS_SUPPORT_NDP_BAM=y
+CONFIG_QPNP_COINCELL=y
+CONFIG_QPNP_REVID=y
+CONFIG_REMOTE_SPINLOCK_MSM=y
+CONFIG_MAILBOX=y
+CONFIG_ARM_SMMU=y
+CONFIG_QCOM_LAZY_MAPPING=y
+CONFIG_QCOM_RUN_QUEUE_STATS=y
+CONFIG_MSM_SPM=y
+CONFIG_MSM_L2_SPM=y
+CONFIG_MSM_BOOT_STATS=y
+CONFIG_QCOM_WATCHDOG_V2=y
+CONFIG_QCOM_MEMORY_DUMP_V2=y
+CONFIG_MSM_RPM_SMD=y
+CONFIG_QCOM_BUS_SCALING=y
+CONFIG_QCOM_SECURE_BUFFER=y
+CONFIG_QCOM_EARLY_RANDOM=y
+CONFIG_MSM_SMEM=y
+CONFIG_MSM_SMD=y
+CONFIG_MSM_SMD_DEBUG=y
+CONFIG_MSM_TZ_SMMU=y
+CONFIG_MSM_SMP2P=y
+CONFIG_MSM_SUBSYSTEM_RESTART=y
+CONFIG_MSM_PIL=y
+CONFIG_MSM_PIL_SSR_GENERIC=y
+CONFIG_ICNSS=y
+CONFIG_MSM_PERFORMANCE=y
+CONFIG_MSM_EVENT_TIMER=y
+CONFIG_MSM_PM=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_QCOM_BIMC_BWMON=y
+CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
+CONFIG_SPDM_SCM=y
+CONFIG_DEVFREQ_SPDM=y
+CONFIG_PWM=y
+CONFIG_PWM_QPNP=y
+CONFIG_PWM_QTI_LPG=y
+CONFIG_QTI_MPM=y
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+CONFIG_SENSORS_SSC=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_QFMT_V2=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_TMPFS=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_DEBUG_INFO_DWARF4=y
+CONFIG_FRAME_WARN=2048
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_PANIC_TIMEOUT=5
+CONFIG_STACKTRACE=y
+# CONFIG_FTRACE is not set
+CONFIG_SECURITY=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_CRYPTO_USER_API_HASH=m
+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/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig
index 2ba24d9..aa557b0 100644
--- a/arch/arm/configs/msm8953-perf_defconfig
+++ b/arch/arm/configs/msm8953-perf_defconfig
@@ -307,6 +307,10 @@
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_FT5X06=y
CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y
+CONFIG_TOUCHSCREEN_HIMAX_I2C=y
+CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y
+CONFIG_HMX_DB=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
@@ -352,11 +356,19 @@
CONFIG_MSM_APM=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_VIRTUAL_SENSOR=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig
index 8299018..f38341d 100644
--- a/arch/arm/configs/msm8953_defconfig
+++ b/arch/arm/configs/msm8953_defconfig
@@ -312,6 +312,10 @@
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_FT5X06=y
CONFIG_TOUCHSCREEN_GEN_VKEYS=y
+CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y
+CONFIG_TOUCHSCREEN_HIMAX_I2C=y
+CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y
+CONFIG_HMX_DB=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
@@ -359,11 +363,19 @@
CONFIG_MSM_APM=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_VIRTUAL_SENSOR=y
+CONFIG_QTI_QMI_COOLING_DEVICE=y
+CONFIG_REGULATOR_COOLING_DEVICE=y
+CONFIG_QTI_BCL_PMIC5=y
+CONFIG_QTI_BCL_SOC_DRIVER=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig
index 0e971d2..14c2a7c 100644
--- a/arch/arm/configs/sdxpoorwills-perf_defconfig
+++ b/arch/arm/configs/sdxpoorwills-perf_defconfig
@@ -222,6 +222,7 @@
CONFIG_INPUT_GPIO=m
CONFIG_SERIO_LIBPS2=y
# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_MSM=y
CONFIG_SERIAL_MSM_HS=y
CONFIG_DIAG_CHAR=y
CONFIG_HW_RANDOM=y
@@ -381,6 +382,9 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
+CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_EXTCON_QCOM_SPMI_MISC=y
CONFIG_IIO=y
CONFIG_PWM=y
diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig
index 52f3fda..b259dc7 100644
--- a/arch/arm/configs/sdxpoorwills_defconfig
+++ b/arch/arm/configs/sdxpoorwills_defconfig
@@ -386,6 +386,8 @@
CONFIG_QTI_RPM_STATS_LOG=y
CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
CONFIG_QMP_DEBUGFS_CLIENT=y
+CONFIG_ARM_MEMLAT_MON=y
+CONFIG_DEVFREQ_GOV_MEMLAT=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_EXTCON_QCOM_SPMI_MISC=y
CONFIG_IIO=y
diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h
index 4f8e9e5..2dbb8c6 100644
--- a/arch/arm/include/asm/dma-contiguous.h
+++ b/arch/arm/include/asm/dma-contiguous.h
@@ -1,14 +1,25 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
#ifndef ASMARM_DMA_CONTIGUOUS_H
#define ASMARM_DMA_CONTIGUOUS_H
#ifdef __KERNEL__
-#ifdef CONFIG_DMA_CMA
#include <linux/types.h>
void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
#endif
-#endif
#endif
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index d5423ab..9fe1043 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -318,4 +318,10 @@
return -ENXIO;
}
+static inline bool kvm_arm_harden_branch_predictor(void)
+{
+ /* No way to detect it yet, pretend it is not there. */
+ return false;
+}
+
#endif /* __ARM_KVM_HOST_H__ */
diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h
deleted file mode 100644
index 6bda945..0000000
--- a/arch/arm/include/asm/kvm_psci.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2012 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __ARM_KVM_PSCI_H__
-#define __ARM_KVM_PSCI_H__
-
-#define KVM_ARM_PSCI_0_1 1
-#define KVM_ARM_PSCI_0_2 2
-
-int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
-
-#endif /* __ARM_KVM_PSCI_H__ */
diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h
index 71e473d..620dc75 100644
--- a/arch/arm/include/asm/xen/events.h
+++ b/arch/arm/include/asm/xen/events.h
@@ -16,7 +16,7 @@
return raw_irqs_disabled_flags(regs->ARM_cpsr);
}
-#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr), \
+#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((long long*)(ptr),\
atomic64_t, \
counter), (val))
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4f9e2b5..5b6cb33 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1066,8 +1066,6 @@
{
unsigned long config_base = 0;
- if (attr->exclude_idle)
- return -EPERM;
if (attr->exclude_user)
config_base |= ARMV7_EXCLUDE_USER;
if (attr->exclude_kernel)
@@ -1184,11 +1182,68 @@
*nb_cnt += 1;
}
-static int armv7_probe_num_events(struct arm_pmu *arm_pmu)
+static void armv7_pmu_idle_update(struct arm_pmu *cpu_pmu)
{
- return smp_call_function_any(&arm_pmu->supported_cpus,
+ struct pmu_hw_events *hw_events;
+ struct perf_event *event;
+ int idx;
+
+ if (!cpu_pmu)
+ return;
+
+ hw_events = this_cpu_ptr(cpu_pmu->hw_events);
+ if (!hw_events)
+ return;
+
+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
+ event = hw_events->events[idx];
+
+ if (!event || !event->attr.exclude_idle ||
+ event->state != PERF_EVENT_STATE_ACTIVE)
+ continue;
+
+ cpu_pmu->pmu.read(event);
+ }
+}
+
+struct armv7_pmu_idle_nb {
+ struct arm_pmu *cpu_pmu;
+ struct notifier_block perf_cpu_idle_nb;
+};
+
+static int armv7_pmu_idle_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct armv7_pmu_idle_nb *pmu_idle_nb = container_of(nb,
+ struct armv7_pmu_idle_nb, perf_cpu_idle_nb);
+
+ if (action == IDLE_START)
+ armv7_pmu_idle_update(pmu_idle_nb->cpu_pmu);
+
+ return NOTIFY_OK;
+}
+
+static int armv7_probe_pmu(struct arm_pmu *arm_pmu)
+{
+ int ret;
+ struct armv7_pmu_idle_nb *pmu_idle_nb;
+
+ pmu_idle_nb = devm_kzalloc(&arm_pmu->plat_device->dev,
+ sizeof(*pmu_idle_nb), GFP_KERNEL);
+ if (!pmu_idle_nb)
+ return -ENOMEM;
+
+ ret = smp_call_function_any(&arm_pmu->supported_cpus,
armv7_read_num_pmnc_events,
&arm_pmu->num_events, 1);
+ if (ret)
+ return ret;
+
+ pmu_idle_nb->cpu_pmu = arm_pmu;
+ pmu_idle_nb->perf_cpu_idle_nb.notifier_call = armv7_pmu_idle_notifier;
+ idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb);
+
+ return 0;
}
static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1200,7 +1255,7 @@
&armv7_pmuv1_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
&armv7_pmu_format_attr_group;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1212,7 +1267,7 @@
&armv7_pmuv1_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
&armv7_pmu_format_attr_group;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1224,7 +1279,7 @@
&armv7_pmuv1_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
&armv7_pmu_format_attr_group;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1237,7 +1292,7 @@
&armv7_pmuv2_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
&armv7_pmu_format_attr_group;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1250,7 +1305,7 @@
&armv7_pmuv2_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
&armv7_pmu_format_attr_group;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1263,7 +1318,7 @@
&armv7_pmuv2_events_attr_group;
cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] =
&armv7_pmu_format_attr_group;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1660,7 +1715,7 @@
cpu_pmu->disable = krait_pmu_disable_event;
cpu_pmu->get_event_idx = krait_pmu_get_event_idx;
cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
/*
@@ -1983,7 +2038,7 @@
cpu_pmu->disable = scorpion_pmu_disable_event;
cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx;
cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu)
@@ -1996,7 +2051,7 @@
cpu_pmu->disable = scorpion_pmu_disable_event;
cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx;
cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx;
- return armv7_probe_num_events(cpu_pmu);
+ return armv7_probe_pmu(cpu_pmu);
}
static const struct of_device_id armv7_pmu_of_device_ids[] = {
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index c6324b5..38ad8b9 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -129,13 +129,13 @@
for (j = 0; j < 8; j++) {
u32 data;
if (probe_kernel_address(p, data)) {
- printk(" ********");
+ pr_cont(" ********");
} else {
- printk(" %08x", data);
+ pr_cont(" %08x", data);
}
++p;
}
- printk("\n");
+ pr_cont("\n");
}
}
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index c38bfbe..ef6595c 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -29,6 +29,7 @@
#include <linux/kvm.h>
#include <trace/events/kvm.h>
#include <kvm/arm_pmu.h>
+#include <kvm/arm_psci.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -44,7 +45,6 @@
#include <asm/kvm_mmu.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
-#include <asm/kvm_psci.h>
#include <asm/sections.h>
#ifdef REQUIRES_VIRT
@@ -1088,7 +1088,7 @@
pgd_ptr = kvm_mmu_get_httbr();
stack_page = __this_cpu_read(kvm_arm_hyp_stack_page);
hyp_stack_ptr = stack_page + PAGE_SIZE;
- vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector);
+ vector_ptr = (unsigned long)kvm_get_hyp_vector();
__cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr);
__cpu_init_stage2();
@@ -1345,6 +1345,13 @@
goto out_err;
}
+
+ err = kvm_map_vectors();
+ if (err) {
+ kvm_err("Cannot map vectors\n");
+ goto out_err;
+ }
+
/*
* Map the Hyp stack pages
*/
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 4e57ebc..de1aedc 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -21,7 +21,7 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
#include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
+#include <kvm/arm_psci.h>
#include <trace/events/kvm.h>
#include "trace.h"
@@ -36,7 +36,7 @@
kvm_vcpu_hvc_get_imm(vcpu));
vcpu->stat.hvc_exit_stat++;
- ret = kvm_psci_call(vcpu);
+ ret = kvm_hvc_call_handler(vcpu);
if (ret < 0) {
vcpu_set_reg(vcpu, 0, ~0UL);
return 1;
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index 624a510..ebd2dd4 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -237,8 +237,10 @@
vcpu = (struct kvm_vcpu *)read_sysreg(HTPIDR);
host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+ __timer_save_state(vcpu);
__deactivate_traps(vcpu);
__deactivate_vm(vcpu);
+ __banked_restore_state(host_ctxt);
__sysreg_restore_state(host_ctxt);
}
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index a08d7a9..3d96225 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -15,16 +15,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/arm-smccc.h>
#include <linux/preempt.h>
#include <linux/kvm_host.h>
#include <linux/wait.h>
#include <asm/cputype.h>
#include <asm/kvm_emulate.h>
-#include <asm/kvm_psci.h>
#include <asm/kvm_host.h>
-#include <uapi/linux/psci.h>
+#include <kvm/arm_psci.h>
/*
* This is an implementation of the Power State Coordination Interface
@@ -33,6 +33,38 @@
#define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1)
+static u32 smccc_get_function(struct kvm_vcpu *vcpu)
+{
+ return vcpu_get_reg(vcpu, 0);
+}
+
+static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu)
+{
+ return vcpu_get_reg(vcpu, 1);
+}
+
+static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu)
+{
+ return vcpu_get_reg(vcpu, 2);
+}
+
+static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu)
+{
+ return vcpu_get_reg(vcpu, 3);
+}
+
+static void smccc_set_retval(struct kvm_vcpu *vcpu,
+ unsigned long a0,
+ unsigned long a1,
+ unsigned long a2,
+ unsigned long a3)
+{
+ vcpu_set_reg(vcpu, 0, a0);
+ vcpu_set_reg(vcpu, 1, a1);
+ vcpu_set_reg(vcpu, 2, a2);
+ vcpu_set_reg(vcpu, 3, a3);
+}
+
static unsigned long psci_affinity_mask(unsigned long affinity_level)
{
if (affinity_level <= 3)
@@ -75,7 +107,7 @@
unsigned long context_id;
phys_addr_t target_pc;
- cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+ cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK;
if (vcpu_mode_is_32bit(source_vcpu))
cpu_id &= ~((u32) 0);
@@ -88,14 +120,14 @@
if (!vcpu)
return PSCI_RET_INVALID_PARAMS;
if (!vcpu->arch.power_off) {
- if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1)
+ if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1)
return PSCI_RET_ALREADY_ON;
else
return PSCI_RET_INVALID_PARAMS;
}
- target_pc = vcpu_get_reg(source_vcpu, 2);
- context_id = vcpu_get_reg(source_vcpu, 3);
+ target_pc = smccc_get_arg2(source_vcpu);
+ context_id = smccc_get_arg3(source_vcpu);
kvm_reset_vcpu(vcpu);
@@ -114,7 +146,7 @@
* NOTE: We always update r0 (or x0) because for PSCI v0.1
* the general puspose registers are undefined upon CPU_ON.
*/
- vcpu_set_reg(vcpu, 0, context_id);
+ smccc_set_retval(vcpu, context_id, 0, 0, 0);
vcpu->arch.power_off = false;
smp_mb(); /* Make sure the above is visible */
@@ -134,8 +166,8 @@
struct kvm *kvm = vcpu->kvm;
struct kvm_vcpu *tmp;
- target_affinity = vcpu_get_reg(vcpu, 1);
- lowest_affinity_level = vcpu_get_reg(vcpu, 2);
+ target_affinity = smccc_get_arg1(vcpu);
+ lowest_affinity_level = smccc_get_arg2(vcpu);
/* Determine target affinity mask */
target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -198,18 +230,10 @@
kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET);
}
-int kvm_psci_version(struct kvm_vcpu *vcpu)
-{
- if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
- return KVM_ARM_PSCI_0_2;
-
- return KVM_ARM_PSCI_0_1;
-}
-
static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
- unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+ unsigned long psci_fn = smccc_get_function(vcpu);
unsigned long val;
int ret = 1;
@@ -219,7 +243,7 @@
* Bits[31:16] = Major Version = 0
* Bits[15:0] = Minor Version = 2
*/
- val = 2;
+ val = KVM_ARM_PSCI_0_2;
break;
case PSCI_0_2_FN_CPU_SUSPEND:
case PSCI_0_2_FN64_CPU_SUSPEND:
@@ -276,14 +300,56 @@
break;
}
- vcpu_set_reg(vcpu, 0, val);
+ smccc_set_retval(vcpu, val, 0, 0, 0);
+ return ret;
+}
+
+static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu)
+{
+ u32 psci_fn = smccc_get_function(vcpu);
+ u32 feature;
+ unsigned long val;
+ int ret = 1;
+
+ switch(psci_fn) {
+ case PSCI_0_2_FN_PSCI_VERSION:
+ val = KVM_ARM_PSCI_1_0;
+ break;
+ case PSCI_1_0_FN_PSCI_FEATURES:
+ feature = smccc_get_arg1(vcpu);
+ switch(feature) {
+ case PSCI_0_2_FN_PSCI_VERSION:
+ case PSCI_0_2_FN_CPU_SUSPEND:
+ case PSCI_0_2_FN64_CPU_SUSPEND:
+ case PSCI_0_2_FN_CPU_OFF:
+ case PSCI_0_2_FN_CPU_ON:
+ case PSCI_0_2_FN64_CPU_ON:
+ case PSCI_0_2_FN_AFFINITY_INFO:
+ case PSCI_0_2_FN64_AFFINITY_INFO:
+ case PSCI_0_2_FN_MIGRATE_INFO_TYPE:
+ case PSCI_0_2_FN_SYSTEM_OFF:
+ case PSCI_0_2_FN_SYSTEM_RESET:
+ case PSCI_1_0_FN_PSCI_FEATURES:
+ case ARM_SMCCC_VERSION_FUNC_ID:
+ val = 0;
+ break;
+ default:
+ val = PSCI_RET_NOT_SUPPORTED;
+ break;
+ }
+ break;
+ default:
+ return kvm_psci_0_2_call(vcpu);
+ }
+
+ smccc_set_retval(vcpu, val, 0, 0, 0);
return ret;
}
static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
{
struct kvm *kvm = vcpu->kvm;
- unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
+ unsigned long psci_fn = smccc_get_function(vcpu);
unsigned long val;
switch (psci_fn) {
@@ -301,7 +367,7 @@
break;
}
- vcpu_set_reg(vcpu, 0, val);
+ smccc_set_retval(vcpu, val, 0, 0, 0);
return 1;
}
@@ -319,9 +385,11 @@
* Errors:
* -EINVAL: Unrecognized PSCI function
*/
-int kvm_psci_call(struct kvm_vcpu *vcpu)
+static int kvm_psci_call(struct kvm_vcpu *vcpu)
{
- switch (kvm_psci_version(vcpu)) {
+ switch (kvm_psci_version(vcpu, vcpu->kvm)) {
+ case KVM_ARM_PSCI_1_0:
+ return kvm_psci_1_0_call(vcpu);
case KVM_ARM_PSCI_0_2:
return kvm_psci_0_2_call(vcpu);
case KVM_ARM_PSCI_0_1:
@@ -330,3 +398,30 @@
return -EINVAL;
};
}
+
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
+{
+ u32 func_id = smccc_get_function(vcpu);
+ u32 val = PSCI_RET_NOT_SUPPORTED;
+ u32 feature;
+
+ switch (func_id) {
+ case ARM_SMCCC_VERSION_FUNC_ID:
+ val = ARM_SMCCC_VERSION_1_1;
+ break;
+ case ARM_SMCCC_ARCH_FEATURES_FUNC_ID:
+ feature = smccc_get_arg1(vcpu);
+ switch(feature) {
+ case ARM_SMCCC_ARCH_WORKAROUND_1:
+ if (kvm_arm_harden_branch_predictor())
+ val = 0;
+ break;
+ }
+ break;
+ default:
+ return kvm_psci_call(vcpu);
+ }
+
+ smccc_set_retval(vcpu, val, 0, 0, 0);
+ return 1;
+}
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index add3771..9a22d40 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -821,6 +821,8 @@
.resource = da8xx_rproc_resources,
};
+static bool rproc_mem_inited __initdata;
+
#if IS_ENABLED(CONFIG_DA8XX_REMOTEPROC)
static phys_addr_t rproc_base __initdata;
@@ -859,6 +861,8 @@
ret = dma_declare_contiguous(&da8xx_dsp.dev, rproc_size, rproc_base, 0);
if (ret)
pr_err("%s: dma_declare_contiguous failed %d\n", __func__, ret);
+ else
+ rproc_mem_inited = true;
}
#else
@@ -873,6 +877,12 @@
{
int ret;
+ if (!rproc_mem_inited) {
+ pr_warn("%s: memory not reserved for DSP, not registering DSP device\n",
+ __func__);
+ return -ENOMEM;
+ }
+
ret = platform_device_register(&da8xx_dsp);
if (ret)
pr_err("%s: can't register DSP device: %d\n", __func__, ret);
diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c
index b3347d3..94906ed 100644
--- a/arch/arm/mach-imx/cpu.c
+++ b/arch/arm/mach-imx/cpu.c
@@ -131,6 +131,9 @@
case MXC_CPU_IMX6UL:
soc_id = "i.MX6UL";
break;
+ case MXC_CPU_IMX6ULL:
+ soc_id = "i.MX6ULL";
+ break;
case MXC_CPU_IMX7D:
soc_id = "i.MX7D";
break;
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 34f2ff6..e00d626 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -39,6 +39,7 @@
#define MXC_CPU_IMX6SX 0x62
#define MXC_CPU_IMX6Q 0x63
#define MXC_CPU_IMX6UL 0x64
+#define MXC_CPU_IMX6ULL 0x65
#define MXC_CPU_IMX7D 0x72
#define IMX_DDR_TYPE_LPDDR2 1
@@ -73,6 +74,11 @@
return __mxc_cpu_type == MXC_CPU_IMX6UL;
}
+static inline bool cpu_is_imx6ull(void)
+{
+ return __mxc_cpu_type == MXC_CPU_IMX6ULL;
+}
+
static inline bool cpu_is_imx6q(void)
{
return __mxc_cpu_type == MXC_CPU_IMX6Q;
diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig
index 1ab1fbb..b055b60 100644
--- a/arch/arm/mach-qcom/Kconfig
+++ b/arch/arm/mach-qcom/Kconfig
@@ -65,6 +65,17 @@
select HAVE_CLK_PREPARE
select COMMON_CLK_MSM
+config ARCH_MSM8953_BOOT_ORDERING
+ bool "Enable support for MSM8953 device boot ordering"
+ default n
+ help
+ Populate devices from devicetree at late_init, after
+ drivers for all platform devices have been registered.
+ This causes devices to be probed in the order they are
+ listed in devicetree. Thus it is possible to have
+ greater control over the probe ordering such that
+ overall boot time can be reduced.
+
config ARCH_MSM8937
bool "Enable support for MSM8937"
select CPU_V7
diff --git a/arch/arm/mach-qcom/board-msm8953.c b/arch/arm/mach-qcom/board-msm8953.c
index 04b0bcc..9a82e3a 100644
--- a/arch/arm/mach-qcom/board-msm8953.c
+++ b/arch/arm/mach-qcom/board-msm8953.c
@@ -14,6 +14,7 @@
#include "board-dt.h"
#include <asm/mach/map.h>
#include <asm/mach/arch.h>
+#include <linux/of_platform.h>
static const char *msm8953_dt_match[] __initconst = {
"qcom,msm8953",
@@ -23,9 +24,25 @@
static void __init msm8953_init(void)
{
+ if (IS_ENABLED(CONFIG_ARCH_MSM8953_BOOT_ORDERING))
+ return;
board_dt_populate(NULL);
}
+#ifdef CONFIG_ARCH_MSM8953_BOOT_ORDERING
+static int __init msm8953_dt_populate(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+
+ /* Explicitly parent the /soc devices to the root node to preserve
+ * the kernel ABI (sysfs structure, etc) until userspace is updated
+ */
+ return of_platform_populate(of_find_node_by_path("/soc"),
+ of_default_bus_match_table, NULL, NULL);
+}
+late_initcall(msm8953_dt_populate);
+#endif
+
DT_MACHINE_START(MSM8953_DT,
"Qualcomm Technologies, Inc. MSM8953 (Flattened Device Tree)")
.init_machine = msm8953_init,
diff --git a/arch/arm/mach-qcom/board-sdm429.c b/arch/arm/mach-qcom/board-sdm429.c
index c648eaf..6bdf0f4 100644
--- a/arch/arm/mach-qcom/board-sdm429.c
+++ b/arch/arm/mach-qcom/board-sdm429.c
@@ -17,6 +17,7 @@
static const char *sdm429_dt_match[] __initconst = {
"qcom,sdm429",
+ "qcom,sda429",
NULL
};
diff --git a/arch/arm/mach-qcom/board-sdm439.c b/arch/arm/mach-qcom/board-sdm439.c
index 312f3a5..7b9aa0f 100644
--- a/arch/arm/mach-qcom/board-sdm439.c
+++ b/arch/arm/mach-qcom/board-sdm439.c
@@ -17,6 +17,7 @@
static const char *sdm439_dt_match[] __initconst = {
"qcom,sdm439",
+ "qcom,sda439",
NULL
};
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index b57aafc..f216025 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -2372,6 +2372,7 @@
mapping->nr_bitmaps = 1;
mapping->extensions = extensions;
+ mapping->bits = BITS_PER_BYTE * bitmap_size;
spin_lock_init(&mapping->lock);
mapping->ops = &iommu_ops;
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index da0b33d..5629d75 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -648,7 +648,7 @@
*/
static int vfp_dying_cpu(unsigned int cpu)
{
- vfp_force_reload(cpu, current_thread_info());
+ vfp_current_hw_state[cpu] = NULL;
return 0;
}
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 1b135e5..9c01a31 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -825,6 +825,18 @@
If unsure, say Y.
+config PSCI_BP_HARDENING
+ depends on HARDEN_BRANCH_PREDICTOR
+ bool "Use PSCI get version to enable branch predictor hardening"
+ help
+ If the mitigation for branch prediction is supported using psci
+ get version by the firmware then enable this option. Some older
+ versions of firmwares may not be using new SMCCC convention in
+ such cases use psci get version method to enable hardening for
+ branch prediction attacks.
+
+ If unsure, say N.
+
menuconfig ARMV8_DEPRECATED
bool "Emulate deprecated/obsolete ARMv8 instructions"
depends on COMPAT
diff --git a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
index 3947406..c8330bd 100644
--- a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
+++ b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi
@@ -79,6 +79,31 @@
};
};
+&msm_gpio {
+ /delete-node/ mpu6050_int_pin;
+ /delete-node/ apds99xx_int_pin;
+ /delete-node/ ak8963_int_pin;
+
+ pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio25", "gpio37", "gpio59";
+ };
+ config {
+ pins = "gpio25", "gpio37", "gpio59";
+ };
+ };
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio25", "gpio37", "gpio59";
+ };
+ config {
+ pins = "gpio25", "gpio37", "gpio59";
+ };
+ };
+ };
+};
+
&i2c_3 {
qcom,actuator@0 {
/delete-property/ cam_vaf-supply;
diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile
index 31d4b0d..9cfb7cb 100644
--- a/arch/arm64/boot/dts/qcom/Makefile
+++ b/arch/arm64/boot/dts/qcom/Makefile
@@ -308,7 +308,8 @@
dtbo-$(CONFIG_ARCH_SDM439) += sdm439-mtp-overlay.dtbo \
sdm439-cdp-overlay.dtbo \
- sdm439-qrd-overlay.dtbo
+ sdm439-qrd-overlay.dtbo \
+ sdm439-external-codec-mtp-overlay.dtbo
dtbo-$(CONFIG_ARCH_SDM429) += sdm429-mtp-overlay.dtbo \
sdm429-cdp-overlay.dtbo \
@@ -368,14 +369,19 @@
sdm632-pm8004.dtb
sdm439-mtp-overlay.dtbo-base := sdm439.dtb \
+ sda439.dtb \
msm8937-interposer-sdm439.dtb
sdm439-cdp-overlay.dtbo-base := sdm439.dtb \
+ sda439.dtb \
msm8937-interposer-sdm439.dtb
sdm439-qrd-overlay.dtbo-base := sdm439.dtb \
msm8937-interposer-sdm439.dtb
+sdm439-external-codec-mtp-overlay.dtbo-base := sdm439.dtb
sdm429-mtp-overlay.dtbo-base := sdm429.dtb \
+ sda429.dtb \
msm8937-interposer-sdm429.dtb
sdm429-cdp-overlay.dtbo-base := sdm429.dtb \
+ sda429.dtb \
msm8937-interposer-sdm429.dtb
sdm429-qrd-overlay.dtbo-base := sdm429.dtb \
msm8937-interposer-sdm429.dtb
@@ -398,6 +404,14 @@
apq8053-iot-mtp.dtb \
apq8053-lite-dragon-v1.0.dtb \
apq8053-lite-dragon-v2.0.dtb \
+ apq8053-lite-dragon-v2.1.dtb \
+ apq8053-lite-dragon-v2.2.dtb \
+ apq8053-lite-dragon-v2.3.dtb \
+ apq8053-lite-dragon-v2.4.dtb \
+ apq8053-lite-lenovo-v1.0.dtb \
+ apq8053-lite-lenovo-v1.1.dtb \
+ apq8053-lite-harman-v1.0.dtb \
+ apq8053-lite-lge-v1.0.dtb \
msm8953-pmi8940-cdp.dtb \
msm8953-pmi8940-mtp.dtb \
msm8953-pmi8937-cdp.dtb \
@@ -414,14 +428,29 @@
msm8937-interposer-sdm429-mtp.dtb
dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb \
+ msm8917-pmi8950-cdp.dtb \
+ msm8917-pmi8950-rcm.dtb \
+ msm8917-pmi8950-ext-codec-cdp.dtb \
+ msm8917-pmi8950-cdp-mirror-lake-touch.dtb \
+ apq8017-pmi8950-cdp-wcd-rome.dtb \
+ apq8017-pmi8950-mtp.dtb \
+ apq8017-pmi8950-cdp.dtb \
msm8917-pmi8937-qrd-sku5.dtb \
+ msm8917-pmi8937-mtp.dtb \
+ msm8917-pmi8937-cdp.dtb \
+ msm8917-pmi8937-rcm.dtb \
+ apq8017-pmi8937-mtp.dtb \
+ apq8017-pmi8937-cdp.dtb \
+ apq8017-pmi8937-cdp-wcd-rome.dtb \
msm8917-pmi8940-mtp.dtb \
- msm8917-pmi8937-mtp.dtb
+ msm8917-pmi8940-cdp.dtb \
+ msm8917-pmi8940-rcm.dtb
dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \
apq8009w-bg-wtp-v2.dtb \
apq8009w-bg-alpha.dtb \
apq8009-mtp-wcd9326-refboard.dtb \
+ apq8009-robot-som-refboard.dtb \
apq8009-dragon.dtb
dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \
@@ -459,7 +488,8 @@
sdm439-cdp.dtb \
sdm439-qrd.dtb \
sda439-mtp.dtb \
- sda439-cdp.dtb
+ sda439-cdp.dtb \
+ sdm439-external-codec-mtp.dtb
dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \
sdm429-cdp.dtb \
diff --git a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts
index 6b3aea0..12a4363 100644
--- a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts
+++ b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts
@@ -66,6 +66,11 @@
mdss_mdp: qcom,mdss_mdp@1a00000 {
status = "disabled";
};
+
+ bluetooth: bt_qca9379 {
+ compatible = "qca,qca9379";
+ qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */
+ };
};
&sdhc_2 {
@@ -133,3 +138,7 @@
&pm8916_bms {
status = "ok";
};
+
+&blsp1_uart2_hs {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts
new file mode 100644
index 0000000..958f7c8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts
@@ -0,0 +1,188 @@
+/*
+ * 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 "msm8909-mtp.dtsi"
+#include "8909-pm8916.dtsi"
+#include "msm8909-pm8916-mtp.dtsi"
+#include "apq8009-audio-external_codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8009 Robot SOM refboard";
+ compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp";
+ qcom,msm-id = <265 2>;
+ qcom,board-id = <8 0x15>;
+};
+
+&soc {
+ ext-codec {
+ qcom,msm-mbhc-hphl-swh = <0>;
+ 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";
+ };
+
+ sound-9335 {
+ status = "disabled";
+ };
+
+ i2c@78b8000 {
+ wcd9xxx_codec@d {
+ status = "disabled";
+ };
+ };
+
+ vph_pwr_vreg: vph_pwr_vreg {
+ compatible = "regulator-fixed";
+ status = "ok";
+ regulator-name = "vph_pwr";
+ regulator-always-on;
+ };
+
+ mdss_mdp: qcom,mdss_mdp@1a00000 {
+ status = "disabled";
+ };
+
+ 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 */
+ };
+};
+
+&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";
+};
+
+&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>;
+ qcom,switch-vbus-w-id;
+ vbus_otg-supply = <&vph_pwr_vreg>;
+ extcon = <&pm8916_chg>;
+};
+
+&external_image_mem {
+ reg = <0x0 0x87a00000 0x0 0x0600000>;
+};
+
+&modem_adsp_mem {
+ reg = <0x0 0x88000000 0x0 0x01e00000>;
+};
+
+&peripheral_mem {
+ reg = <0x0 0x89e00000 0x0 0x0700000>;
+};
+
+&pm8916_chg {
+ status = "ok";
+};
+
+&pm8916_bms {
+ status = "ok";
+};
+
+&blsp1_uart2_hs {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts
index 89e1b76..1fe7b15 100644
--- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts
+++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts
@@ -300,4 +300,5 @@
&mdss_dsi0 {
qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>;
qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>;
+ qcom,platform-enable-gpio = <&msm_gpio 59 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
index 9fb6626..8113670 100644
--- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
+++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts
@@ -317,4 +317,5 @@
&mdss_dsi0 {
qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>;
qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>;
+ qcom,platform-enable-gpio = <&msm_gpio 59 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi b/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi
new file mode 100644
index 0000000..56f69ad
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi
@@ -0,0 +1,345 @@
+/*
+ * 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.
+ */
+
+&wsa881x_211 {
+ qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&wsa881x_212 {
+ qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&wsa881x_213 {
+ qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&wsa881x_214 {
+ qcom,spkr-sd-n-gpio = <&tlmm 92 0>;
+};
+
+&pm8937_gpios {
+ gpio@c000 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+
+ gpio@c600 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
+
+&slim_msm {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&clock_audio {
+ status = "okay";
+};
+
+&wcd9335 {
+ status = "okay";
+ cdc-vdd-mic-bias-supply = <&pm8937_l9>;
+ qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>;
+ qcom,cdc-vdd-mic-bias-current = <15000>;
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&ext_codec {
+ status = "okay";
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-mbhc-gnd-swh = <1>;
+ qcom,tdm-audio-intf;
+ qcom,afe-rxtx-lb;
+ reg = <0xc051000 0x4>,
+ <0xc051004 0x4>,
+ <0xc055000 0x4>,
+ <0xc052000 0x4>,
+ <0x0c056000 0x4>,
+ <0x0c054000 0x4>,
+ <0x0c053000 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",
+ "csr_gp_io_lpaif_qui_pcm_sec_mode_muxsel",
+ "csr_gp_io_mux_mic_ext_clk_ctl",
+ "csr_gp_io_mux_sec_tlmm_ctl";
+ qcom,audio-routing =
+ "AIF4 VI", "MCLK",
+ "AIF4 VI", "MICBIAS_REGULATOR",
+ "RX_BIAS", "MCLK",
+ "BRIDGE RX OUT", "MCLK",
+ "BRIDGE TX IN", "MCLK",
+ "MADINPUT", "MCLK",
+ "AIF4 MAD", "MICBIAS_REGULATOR",
+ "AMIC1", "MIC BIAS3",
+ "MIC BIAS3", "Handset Mic",
+ "AMIC2", "MIC BIAS2",
+ "MIC BIAS2", "Headset Mic",
+ "AMIC3", "MIC BIAS3",
+ "MIC BIAS3", "Secondary Mic",
+ "AMIC4", "MIC BIAS3",
+ "MIC BIAS3", "Analog Mic4",
+ "AMIC5", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic7",
+ "AMIC6", "MIC BIAS4",
+ "MIC BIAS4", "Analog Mic6",
+ "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",
+ "MIC BIAS3", "MICBIAS_REGULATOR",
+ "MIC BIAS4", "MICBIAS_REGULATOR",
+ "SpkrLeft IN", "SPK1 OUT",
+ "SpkrRight IN", "SPK2 OUT";
+ asoc-cpu = <&dai_pri_auxpcm>,
+ <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
+ <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>,
+ <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>,
+ <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>,
+ <&afe_pcm_rx>, <&afe_pcm_tx>,
+ <&afe_proxy_rx>, <&afe_proxy_tx>,
+ <&incall_record_rx>, <&incall_record_tx>,
+ <&incall_music_rx>, <&incall_music_2_rx>,
+ <&sb_5_rx>, <&bt_sco_rx>,
+ <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>,
+ <&sb_6_rx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>,
+ <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&afe_loopback_tx>;
+ asoc-cpu-names = "msm-dai-q6-auxpcm.1",
+ "msm-dai-q6-mi2s.2",
+ "msm-dai-q6-mi2s.3", "msm-dai-q6-mi2s.5",
+ "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385",
+ "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387",
+ "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389",
+ "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391",
+ "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393",
+ "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224",
+ "msm-dai-q6-dev.225", "msm-dai-q6-dev.241",
+ "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771",
+ "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773",
+ "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394",
+ "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289",
+ "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293",
+ "msm-dai-q6-dev.16396", "msm-dai-q6-tdm.36864",
+ "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880",
+ "msm-dai-q6-tdm.36881", "msm-dai-q6-dev.24577";
+ qcom,msm-gpios =
+ "quin_i2s",
+ "us_eu_gpio",
+ "quat_i2s";
+ qcom,pinctrl-names =
+ "all_off",
+ "quin_i2s_act",
+ "us_eu_gpio_act",
+ "quin_i2s_us_eu_gpio_act",
+ "quat_i2s_act",
+ "quat_i2s_quin_i2s_act",
+ "quat_i2s_us_eu_gpio_act",
+ "quat_i2s_us_eu_gpio_quin_i2s_act";
+ pinctrl-names =
+ "all_off",
+ "quin_i2s_act",
+ "us_eu_gpio_act",
+ "quin_i2s_us_eu_gpio_act",
+ "quat_i2s_act",
+ "quat_i2s_quin_i2s_act",
+ "quat_i2s_us_eu_gpio_act",
+ "quat_i2s_us_eu_gpio_quin_i2s_act";
+
+ pinctrl-0 = <&pri_tlmm_ws_sus
+ &cross_conn_det_sus &pri_mi2s_sd0_sleep
+ &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+ &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+ &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+ pinctrl-1 = <&pri_tlmm_ws_act
+ &cross_conn_det_sus &pri_mi2s_sd0_active
+ &pri_mi2s_sck_active &pri_mi2s_sd1_active
+ &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+ &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+ pinctrl-2 = <&pri_tlmm_ws_sus
+ &cross_conn_det_act &pri_mi2s_sd0_sleep
+ &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+ &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+ &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+ pinctrl-3 = <&pri_tlmm_ws_act
+ &cross_conn_det_act &pri_mi2s_sd0_active
+ &pri_mi2s_sck_active &pri_mi2s_sd1_active
+ &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep
+ &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>;
+ pinctrl-4 = <&pri_tlmm_ws_sus
+ &cross_conn_det_sus &pri_mi2s_sd0_sleep
+ &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+ &sec_mi2s_ws_active &sec_mi2s_sck_active
+ &sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+ pinctrl-5 = <&pri_tlmm_ws_act
+ &cross_conn_det_sus &pri_mi2s_sd0_active
+ &pri_mi2s_sck_active &pri_mi2s_sd1_active
+ &sec_mi2s_ws_active &sec_mi2s_sck_active
+ &sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+ pinctrl-6 = <&pri_tlmm_ws_sus
+ &cross_conn_det_act &pri_mi2s_sd0_sleep
+ &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep
+ &sec_mi2s_ws_active &sec_mi2s_sck_active
+ &sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+ pinctrl-7 = <&pri_tlmm_ws_act
+ &cross_conn_det_act &pri_mi2s_sd0_active
+ &pri_mi2s_sck_active &pri_mi2s_sd1_active
+ &sec_mi2s_ws_active &sec_mi2s_sck_active
+ &sec_mi2s_sd1_active &sec_mi2s_sd0_active>;
+};
+
+&int_codec {
+ status = "disabled";
+};
+
+&wsa881x_i2c_f {
+ status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+ status = "disabled";
+};
+
+&soc {
+ qcom,msm-dai-tdm-pri-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37120>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36864>;
+ qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+ qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+ dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36864>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-pri-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37121>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36865>;
+ qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+ qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+ dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36865>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-rx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37136>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36880>;
+ qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+ qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+ dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36880>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+
+ qcom,msm-dai-tdm-sec-tx {
+ compatible = "qcom,msm-dai-tdm";
+ qcom,msm-cpudai-tdm-group-id = <37137>;
+ qcom,msm-cpudai-tdm-group-num-ports = <1>;
+ qcom,msm-cpudai-tdm-group-port-id = <36881>;
+ qcom,msm-cpudai-tdm-clk-rate = <12288000>;
+ qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
+ dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 {
+ compatible = "qcom,msm-dai-q6-tdm";
+ qcom,msm-cpudai-tdm-dev-id = <36881>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <1>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <1>;
+ qcom,msm-cpudai-tdm-data-align = <0>;
+ };
+ };
+};
+
+&dai_pri_auxpcm {
+ qcom,msm-cpudai-afe-clk-ver = <2>;
+};
+
+&tlmm {
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio91", "gpio127", "gpio128";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio91", "gpio127", "gpio128";
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio91", "gpio127", "gpio128";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio91", "gpio127", "gpio128";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts
new file mode 100644
index 0000000..19c24f8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts
@@ -0,0 +1,98 @@
+/*
+ * 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 "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+#include "apq8017-rome.dtsi"
+#include "apq8017-audio.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 CDP \
+ with WCD codec/Rome card";
+ compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+ qcom,board-id= <1 2>;
+ qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+ status = "ok";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ /delete-property/vdd-supply;
+ /delete-property/qcom,vdd-voltage-level;
+ /delete-property/qcom,vdd-current-level;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ 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_active>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+ &sdc2_wlan_gpio_sleep>;
+
+ #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 124 0x4>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
+ /delete-property/cd-gpios;
+ /delete-property/qcom,devfreq,freq-table;
+
+ status = "ok";
+
+};
+
+&mdss_fb0 {
+ /delete-node/ qcom,cont-splash-memory;
+};
+
+/delete-node/ &cont_splash_mem;
+
+&soc {
+ gpio_keys {
+ /delete-node/ home;
+ };
+};
+
+&modem_mem {
+ reg = <0x0 0x86800000 0x0 0x1500000>;
+};
+
+&adsp_fw_mem {
+ reg = <0x0 0x87d00000 0x0 0x1100000>;
+};
+
+&wcnss_fw_mem {
+ reg = <0x0 0x88e00000 0x0 0x700000>;
+};
+
+&secure_mem {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts
new file mode 100644
index 0000000..6faa413
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 CDP";
+ compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+ qcom,board-id= <1 0>;
+ qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts
new file mode 100644
index 0000000..01305e6
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-mtp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 MTP";
+ compatible = "qcom,apq8017-mtp", "qcom,apq8017", "qcom,mtp";
+ qcom,board-id= <8 0>;
+ qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+ status = "ok";
+};
+
+&vendor {
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&qpnp_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+ qcom,battery-data = <&mtp_batterydata>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
new file mode 100644
index 0000000..8ddb1fc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts
@@ -0,0 +1,309 @@
+/*
+ * 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 "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+#include "apq8017-rome.dtsi"
+#include "apq8017-audio.dtsi"
+#include "apq8017-pmi8950-cdp-wcd-rome.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP \
+ with WCD codec/Rome card";
+ compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+ qcom,board-id= <1 2>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+ status = "ok";
+};
+
+&wcd9335 {
+ qcom,cdc-mic-unmute-delay = <50>;
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ /delete-property/vdd-supply;
+ /delete-property/qcom,vdd-voltage-level;
+ /delete-property/qcom,vdd-current-level;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l5>;
+ qcom,vdd-io-always-on;
+ qcom,vdd-io-voltage-level = <1800000 1800000>;
+ qcom,vdd-io-current-level = <200 325000>;
+
+ 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_active>;
+ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
+ &sdc2_wlan_gpio_sleep>;
+
+ #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 124 0x4>;
+ interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq";
+
+ /delete-property/cd-gpios;
+ /delete-property/qcom,devfreq,freq-table;
+
+ status = "ok";
+
+};
+
+&mdss_fb0 {
+ /delete-node/ qcom,cont-splash-memory;
+};
+
+/delete-node/ &cont_splash_mem;
+
+&soc {
+ gpio_keys {
+ /delete-node/ home;
+ };
+};
+
+&usb_otg {
+ vbus_otg-supply = <0>;
+ qcom,vbus-low-as-hostmode;
+};
+
+&i2c_4 {
+ usb2533@2c {
+ status = "ok";
+ };
+};
+
+&i2c_2 {
+ /* DSI_TO_HDMI I2C configuration */
+ adv7533@39 {
+ compatible = "adv7533";
+ reg = <0x39>;
+ instance_id = <0>;
+ adi,video-mode = <3>; /* 3 = 1080p */
+ adi,main-addr = <0x39>;
+ adi,cec-dsi-addr = <0x3C>;
+ adi,enable-audio;
+ adi,irq-gpio = <&tlmm 0x29 0x2002>;
+ adi,power-down-gpio = <&tlmm 0x7D 0x0>;
+ adi,switch-gpio = <&pm8937_gpios 0x8 0x1>;
+ pinctrl-names = "pmx_adv7533_active",
+ "pmx_adv7533_suspend";
+ pinctrl-0 = <&adv7533_int_active>;
+ pinctrl-1 = <&adv7533_int_suspend>;
+ };
+
+ pericom-type-c@1d {
+ status = "disabled";
+ };
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+ qcom,platform-intf-mux-gpio = <&tlmm 115 0>;
+ status = "ok";
+ qcom,bridge-index = <0>;
+ qcom,pluggable;
+};
+
+&dsi_adv7533_1080p {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
+
+&modem_mem {
+ reg = <0x0 0x86800000 0x0 0x1500000>;
+};
+
+&adsp_fw_mem {
+ reg = <0x0 0x87d00000 0x0 0x1100000>;
+};
+
+&wcnss_fw_mem {
+ reg = <0x0 0x88e00000 0x0 0x700000>;
+};
+
+&other_ext_mem {
+ reg = <0x0 0x84f00000 0x0 0x1900000>;
+};
+
+&qcom_seecom {
+ reg = <0x84f00000 0x1400000>;
+};
+
+&secure_mem {
+ status = "disabled";
+};
+
+/* Warning, SPI6 & I2C6 cannot be enabled at the same time due to pin usage. */
+&spi_6 {
+ status = "disabled";
+};
+
+&i2c_6 {
+ status = "ok";
+ qcom,clk-freq-out = <100000>;
+
+ /* TI591XX LED Drivers */
+ tlc59116@60 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,tlc59116";
+ reg = <0x60>;
+ out0@0 {
+ label = "ledsec1_g";
+ reg = <0x0>;
+ };
+ out1@1 {
+ label = "ledsec1_r";
+ reg = <0x1>;
+ };
+ out2@2 {
+ label = "ledsec1_b";
+ reg = <0x2>;
+ };
+ out3@3 {
+ label = "ledsec2_g";
+ reg = <0x3>;
+ };
+ out4@4 {
+ label = "ledsec2_r";
+ reg = <0x4>;
+ };
+ out5@5 {
+ label = "ledsec2_b";
+ reg = <0x5>;
+ };
+ out6@6 {
+ label = "ledsec3_g";
+ reg = <0x6>;
+ };
+ out7@7 {
+ label = "ledsec3_r";
+ reg = <0x7>;
+ };
+ out8@8 {
+ label = "ledsec3_b";
+ reg = <0x8>;
+ };
+ out9@9 {
+ label = "ledsec4_g";
+ reg = <0x9>;
+ };
+ out10@10 {
+ label = "ledsec4_r";
+ reg = <0xa>;
+ };
+ out11@11 {
+ label = "ledsec4_b";
+ reg = <0xb>;
+ };
+ out12@12 {
+ label = "ledsec5_g";
+ reg = <0xc>;
+ };
+ out13@13 {
+ label = "ledsec5_r";
+ reg = <0xd>;
+ };
+ out14@14 {
+ label = "ledsec5_b";
+ reg = <0xe>;
+ };
+ };
+
+ tlc59116@61 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,tlc59116";
+ reg = <0x61>;
+ out0@0 {
+ label = "ledsec6_g";
+ reg = <0x0>;
+ };
+ out1@1 {
+ label = "ledsec6_r";
+ reg = <0x1>;
+ };
+ out2@2 {
+ label = "ledsec6_b";
+ reg = <0x2>;
+ };
+ out3@3 {
+ label = "ledsec7_g";
+ reg = <0x3>;
+ };
+ out4@4 {
+ label = "ledsec7_r";
+ reg = <0x4>;
+ };
+ out5@5 {
+ label = "ledsec7_b";
+ reg = <0x5>;
+ };
+ out6@6 {
+ label = "ledsec8_g";
+ reg = <0x6>;
+ };
+ out7@7 {
+ label = "ledsec8_r";
+ reg = <0x7>;
+ };
+ out8@8 {
+ label = "ledsec8_b";
+ reg = <0x8>;
+ };
+ out9@9 {
+ label = "ledsec9_g";
+ reg = <0x9>;
+ };
+ out10@10 {
+ label = "ledsec9_r";
+ reg = <0xa>;
+ };
+ out11@11 {
+ label = "ledsec9_b";
+ reg = <0xb>;
+ };
+ };
+};
+
+&soc {
+ pinctrl@1000000 {
+ i2c6{
+ tlc59116_reset: tlc59116_reset {
+ config {
+ pins = "gpio20";
+ drive-strength = <16>;
+ bias-pull-up;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi
new file mode 100644
index 0000000..3337add
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP \
+ with WCD codec/Rome card";
+ compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+ qcom,board-id= <1 2>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+
+ aliases {
+ i2c6 = &i2c_6;
+ };
+};
+
+&soc {
+ i2c_6: i2c@7af6000 { /* BLSP2 QUP2 */
+ compatible = "qcom,i2c-msm-v2";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg-names = "qup_phys_addr";
+ reg = <0x7af6000 0x600>;
+ interrupt-names = "qup_irq";
+ interrupts = <0 300 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_qup2_i2c_apps_clk>;
+
+ pinctrl-names = "i2c_active", "i2c_sleep";
+ pinctrl-0 = <&i2c_6_active>;
+ pinctrl-1 = <&i2c_6_sleep>;
+ qcom,noise-rjct-scl = <0>;
+ qcom,noise-rjct-sda = <0>;
+ qcom,master-id = <84>;
+ dmas = <&dma_blsp2 6 64 0x20000020 0x20>,
+ <&dma_blsp2 7 32 0x20000020 0x20>;
+ dma-names = "tx", "rx";
+ status = "disabled";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts
new file mode 100644
index 0000000..5c8ef83
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP";
+ compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp";
+ qcom,board-id= <1 0>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&mdss_fb0 {
+ /delete-node/ qcom,cont-splash-memory;
+};
+
+/delete-node/ &cont_splash_mem;
diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts
new file mode 100644
index 0000000..b5b7667
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8017.dtsi"
+#include "msm8917-mtp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 MTP";
+ compatible = "qcom,apq8017-mtp", "qcom,apq8017", "qcom,mtp";
+ qcom,board-id= <8 0>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&blsp1_uart1 {
+ status = "ok";
+};
+
+&vendor {
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&qpnp_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&i2c_2 {
+ /* DSI_TO_HDMI I2C configuration */
+ adv7533@39 {
+ compatible = "adv7533";
+ reg = <0x39>;
+ instance_id = <0>;
+ adi,video-mode = <3>; /* 3 = 1080p */
+ adi,main-addr = <0x39>;
+ adi,cec-dsi-addr = <0x3C>;
+ adi,enable-audio;
+ adi,irq-gpio = <&tlmm 0x29 0x2002>;
+ adi,power-down-gpio = <&tlmm 0x7D 0x0>;
+ adi,switch-gpio = <&pm8937_gpios 0x8 0x1>;
+ pinctrl-names = "pmx_adv7533_active",
+ "pmx_adv7533_suspend";
+ pinctrl-0 = <&adv7533_int_active>;
+ pinctrl-1 = <&adv7533_int_suspend>;
+ };
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>;
+ qcom,platform-intf-mux-gpio = <&tlmm 115 0>;
+ status = "ok";
+ qcom,bridge-index = <0>;
+ qcom,pluggable;
+};
+
+&dsi_adv7533_1080p {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi b/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi
new file mode 100644
index 0000000..7dfa952
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi
@@ -0,0 +1,33 @@
+/*
+ * copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ qcom,cnss_sdio {
+ compatible = "qcom,cnss_sdio";
+ qcom,wlan-ramdump-dynamic = <0x200000>;
+ subsys-name = "AR6320";
+ qcom,cap-tsf-gpio = <&tlmm 126 1>;
+ };
+};
+
+&pm8937_gpios {
+ gpio@c100 { /* GPIO 2 - Rome Sleep Clock */
+ qcom,mode = <1>; /* Digital output */
+ qcom,vin-sel = <3>; /* VIN 3 */
+ qcom,src-sel = <2>; /* Function 2 */
+ qcom,out-strength = <2>; /* Medium */
+ qcom,pull = <4>;
+ qcom,master-en = <1>; /* Enable GPIO */
+ status = "okay";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8017.dtsi b/arch/arm64/boot/dts/qcom/apq8017.dtsi
new file mode 100644
index 0000000..fecc7ce8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8017.dtsi
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "msm8917.dtsi"
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8017";
+ compatible = "qcom,apq8017";
+ qcom,msm-id = <307 0x0>;
+};
+
+&tlmm {
+ pmx_adv7533_int: pmx_adv7533_int {
+ adv7533_int_active: adv7533_int_active {
+ mux {
+ pins = "gpio41";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio41";
+ function = "gpio";
+ drive-strength = <16>;
+ bias-pull-up; /* pull up */
+ };
+ };
+
+ adv7533_int_suspend: adv7533_int_suspend {
+ mux {
+ pins = "gpio41";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio41";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+ };
+};
+
+&mdss_dsi_active {
+ mux {
+ pins = "gpio60", "gpio98", "gpio115", "gpio133";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio60", "gpio98", "gpio115", "gpio133";
+ drive-strength = <8>; /* 8 mA */
+ bias-disable = <0>; /* no pull */
+ output-high;
+ };
+};
+
+&mdss_dsi_suspend {
+ mux {
+ pins = "gpio60", "gpio98", "gpio115", "gpio133";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio60", "gpio98", "gpio115", "gpio133";
+ drive-strength = <2>; /* 2 mA */
+ bias-pull-down; /* pull down */
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts
index 8f7e326..9f0edda 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts
@@ -26,3 +26,63 @@
qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
};
+&int_codec {
+ status = "disabled";
+};
+
+&wsa881x_i2c_f {
+ status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+ status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+ status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+ status = "disabled";
+};
+
+&cdc_comp_gpios {
+ status = "disabled";
+};
+
+&slim_msm {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&clock_audio {
+ status = "okay";
+};
+
+&wcd9335 {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&ext_codec {
+ qcom,model = "msm8953-tasha-snd-card";
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
index d7836e5..55d8b7b 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts
@@ -13,7 +13,6 @@
/dts-v1/;
-#include "apq8053-lite.dtsi"
#include "apq8053-lite-dragon-v2.0.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
index 947af4d..bb40018 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi
@@ -12,68 +12,25 @@
*/
#include "apq8053-lite-dragon.dtsi"
-#include "msm8953-mdss-panels.dtsi"
-
-&i2c_3 {
- status = "okay";
- himax_ts@48 {
- compatible = "himax,hxcommon";
- reg = <0x48>;
- interrupt-parent = <&tlmm>;
- interrupts = <65 0x2>;
- vdd-supply = <&pm8953_l10>;
- avdd-supply = <&pm8953_l5>;
- pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
- "pmx_ts_release";
- pinctrl-0 = <&ts_int_active &ts_reset_active>;
- pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
- pinctrl-2 = <&ts_release>;
- himax,panel-coords = <0 800 0 1280>;
- himax,display-coords = <0 800 0 1280>;
- himax,irq-gpio = <&tlmm 65 0x2008>;
- report_type = <1>;
- };
-};
-
-&mdss_mdp {
- qcom,mdss-pref-prim-intf = "dsi";
-};
-
-&mdss_dsi {
- hw-config = "single_dsi";
-};
&mdss_dsi0 {
- qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>;
- pinctrl-names = "mdss_default", "mdss_sleep";
pinctrl-0 = <&mdss_dsi_active &mdss_te_active &mdss_dsi_gpio>;
pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend &mdss_dsi_gpio>;
-
- vdd-supply = <&pm8953_l10>;
- 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>;
-};
-
-&mdss_dsi1 {
- status = "disabled";
-};
-
-&labibb {
- status = "okay";
- qpnp,qpnp-labibb-mode = "lcd";
-};
-
-&wled {
- qcom,cons-sync-write-delay-us = <1000>;
- qcom,led-strings-list = [00 01 02 03];
};
&pm8953_l4 {
status = "okay";
regulator-always-on;
};
+
+&camera0 {
+ qcom,mount-angle = <90>;
+};
+
+&camera1 {
+ qcom,mount-angle = <90>;
+};
+
+&camera2{
+ qcom,mount-angle = <90>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts
new file mode 100644
index 0000000..6c9c266
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-dragon-v2.1.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard V2.1";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01010020 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
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
new file mode 100644
index 0000000..4d9c40c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.1.dtsi
@@ -0,0 +1,68 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&mdss_dsi0 {
+ qcom,ext_vdd-gpio = <&tlmm 100 0>;
+ qcom,platform-bklight-en-gpio = <&tlmm 95 0>;
+
+ qcom,platform-lane-config = [00 00 ff 0f
+ 00 00 ff 0f
+ 00 00 ff 0f
+ 00 00 ff 0f
+ 00 00 ff 8f];
+};
+
+&eeprom0 {
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>,
+ <&tlmm 39 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_STANDBY0";
+};
+
+&camera0 {
+ qcom,mount-angle = <270>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VDIG",
+ "CAM_VANA";
+};
+
+&camera1 {
+ qcom,mount-angle = <270>;
+};
+
+&camera2{
+ qcom,mount-angle = <270>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts
new file mode 100644
index 0000000..ecc4fea
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-dragon-v2.2.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard V2.2";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01010120 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
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
new file mode 100644
index 0000000..396fd55
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.2.dtsi
@@ -0,0 +1,62 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&i2c_3 {
+ status = "okay";
+ /delete-node/ himax_ts@48;
+};
+
+&eeprom0 {
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>,
+ <&tlmm 39 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_STANDBY0";
+};
+
+&camera0 {
+ qcom,mount-angle = <270>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VDIG",
+ "CAM_VANA";
+};
+
+&camera1 {
+ qcom,mount-angle = <270>;
+};
+
+&camera2{
+ qcom,mount-angle = <270>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dts
new file mode 100644
index 0000000..e3f80be
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-dragon-v2.3.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard V2.3";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01020020 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
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
new file mode 100644
index 0000000..5cf8ac0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.3.dtsi
@@ -0,0 +1,80 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&pm8953_l4 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&pm8953_l10 {
+ status = "okay";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+};
+
+&pm8953_l2 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&pm8953_l17 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&pm8953_l22 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&i2c_3 {
+ status = "okay";
+ /delete-node/ himax_ts@48;
+ focaltech_ts@38 {
+ compatible = "focaltech,fts";
+ reg = <0x38>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <65 0x2>;
+ vdd-supply = <&pm8953_l10>;
+ avdd-supply = <&pm8953_l6>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
+ "pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ focaltech,display-coords = <0 0 800 1280>;
+ focaltech,reset-gpio = <&tlmm 64 0x0>;
+ focaltech,irq-gpio = <&tlmm 65 0x2>;
+ focaltech,max-touch-number = <5>;
+ report_type = <1>;
+ };
+};
+
+&wled {
+ qcom,led-strings-list = [00 01 02];
+};
+
+&camera0 {
+ qcom,mount-angle = <90>;
+};
+
+&camera1 {
+ qcom,mount-angle = <90>;
+};
+
+&camera2{
+ qcom,mount-angle = <90>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.4.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.4.dts
new file mode 100644
index 0000000..1f40ef8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.4.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-dragon-v2.4.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite DragonBoard V2.4";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01030020 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.4.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.4.dtsi
new file mode 100644
index 0000000..db0331e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.4.dtsi
@@ -0,0 +1,30 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&wled {
+ qcom,fs-curr-ua = <17500>;
+};
+
+&camera0 {
+ qcom,mount-angle = <180>;
+};
+
+&camera1 {
+ qcom,mount-angle = <180>;
+};
+
+&camera2 {
+ qcom,mount-angle = <180>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
index 5e3ddce..bd48f09 100644
--- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include "apq8053-lite.dtsi"
#include "msm8953-pinctrl.dtsi"
#include "apq8053-camera-sensor-dragon.dtsi"
#include "pmi8950.dtsi"
@@ -185,39 +186,22 @@
&i2c_3 {
status = "okay";
- focaltech@38 {
- compatible = "focaltech,5x06";
- reg = <0x38>;
+ himax_ts@48 {
+ compatible = "himax,hxcommon";
+ reg = <0x48>;
interrupt-parent = <&tlmm>;
interrupts = <65 0x2>;
vdd-supply = <&pm8953_l10>;
- vcc_i2c-supply = <&pm8953_l5>;
- /* pins used by touchscreen */
+ avdd-supply = <&pm8953_l5>;
pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
- "pmx_ts_release";
+ "pmx_ts_release";
pinctrl-0 = <&ts_int_active &ts_reset_active>;
pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
pinctrl-2 = <&ts_release>;
- focaltech,name = "ft5606";
- focaltech,family-id = <0x08>;
- focaltech,reset-gpio = <&tlmm 64 0x0>;
- focaltech,irq-gpio = <&tlmm 65 0x2008>;
- focaltech,display-coords = <0 0 1919 1199>;
- focaltech,panel-coords = <0 0 1919 1199>;
- focaltech,no-force-update;
- focaltech,i2c-pull-up;
- focaltech,group-id = <1>;
- focaltech,hard-reset-delay-ms = <20>;
- focaltech,soft-reset-delay-ms = <200>;
- focaltech,num-max-touches = <5>;
- focaltech,fw-delay-aa-ms = <30>;
- focaltech,fw-delay-55-ms = <30>;
- focaltech,fw-upgrade-id1 = <0x79>;
- focaltech,fw-upgrade-id2 = <0x08>;
- focaltech,fw-delay-readid-ms = <10>;
- focaltech,fw-delay-era-flsh-ms = <2000>;
- focaltech,fw-auto-cal;
- focaltech,resume-in-workqueue;
+ himax,panel-coords = <0 800 0 1280>;
+ himax,display-coords = <0 800 0 1280>;
+ himax,irq-gpio = <&tlmm 65 0x2008>;
+ report_type = <1>;
};
};
@@ -229,6 +213,71 @@
status = "disabled";
};
+#include "msm8953-mdss-panels.dtsi"
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi_active {
+ mux {
+ pins = "gpio61", "gpio100";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio61", "gpio100";
+ drive-strength = <8>;
+ bias-disable = <0>;
+ output-high;
+ };
+};
+
+&mdss_dsi_suspend {
+ mux {
+ pins = "gpio61", "gpio100";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio61", "gpio100";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>;
+ 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_l10>;
+ 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>;
+};
+
+&mdss_dsi1 {
+ status = "disabled";
+};
+
+&labibb {
+ status = "okay";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&wled {
+ qcom,cons-sync-write-delay-us = <1000>;
+ qcom,led-strings-list = [00 01 02 03];
+};
&blsp1_uart0 {
status = "ok";
pinctrl-names = "default";
@@ -270,7 +319,7 @@
pins = "gpio75";
drive-strength = <10>;
bias-pull-up;
- output-high;
+ output-low;
};
};
sdc2_wlan_gpio_off: sdc2_wlan_gpio_off {
@@ -290,6 +339,7 @@
&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>;
@@ -301,7 +351,7 @@
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off
&sdc2_wlan_gpio_off>;
- qcom,clk-rates = <400000 20000000 25000000 50000000>;
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>;
qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
status = "ok";
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts
new file mode 100644
index 0000000..203b6b8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-harman-v1.0.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite Harman v1.0 Board";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01020020 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi
new file mode 100644
index 0000000..5cf8ac0
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi
@@ -0,0 +1,80 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&pm8953_l4 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&pm8953_l10 {
+ status = "okay";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+};
+
+&pm8953_l2 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&pm8953_l17 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&pm8953_l22 {
+ status = "okay";
+ regulator-always-on;
+};
+
+&i2c_3 {
+ status = "okay";
+ /delete-node/ himax_ts@48;
+ focaltech_ts@38 {
+ compatible = "focaltech,fts";
+ reg = <0x38>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <65 0x2>;
+ vdd-supply = <&pm8953_l10>;
+ avdd-supply = <&pm8953_l6>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend",
+ "pmx_ts_release";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ pinctrl-2 = <&ts_release>;
+ focaltech,display-coords = <0 0 800 1280>;
+ focaltech,reset-gpio = <&tlmm 64 0x0>;
+ focaltech,irq-gpio = <&tlmm 65 0x2>;
+ focaltech,max-touch-number = <5>;
+ report_type = <1>;
+ };
+};
+
+&wled {
+ qcom,led-strings-list = [00 01 02];
+};
+
+&camera0 {
+ qcom,mount-angle = <90>;
+};
+
+&camera1 {
+ qcom,mount-angle = <90>;
+};
+
+&camera2{
+ qcom,mount-angle = <90>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts
new file mode 100644
index 0000000..325accf
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-lenovo-v1.0.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.0 Board";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01010020 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi
new file mode 100644
index 0000000..4d9c40c
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi
@@ -0,0 +1,68 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&mdss_dsi0 {
+ qcom,ext_vdd-gpio = <&tlmm 100 0>;
+ qcom,platform-bklight-en-gpio = <&tlmm 95 0>;
+
+ qcom,platform-lane-config = [00 00 ff 0f
+ 00 00 ff 0f
+ 00 00 ff 0f
+ 00 00 ff 0f
+ 00 00 ff 8f];
+};
+
+&eeprom0 {
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>,
+ <&tlmm 39 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_STANDBY0";
+};
+
+&camera0 {
+ qcom,mount-angle = <270>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VDIG",
+ "CAM_VANA";
+};
+
+&camera1 {
+ qcom,mount-angle = <270>;
+};
+
+&camera2{
+ qcom,mount-angle = <270>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts
new file mode 100644
index 0000000..0c7b557
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-lenovo-v1.1.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.1 Board";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01010120 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi
new file mode 100644
index 0000000..396fd55
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi
@@ -0,0 +1,62 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&i2c_3 {
+ status = "okay";
+ /delete-node/ himax_ts@48;
+};
+
+&eeprom0 {
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>,
+ <&tlmm 39 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_VDIG",
+ "CAM_VANA",
+ "CAM_STANDBY0";
+};
+
+&camera0 {
+ qcom,mount-angle = <270>;
+ gpios = <&tlmm 26 0>,
+ <&tlmm 40 0>,
+ <&tlmm 39 0>,
+ <&tlmm 118 0>,
+ <&tlmm 119 0>;
+ qcom,gpio-vdig = <3>;
+ qcom,gpio-vana = <4>;
+ qcom,gpio-req-tbl-num = <0 1 2 3 4>;
+ qcom,gpio-req-tbl-flags = <1 0 0 0 0>;
+ qcom,gpio-req-tbl-label = "CAMIF_MCLK0",
+ "CAM_RESET0",
+ "CAM_STANDBY0",
+ "CAM_VDIG",
+ "CAM_VANA";
+};
+
+&camera1 {
+ qcom,mount-angle = <270>;
+};
+
+&camera2{
+ qcom,mount-angle = <270>;
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts
new file mode 100644
index 0000000..70952dc
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "apq8053-lite-lge-v1.0.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. APQ8053 Lite LGE v1.0 Board";
+ compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053",
+ "qcom,dragonboard";
+ qcom,board-id= <0x01030020 0>;
+};
+
+&blsp2_uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi
new file mode 100644
index 0000000..db0331e
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi
@@ -0,0 +1,30 @@
+/*
+ * 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 "apq8053-lite-dragon.dtsi"
+
+&wled {
+ qcom,fs-curr-ua = <17500>;
+};
+
+&camera0 {
+ qcom,mount-angle = <180>;
+};
+
+&camera1 {
+ qcom,mount-angle = <180>;
+};
+
+&camera2 {
+ qcom,mount-angle = <180>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi
new file mode 100644
index 0000000..fe9094f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ pcm0: qcom,msm-pcm {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <0>;
+ };
+
+ routing: qcom,msm-pcm-routing {
+ compatible = "qcom,msm-pcm-routing";
+ };
+
+ compr: qcom,msm-compr-dsp {
+ compatible = "qcom,msm-compr-dsp";
+ };
+
+ pcm1: qcom,msm-pcm-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <1>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "regular";
+ };
+
+ pcm2: qcom,msm-ultra-low-latency {
+ compatible = "qcom,msm-pcm-dsp";
+ qcom,msm-pcm-dsp-id = <2>;
+ qcom,msm-pcm-low-latency;
+ qcom,latency-level = "ultra";
+ };
+
+ 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";
+ };
+
+ lsm: qcom,msm-lsm-client {
+ compatible = "qcom,msm-lsm-client";
+ };
+
+ qcom,msm-dai-q6 {
+ compatible = "qcom,msm-dai-q6";
+ 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>;
+ };
+
+ usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28672>;
+ };
+
+ usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx {
+ compatible = "qcom,msm-dai-q6-dev";
+ qcom,msm-dai-q6-dev-id = <28673>;
+ };
+ };
+
+ hostless: qcom,msm-pcm-hostless {
+ compatible = "qcom,msm-pcm-hostless";
+ };
+
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
index f2cea32..fa6498e 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi
@@ -9,8 +9,15 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#include "msm-audio-lpass-msm8909.dtsi"
&soc {
+ qcom,msm-audio-apr {
+ compatible = "qcom,msm-audio-apr";
+ msm_audio_apr_dummy {
+ compatible = "qcom,msm-audio-apr-dummy";
+ };
+ };
audio_codec_bg: sound {
status = "disabled";
compatible = "qcom,msm-bg-audio-codec";
@@ -28,6 +35,8 @@
qcom,msm-ext-pa = "primary";
qcom,tdm-audio-intf;
qcom,msm-afe-clk-ver = <1>;
+ qcom,split-a2dp;
+ qcom,pri-mi2s-gpios = <&cdc_dmic_gpios>;
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
<&afe>, <&lsm>, <&routing>, <&lpa>,
@@ -69,7 +78,12 @@
asoc-codec = <&stub_codec>;
asoc-codec-names = "msm-stub-codec.1";
};
-
+ cdc_dmic_gpios: cdc_dmic_pinctrl {
+ 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>;
+ };
pri_tdm_rx: qcom,msm-dai-tdm-pri-rx {
compatible = "qcom,msm-dai-tdm";
qcom,msm-cpudai-tdm-group-id = <37120>;
@@ -77,49 +91,32 @@
qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>;
qcom,msm-cpudai-tdm-clk-rate = <0>;
qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+ qcom,msm-cpudai-tdm-clk-internal = <0>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-sec-port-enable;
qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
- pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36864>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36866>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36868>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36870>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
};
@@ -131,49 +128,32 @@
qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>;
qcom,msm-cpudai-tdm-clk-rate = <0>;
qcom,msm-cpudai-tdm-afe-ebit-unsupported;
+ qcom,msm-cpudai-tdm-clk-internal = <0>;
+ qcom,msm-cpudai-tdm-sync-mode = <0>;
+ qcom,msm-cpudai-tdm-sync-src = <0>;
+ qcom,msm-cpudai-tdm-data-out = <0>;
+ qcom,msm-cpudai-tdm-invert-sync = <0>;
+ qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-sec-port-enable;
qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>;
- pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>;
dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36865>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36867>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36869>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 {
compatible = "qcom,msm-dai-q6-tdm";
qcom,msm-cpudai-tdm-dev-id = <36871>;
- qcom,msm-cpudai-tdm-sync-mode = <0>;
- qcom,msm-cpudai-tdm-sync-src = <0>;
- qcom,msm-cpudai-tdm-data-out = <0>;
- qcom,msm-cpudai-tdm-invert-sync = <0>;
- qcom,msm-cpudai-tdm-data-delay = <0>;
qcom,msm-cpudai-tdm-data-align = <0>;
};
};
@@ -187,6 +167,7 @@
status = "disabled";
compatible = "qcom,bg-codec";
qcom,subsys-name = "modem";
+ qcom,bg-speaker-connected;
qcom,bg-glink {
compatible = "qcom,bg-cdc-glink";
qcom,msm-glink-channels = <4>;
diff --git a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
index 4e7d6f8..9d35b06 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi
@@ -1,413 +1,694 @@
-/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
+/*
+ * 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
+ * it under the terms of the GNU General Public License version 2 an
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
&soc {
tmc_etr: tmc@826000 {
- compatible = "arm,coresight-tmc";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
reg = <0x826000 0x1000>,
<0x884000 0x15000>;
reg-names = "tmc-base", "bam-base";
+
interrupts = <0 166 0>;
interrupt-names = "byte-cntr-irq";
- qcom,memory-size = <0x100000>;
- qcom,sg-enable;
+ arm,buffer-size = <0x100000>;
+ arm,sg-enable;
- coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
- coresight-nr-inports = <1>;
coresight-ctis = <&cti0 &cti8>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- tpiu: tpiu@820000 {
- compatible = "arm,coresight-tpiu";
- reg = <0x820000 0x1000>,
- <0x1100000 0xb0000>;
- reg-names = "tpiu-base", "nidnt-base";
-
- coresight-id = <1>;
- coresight-name = "coresight-tpiu";
- coresight-nr-inports = <1>;
-
- qcom,nidnthw;
- qcom,nidnt-swduart;
- qcom,nidnt-swdtrc;
- qcom,nidnt-jtag;
- qcom,nidnt-spmi;
- nidnt-gpio = <38>;
- nidnt-gpio-polarity = <1>;
-
- interrupts = <0 82 0>;
- interrupt-names = "nidnt-irq";
-
- vdd-supply = <&pm8909_l11>;
- qcom,vdd-voltage-level = <2950000 2950000>;
- qcom,vdd-current-level = <15000 400000>;
-
- vdd-io-supply = <&pm8909_l12>;
- qcom,vdd-io-voltage-level = <2950000 2950000>;
- qcom,vdd-io-current-level = <200 50000>;
+ coresight-csr = <&csr>;
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- replicator: replicator@824000 {
- compatible = "qcom,coresight-replicator";
- reg = <0x824000 0x1000>;
- reg-names = "replicator-base";
-
- coresight-id = <2>;
- coresight-name = "coresight-replicator";
- coresight-nr-inports = <1>;
- coresight-outports = <0 1>;
- coresight-child-list = <&tmc_etr &tpiu>;
- coresight-child-ports = <0 0>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+ port {
+ tmc_etr_in_replicator: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_tmc_etr>;
+ };
+ };
};
tmc_etf: tmc@825000 {
- compatible = "arm,coresight-tmc";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
reg = <0x825000 0x1000>;
reg-names = "tmc-base";
- coresight-id = <3>;
coresight-name = "coresight-tmc-etf";
- coresight-nr-inports = <1>;
- coresight-outports = <0>;
- coresight-child-list = <&replicator>;
- coresight-child-ports = <0>;
- coresight-default-sink;
+
+ arm,default-sink;
coresight-ctis = <&cti0 &cti8>;
+ coresight-csr = <&csr>;
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ tmc_etf_out_replicator:endpoint {
+ remote-endpoint =
+ <&replicator_in_tmc_etf>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ tmc_etf_in_funnel_in0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in0_out_tmc_etf>;
+ };
+ };
+ };
+ };
+
+ replicator: replicator@824000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b909>;
+
+ reg = <0x824000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-name = "coresight-replicator";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ replicator_out_tmc_etr: endpoint {
+ remote-endpoint =
+ <&tmc_etr_in_replicator>;
+ };
+ };
+ port@1 {
+ reg = <0>;
+ replicator_in_tmc_etf: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tmc_etf_out_replicator>;
+ };
+ };
+ };
};
funnel_in0: funnel@821000 {
- compatible = "arm,coresight-funnel";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x821000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <4>;
coresight-name = "coresight-funnel-in0";
- coresight-nr-inports = <8>;
- coresight-outports = <0>;
- coresight-child-list = <&tmc_etf>;
- coresight-child-ports = <0>;
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ funnel_in0_out_tmc_etf: endpoint {
+ remote-endpoint =
+ <&tmc_etf_in_funnel_in0>;
+ };
+ };
+ port@1 {
+ reg = <7>;
+ funnel_in0_in_stm: endpoint {
+ slave-mode;
+ remote-endpoint = <&stm_out_funnel_in0>;
+ };
+ };
+
+ port@2 {
+ reg = <3>;
+ funnel_in0_in_funnel_center: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_center_out_funnel_in0>;
+ };
+ };
+
+ port@3 {
+ reg = <4>;
+ funnel_in0_in_funnel_right: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_right_out_funnel_in0>;
+ };
+ };
+
+ port@4 {
+
+ reg = <0>;
+ funnel_in0_in_rpm_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&rpm_etm0_out_funnel_center>;
+ };
+ };
+
+ port@5 {
+ reg = <1>;
+ funnel_in0_in_modem_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&modem_etm0_out_funnel_right>;
+ };
+ };
+ };
};
- funnel_in2: funnel@869000 {
- compatible = "arm,coresight-funnel";
+ funnel_center: funnel@869000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x869000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <5>;
- coresight-name = "coresight-funnel-in2";
- coresight-nr-inports = <8>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <6>;
+ coresight-name = "coresight-funnel-center";
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_center_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_center>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ funnel_center_in_dbgui: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&dbgui_out_funnel_center>;
+ };
+ };
+ };
};
- funnel_in3: funnel@868000 {
- compatible = "arm,coresight-funnel";
+ funnel_right: funnel@868000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
reg = <0x868000 0x1000>;
reg-names = "funnel-base";
- coresight-id = <6>;
- coresight-name = "coresight-funnel-in3";
- coresight-nr-inports = <2>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in2>;
- coresight-child-ports = <7>;
+ coresight-name = "coresight-funnel-right";
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_right_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_right>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ funnel_right_in_funnel_apss: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss_out_funnel_right>;
+ };
+ };
+
+ port@3 {
+ reg = <0>;
+ funnel_right_in_wcn_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&wcn_etm0_out_funnel_mm>;
+ };
+ };
+ };
};
- cti0: cti@810000 {
- compatible = "arm,coresight-cti";
- reg = <0x810000 0x1000>;
- reg-names = "cti-base";
+ funnel_apss: funnel@855000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
- coresight-id = <7>;
- coresight-name = "coresight-cti0";
- coresight-nr-inports = <0>;
+ reg = <0x855000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-apss";
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_apss_out_funnel_right: endpoint {
+ remote-endpoint =
+ <&funnel_right_in_funnel_apss>;
+ };
+ };
+
+ port@1 {
+ reg = <4>;
+ funnel_apss0_in_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm0_out_funnel_apss0>;
+ };
+ };
+
+ port@2 {
+ reg = <5>;
+ funnel_apss0_in_etm1: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm1_out_funnel_apss0>;
+ };
+ };
+
+ port@3 {
+ reg = <6>;
+ funnel_apss0_in_etm2: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm2_out_funnel_apss0>;
+ };
+ };
+
+ port@4 {
+ reg = <7>;
+ funnel_apss0_in_etm3: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm3_out_funnel_apss0>;
+ };
+ };
+
+ };
+
};
- cti1: cti@811000 {
- compatible = "arm,coresight-cti";
- reg = <0x811000 0x1000>;
- reg-names = "cti-base";
+ tpiu: tpiu@820000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b912>;
+ coresight-name = "coresight-tpiu";
- coresight-id = <8>;
- coresight-name = "coresight-cti1";
- coresight-nr-inports = <0>;
+ reg = <0x820000 0x1000>,
+ <0x1100000 0xb0000>;
+ reg-names = "tpiu-base", "nidnt-base";
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
};
- cti2: cti@812000 {
- compatible = "arm,coresight-cti";
- reg = <0x812000 0x1000>;
- reg-names = "cti-base";
+ etm0: etm@84c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b955>;
- coresight-id = <9>;
- coresight-name = "coresight-cti2";
- coresight-nr-inports = <0>;
+ reg = <0x84c000 0x1000>;
+ cpu = <&CPU0>;
+ coresight-name = "coresight-etm0";
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ port {
+ etm0_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm0>;
+ };
+ };
};
- cti3: cti@813000 {
- compatible = "arm,coresight-cti";
- reg = <0x813000 0x1000>;
- reg-names = "cti-base";
+ etm1: etm@84d000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b955>;
- coresight-id = <10>;
- coresight-name = "coresight-cti3";
- coresight-nr-inports = <0>;
+ reg = <0x84d000 0x1000>;
+ cpu = <&CPU1>;
+ coresight-name = "coresight-etm1";
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ port {
+ etm1_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm1>;
+ };
+ };
};
- cti4: cti@814000 {
- compatible = "arm,coresight-cti";
- reg = <0x814000 0x1000>;
- reg-names = "cti-base";
+ etm2: etm@84e000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b955>;
- coresight-id = <11>;
- coresight-name = "coresight-cti4";
- coresight-nr-inports = <0>;
+ reg = <0x84e000 0x1000>;
+ cpu = <&CPU2>;
+ coresight-name = "coresight-etm2";
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ port {
+ etm2_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm2>;
+ };
+ };
};
- cti5: cti@815000 {
- compatible = "arm,coresight-cti";
- reg = <0x815000 0x1000>;
- reg-names = "cti-base";
+ etm3: etm@84f000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b955>;
- coresight-id = <12>;
- coresight-name = "coresight-cti5";
- coresight-nr-inports = <0>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti6: cti@816000 {
- compatible = "arm,coresight-cti";
- reg = <0x816000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <13>;
- coresight-name = "coresight-cti6";
- coresight-nr-inports = <0>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
-
- qcom,cti-gpio-trigout = <2>;
- pinctrl-names = "cti-trigout-pctrl";
- pinctrl-0 = <&trigout_a0>;
- };
-
- cti7: cti@817000 {
- compatible = "arm,coresight-cti";
- reg = <0x817000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <14>;
- coresight-name = "coresight-cti7";
- coresight-nr-inports = <0>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti8: cti@818000 {
- compatible = "arm,coresight-cti";
- reg = <0x818000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <15>;
- coresight-name = "coresight-cti8";
- coresight-nr-inports = <0>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_cpu0: cti@851000 {
- compatible = "arm,coresight-cti";
- reg = <0x851000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <16>;
- coresight-name = "coresight-cti-cpu0";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU0>;
-
- qcom,cti-save;
+ reg = <0x84f000 0x1000>;
+ coresight-name = "coresight-etm3";
+ cpu = <&CPU3>;
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
+ clock-names = "apb_pclk";
- cti_cpu1: cti@852000 {
- compatible = "arm,coresight-cti";
- reg = <0x852000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <17>;
- coresight-name = "coresight-cti-cpu1";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU1>;
-
- qcom,cti-save;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_cpu2: cti@853000 {
- compatible = "arm,coresight-cti";
- reg = <0x853000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <18>;
- coresight-name = "coresight-cti-cpu2";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU2>;
-
- qcom,cti-save;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_cpu3: cti@854000 {
- compatible = "arm,coresight-cti";
- reg = <0x854000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <19>;
- coresight-name = "coresight-cti-cpu3";
- coresight-nr-inports = <0>;
- coresight-cti-cpu = <&CPU3>;
-
- qcom,cti-save;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_rpm_cpu0: cti@83c000 {
- compatible = "arm,coresight-cti";
- reg = <0x83c000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <20>;
- coresight-name = "coresight-cti-rpm-cpu0";
- coresight-nr-inports = <0>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_modem_cpu0: cti@838000 {
- compatible = "arm,coresight-cti";
- reg = <0x838000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <21>;
- coresight-name = "coresight-cti-modem-cpu0";
- coresight-nr-inports = <0>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_wcn_cpu0: cti@835000 {
- compatible = "arm,coresight-cti";
- reg = <0x835000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <22>;
- coresight-name = "coresight-cti-wcn-cpu0";
- coresight-nr-inports = <0>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- cti_video_cpu0: cti@830000 {
- compatible = "arm,coresight-cti";
- reg = <0x830000 0x1000>;
- reg-names = "cti-base";
-
- coresight-id = <23>;
- coresight-name = "coresight-cti-video-cpu0";
- coresight-nr-inports = <0>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ port {
+ etm3_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm3>;
+ };
+ };
};
stm: stm@802000 {
- compatible = "arm,coresight-stm";
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b962>;
+
reg = <0x802000 0x1000>,
<0x9280000 0x180000>;
- reg-names = "stm-base", "stm-data-base";
+ reg-names = "stm-base", "stm-stimulus-base";
- coresight-id = <24>;
coresight-name = "coresight-stm";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <7>;
+
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ port {
+ stm_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_stm>;
+ };
+ };
+ };
+
+ cti0: cti@810000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x810000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti0";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti1: cti@811000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x811000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti1";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti2: cti@812000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x812000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti2";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti3: cti@813000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x813000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti3";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti4: cti@814000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x814000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti4";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti5: cti@815000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x815000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti5";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti6: cti@816000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x816000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti6";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti7: cti@817000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x817000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti7";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti8: cti@818000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x818000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti8";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu0: cti@851000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x851000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu0";
+ cpu = <&CPU0>;
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu1: cti@852000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x852000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu1";
+ cpu = <&CPU1>;
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu2: cti@853000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x853000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu2";
+ cpu = <&CPU2>;
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu3: cti@854000{
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x854000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-cpu3";
+ cpu = <&CPU3>;
+ qcom,cti-save;
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_modem_cpu0: cti@838000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x838000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-modem-cpu0";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Venus CTI */
+ cti_video_cpu0: cti@830000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x830000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-video-cpu0";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Pronto CTI */
+ cti_wcn_cpu0: cti@835000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x835000 0x1000>;
+ reg-names = "cti-base";
+ coresight-name = "coresight-cti-wcn-cpu0";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ wcn_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-wcn-etm0";
+ qcom,inst-id = <3>;
+
+ port {
+ wcn_etm0_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_right_in_wcn_etm0>;
+ };
+ };
+ };
+
+ /* MSS_SCL */
+ modem_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-modem-etm0";
+ qcom,inst-id = <11>;
+
+ port {
+ modem_etm0_out_funnel_right: endpoint {
+ remote-endpoint = <&funnel_in0_in_modem_etm0>;
+ };
+ };
+ };
+
+ rpm_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-rpm-etm0";
+ qcom,inst-id = <4>;
+
+ port {
+ rpm_etm0_out_funnel_center: endpoint {
+ remote-endpoint = <&funnel_in0_in_rpm_etm0>;
+ };
+ };
};
csr: csr@801000 {
@@ -415,209 +696,52 @@
reg = <0x801000 0x1000>;
reg-names = "csr-base";
- coresight-id = <25>;
coresight-name = "coresight-csr";
- coresight-nr-inports = <0>;
+ qcom,usb-bam-support;
+ qcom,hwctrl-set-support;
+ qcom,set-byte-cntr-support;
qcom,blk-size = <1>;
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- funnel_apss: funnel@855000 {
- compatible = "arm,coresight-funnel";
- reg = <0x855000 0x1000>;
- reg-names = "funnel-base";
-
- coresight-id = <26>;
- coresight-name = "coresight-funnel-apss";
- coresight-nr-inports = <4>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <4>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- etm0: etm@84c000 {
- compatible = "arm,coresight-etm";
- reg = <0x84c000 0x1000>;
- reg-names = "etm-base";
-
- coresight-id = <27>;
- coresight-name = "coresight-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss>;
- coresight-child-ports = <0>;
- coresight-etm-cpu = <&CPU0>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- etm1: etm@84d000 {
- compatible = "arm,coresight-etm";
- reg = <0x84d000 0x1000>;
- reg-names = "etm-base";
-
- coresight-id = <28>;
- coresight-name = "coresight-etm1";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss>;
- coresight-child-ports = <1>;
- coresight-etm-cpu = <&CPU1>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- etm2: etm@84e000 {
- compatible = "arm,coresight-etm";
- reg = <0x84e000 0x1000>;
- reg-names = "etm-base";
-
- coresight-id = <29>;
- coresight-name = "coresight-etm2";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss>;
- coresight-child-ports = <2>;
- coresight-etm-cpu = <&CPU2>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- etm3: etm@84f000 {
- compatible = "arm,coresight-etm";
- reg = <0x84f000 0x1000>;
- reg-names = "etm-base";
-
- coresight-id = <30>;
- coresight-name = "coresight-etm3";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_apss>;
- coresight-child-ports = <3>;
- coresight-etm-cpu = <&CPU3>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- hwevent: hwevent@86c000 {
- compatible = "qcom,coresight-hwevent";
- reg = <0x86c000 0x108>,
- <0x86cfb0 0x4>,
- <0x78c5010 0x4>,
- <0x7885010 0x4>;
- reg-names = "wrapper-mux", "wrapper-lockaccess", "usbbam-mux",
- "blsp-mux";
- coresight-id = <31>;
- coresight-name = "coresight-hwevent";
- coresight-nr-inports = <0>;
-
- clocks = <&clock_rpm clk_qdss_clk>,
- <&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
- };
-
- rpm_etm0 {
- compatible = "qcom,coresight-remote-etm";
-
- coresight-id = <32>;
- coresight-name = "coresight-rpm-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <0>;
-
- qcom,inst-id = <4>;
- };
-
- wcn_etm0 {
- compatible = "qcom,coresight-remote-etm";
-
- coresight-id = <33>;
- coresight-name = "coresight-wcn-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in3>;
- coresight-child-ports = <0>;
-
- qcom,inst-id = <3>;
- };
-
- modem_etm0 {
- compatible = "qcom,coresight-remote-etm";
-
- coresight-id = <34>;
- coresight-name = "coresight-modem-etm0";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in0>;
- coresight-child-ports = <2>;
-
- qcom,inst-id = <2>;
- };
-
- fuse: fuse@5e01c {
- compatible = "arm,coresight-fuse-v2";
- reg = <0x5e01c 0x8>,
- <0x58040 0x4>,
- <0x5e00c 0x4>;
- reg-names = "fuse-base", "nidnt-fuse-base", "qpdi-fuse-base";
-
- coresight-id = <35>;
- coresight-name = "coresight-fuse";
- coresight-nr-inports = <0>;
- };
-
- qpdi: qpdi@1941000 {
- compatible = "qcom,coresight-qpdi";
- reg = <0x1941000 0x4>;
- reg-names = "qpdi-base";
-
- coresight-id = <36>;
- coresight-name = "coresight-qpdi";
- coresight-nr-inports = <0>;
-
- vdd-supply = <&pm8909_l11>;
- qcom,vdd-voltage-level = <2800000 2950000>;
- qcom,vdd-current-level = <15000 400000>;
-
- vdd-io-supply = <&pm8909_l12>;
- qcom,vdd-io-voltage-level = <1800000 2950000>;
- qcom,vdd-io-current-level = <200 50000>;
};
dbgui: dbgui@86d000 {
compatible = "qcom,coresight-dbgui";
reg = <0x86d000 0x1000>;
reg-names = "dbgui-base";
-
- coresight-id = <37>;
coresight-name = "coresight-dbgui";
- coresight-nr-inports = <0>;
- coresight-outports = <0>;
- coresight-child-list = <&funnel_in2>;
- coresight-child-ports = <2>;
qcom,dbgui-addr-offset = <0x30>;
- qcom,dbgui-data-offset = <0xB0>;
- qcom,dbgui-size = <32>;
+ qcom,dbgui-data-offset = <0x130>;
+ qcom,dbgui-size = <64>;
clocks = <&clock_rpm clk_qdss_clk>,
<&clock_rpm clk_qdss_a_clk>;
- clock-names = "core_clk", "core_a_clk";
+ clock-names = "apb_pclk";
+
+ port {
+ dbgui_out_funnel_center: endpoint {
+ remote-endpoint = <&funnel_center_in_dbgui>;
+ };
+ };
};
+
+ hwevent: hwevent@86c000 {
+ compatible = "qcom,coresight-hwevent";
+
+ reg = <0x86c000 0x108>,
+ <0x86cfb0 0x4>,
+ <0x78c5010 0x4>,
+ <0x7885010 0x4>;
+
+ reg-names = "center-wrapper-mux", "center-wrapper-lockaccess",
+ "right-wrapper-mux", "right-wrapper-lockaccess";
+
+ coresight-csr = <&csr>;
+ coresight-name = "coresight-hwevent";
+
+ clocks = <&clock_rpm clk_qdss_clk>,
+ <&clock_rpm clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
index 858429b..cd21e6e 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi
@@ -33,12 +33,6 @@
qcom,ion-heap-type = "DMA";
};
- modem_heap: qcom,ion-heap@26 { /* MODEM HEAP */
- reg = <26>;
- memory-region = <&modem_adsp_mem>;
- qcom,ion-heap-type = "DMA";
- };
-
qcom,ion-heap@19 { /* QSEECOM TA HEAP */
reg = <19>;
memory-region = <&qseecom_ta_mem>;
diff --git a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
index 18fc575..e2fbc9e 100644
--- a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi
@@ -410,27 +410,3 @@
};
};
};
-
-/* CoreSight */
-&tpiu {
- pinctrl-names = "sdcard", "trace", "swduart",
- "swdtrc", "jtag", "spmi";
- /* NIDnT */
- pinctrl-0 = <&qdsd_clk_sdcard &qdsd_cmd_sdcard
- &qdsd_data0_sdcard &qdsd_data1_sdcard
- &qdsd_data2_sdcard &qdsd_data3_sdcard>;
- pinctrl-1 = <&qdsd_clk_trace &qdsd_cmd_trace
- &qdsd_data0_trace &qdsd_data1_trace
- &qdsd_data2_trace &qdsd_data3_trace>;
- pinctrl-2 = <&qdsd_cmd_swduart &qdsd_data0_swduart
- &qdsd_data1_swduart &qdsd_data2_swduart
- &qdsd_data3_swduart>;
- pinctrl-3 = <&qdsd_clk_swdtrc &qdsd_cmd_swdtrc
- &qdsd_data0_swdtrc &qdsd_data1_swdtrc
- &qdsd_data2_swdtrc &qdsd_data3_swdtrc>;
- pinctrl-4 = <&qdsd_cmd_jtag &qdsd_data0_jtag
- &qdsd_data1_jtag &qdsd_data2_jtag
- &qdsd_data3_jtag>;
- pinctrl-5 = <&qdsd_clk_spmi &qdsd_cmd_spmi
- &qdsd_data0_spmi &qdsd_data3_spmi>;
-};
diff --git a/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi
new file mode 100644
index 0000000..5eeaa21
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi
@@ -0,0 +1,163 @@
+/* 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.
+ */
+
+&soc {
+ qcom,vidc@1d00000 {
+ compatible = "qcom,msm-vidc";
+ reg = <0x01d00000 0xff000>;
+ interrupts = <0 44 0>;
+ qcom,hfi-version = "3xx";
+ venus-supply = <&gdsc_venus>;
+ venus-core0-supply = <&gdsc_venus_core0>;
+ clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>,
+ <&clock_gcc clk_gcc_venus0_ahb_clk>,
+ <&clock_gcc clk_gcc_venus0_axi_clk>;
+ clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk";
+ qcom,clock-configs = <0x1 0x0 0x0 0x0>;
+ qcom,sw-power-collapse;
+ qcom,slave-side-cp;
+ qcom,hfi = "venus";
+ qcom,reg-presets = <0xe0020 0x05555556>,
+ <0xe0024 0x05555556>,
+ <0x80124 0x00000003>;
+ qcom,qdss-presets = <0x826000 0x1000>,
+ <0x827000 0x1000>,
+ <0x822000 0x1000>,
+ <0x803000 0x1000>,
+ <0x9180000 0x1000>,
+ <0x9181000 0x1000>;
+ qcom,max-hw-load = <244800>; /* 1080p@30 + 720p@30 */
+ qcom,firmware-name = "venus";
+ qcom,allowed-clock-rates = <307200000 266670000 133330000>;
+ qcom,clock-freq-tbl {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,cycles-per-mb = <2316>;
+ qcom,low-power-mode-factor = <32768>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xf3ffffff>;
+ qcom,cycles-per-mb = <788>;
+ };
+ qcom,profile-hevcdec {
+ qcom,codec-mask = <0x0c000000>;
+ qcom,cycles-per-mb = <1015>;
+ };
+ };
+
+ /* MMUs */
+ non_secure_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_ns";
+ iommus = <&apps_iommu 0x800 0x00>,
+ <&apps_iommu 0x807 0x00>,
+ <&apps_iommu 0x808 0x27>,
+ <&apps_iommu 0x811 0x0>;
+ buffer-types = <0xfff>;
+ virtual-addr-pool = <0x5dc00000 0x8f000000>;
+ };
+
+ secure_bitstream_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_bitstream";
+ iommus = <&apps_iommu 0x90c 0x20>;
+ buffer-types = <0x241>;
+ virtual-addr-pool = <0x4b000000 0x12c00000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_pixel";
+ iommus = <&apps_iommu 0x900 0x00>,
+ <&apps_iommu 0x909 0x20>,
+ <&apps_iommu 0x90a 0x00>,
+ <&apps_iommu 0x90b 0x20>,
+ <&apps_iommu 0x90e 0x00>;
+ buffer-types = <0x106>;
+ virtual-addr-pool = <0x25800000 0x25800000>;
+ qcom,secure-context-bank;
+ };
+
+ secure_non_pixel_cb {
+ compatible = "qcom,msm-vidc,context-bank";
+ label = "venus_sec_non_pixel";
+ iommus = <&apps_iommu 0x9c0 0x00>,
+ <&apps_iommu 0x907 0x00>,
+ <&apps_iommu 0x908 0x20>,
+ <&apps_iommu 0x90d 0x20>,
+ <&apps_iommu 0x90f 0x00>;
+ buffer-types = <0x480>;
+ virtual-addr-pool = <0x1000000 0x24800000>;
+ qcom,secure-context-bank;
+ };
+
+ /* Buses */
+ venus_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "venus-ddr-gov";
+ qcom,bus-range-kbps = <1000 917000>;
+ };
+
+ arm9_bus_ddr {
+ compatible = "qcom,msm-vidc,bus";
+ label = "venus-arm9-ddr";
+ qcom,bus-master = <MSM_BUS_MASTER_VIDEO_P0>;
+ qcom,bus-slave = <MSM_BUS_SLAVE_EBI_CH0>;
+ qcom,bus-governor = "performance";
+ qcom,bus-range-kbps = <1 1>;
+ };
+ };
+
+ venus-ddr-gov {
+ compatible = "qcom,msm-vidc,governor,table";
+ name = "venus-ddr-gov";
+ status = "ok";
+ qcom,bus-freq-table {
+ qcom,profile-enc {
+ qcom,codec-mask = <0x55555555>;
+ qcom,load-busfreq-tbl =
+ <244800 841000>, /* 1080p30E */
+ <216000 740000>, /* 720p60E */
+ <194400 680000>, /* FWVGA120E */
+ <144000 496000>, /* VGA120E */
+ <108000 370000>, /* 720p30E */
+ <97200 340000>, /* FWVGA60E */
+ <48600 170000>, /* FWVGA30E */
+ <72000 248000>, /* VGA60E */
+ <36000 124000>, /* VGA30E */
+ <18000 70000>, /* QVGA60E */
+ <9000 35000>, /* QVGA30E */
+ <0 0>;
+ };
+ qcom,profile-dec {
+ qcom,codec-mask = <0xffffffff>;
+ qcom,load-busfreq-tbl =
+ <244800 605000>, /* 1080p30D */
+ <216000 540000>, /* 720p60D */
+ <194400 484000>, /* FWVGA120D */
+ <144000 360000>, /* VGA120D */
+ <108000 270000>, /* 720p30D */
+ <97200 242000>, /* FWVGA60D */
+ <48600 121000>, /* FWVGA30D */
+ <72000 180000>, /* VGA60D */
+ <36000 90000>, /* VGA30D */
+ <18000 45000>, /* HVGA30D */
+ <0 0>;
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi
index a6d42f1..a72fdbf 100644
--- a/arch/arm64/boot/dts/qcom/msm8909.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi
@@ -239,6 +239,7 @@
#include "msm8909-gpu.dtsi"
#include "msm8909-coresight.dtsi"
#include "msm8909-bus.dtsi"
+#include "msm8909-vidc.dtsi"
#include "msm8909-mdss.dtsi"
#include "msm8909-mdss-pll.dtsi"
@@ -1947,19 +1948,6 @@
memory-region = <&modem_adsp_mem>;
};
- mcd {
- compatible = "qcom,mcd";
- qcom,ce-hw-instance = <0>;
- qcom,ce-device = <0>;
- clocks = <&clock_gcc clk_crypto_clk_src>,
- <&clock_gcc clk_gcc_crypto_clk>,
- <&clock_gcc clk_gcc_crypto_ahb_clk>,
- <&clock_gcc clk_gcc_crypto_axi_clk>;
- clock-names = "core_clk_src", "core_clk",
- "iface_clk", "bus_clk";
- qcom,ce-opp-freq = <100000000>;
- };
-
cpu0_slp_sts: cpu-sleep-status@b088008 {
reg = <0xb088008 0x100>;
qcom,sleep-status-mask= <0x80000>;
diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
index 8149eb2..9dd80f0 100644
--- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
+++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts
@@ -320,4 +320,5 @@
&mdss_dsi0 {
qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>;
qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>;
+ qcom,platform-enable-gpio = <&msm_gpio 59 0>;
};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi
new file mode 100644
index 0000000..465859a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&int_codec {
+ status = "okay";
+ qcom,msm-hs-micbias-type = "external";
+
+ asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f";
+ asoc-wsa-codec-prefixes = "SpkrMono";
+
+ msm-vdd-wsa-switch-supply = <&pm8937_l13>;
+ qcom,msm-vdd-wsa-switch-voltage = <3075000>;
+ qcom,msm-vdd-wsa-switch-current = <5000>;
+};
+
+&wsa881x_i2c_f {
+ status = "okay";
+};
+
+&wsa881x_i2c_45 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi
new file mode 100644
index 0000000..d6d85fa
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi
@@ -0,0 +1,250 @@
+/*
+ * 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 "msm8917-pinctrl.dtsi"
+/* #include "msm8917-camera-sensor-cdp.dtsi"*/
+
+&soc {
+ 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 128 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 127 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 91 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ };
+
+ home {
+ label = "home";
+ gpios = <&tlmm 86 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ debounce-interval = <15>;
+ };
+ };
+
+ hbtp {
+ compatible = "qcom,hbtp-input";
+ vcc_ana-supply = <&pm8937_l10>;
+ vcc_dig-supply = <&pm8937_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>;
+ };
+
+ usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ interrupt-names = "vbus_det_irq";
+ interrupt-parent = <&tlmm>;
+ interrupts = <130 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb_mode_select>;
+ qcom,gpio-mode-sel = <&tlmm 130 0>;
+ qcom,notify-host-mode;
+ status = "disabled";
+ };
+};
+
+&flash_led {
+ compatible = "qcom,qpnp-flash-led";
+ reg = <0xd300 0x100>;
+ pinctrl-names = "flash_led_enable","flash_led_disable";
+ pinctrl-0 = <&rear_flash_led_enable>;
+ pinctrl-1 = <&rear_flash_led_disable>;
+ qcom,follow-otst2-rb-disabled;
+};
+
+&wled {
+ qcom,cons-sync-write-delay-us = <1000>;
+};
+
+&pmi_haptic{
+ qcom,actuator-type = "lra";
+ qcom,wave-play-rate-us = <4165>;
+ qcom,lra-auto-res-mode = "qwd";
+ qcom,lra-high-z = "opt1";
+ qcom,lra-res-cal-period = <0>;
+};
+
+&blsp1_uart2 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+#include "msm8937-mdss-panels.dtsi"
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_truly_720_vid>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+ qcom,platform-te-gpio = <&tlmm 24 0>;
+ qcom,platform-reset-gpio = <&tlmm 60 0>;
+ qcom,platform-bklight-en-gpio = <&tlmm 98 0>;
+};
+
+&dsi_truly_720_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_720_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,ulps-enabled;
+ qcom,partial-update-enabled;
+ qcom,panel-roi-alignment = <2 2 2 2 2 2>;
+};
+
+&tlmm {
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ };
+ };
+ };
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_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";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 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>;
+
+ #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 67 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
+&i2c_3 {
+ status = "okay";
+ synaptics@22 {
+ compatible = "synaptics,dsx";
+ reg = <0x22>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <65 0x2008>;
+ avdd-supply = <&pm8937_l10>;
+ vdd-supply = <&pm8937_l5>;
+ synaptics,vdd-voltage = <1880000 1880000>;
+ synaptics,avdd-voltage = <3008000 3008000>;
+ synaptics,vdd-current = <40000>;
+ synaptics,avdd-current = <20000>;
+ pinctrl-names = "pmx_ts_active","pmx_ts_suspend";
+ pinctrl-0 = <&ts_int_active &ts_reset_active>;
+ pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
+ synaptics,display-coords = <0 0 719 1439>;
+ synaptics,panel-coords = <0 0 719 1439>;
+ synaptics,reset-gpio = <&tlmm 64 0x00>;
+ synaptics,irq-gpio = <&tlmm 65 0x2008>;
+ synaptics,disable-gpios;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi
new file mode 100644
index 0000000..fde4847
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include "msm8917-pinctrl.dtsi"
+/* #include "msm8917-camera-sensor-cdp.dtsi"*/
+
+&soc {
+ 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 128 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x210>;
+ debounce-interval = <15>;
+ };
+
+ camera_snapshot {
+ label = "camera_snapshot";
+ gpios = <&tlmm 127 0x1>;
+ linux,input-type = <1>;
+ linux,code = <0x2fe>;
+ debounce-interval = <15>;
+ };
+
+ vol_up {
+ label = "volume_up";
+ gpios = <&tlmm 91 0x1>;
+ linux,input-type = <1>;
+ linux,code = <115>;
+ debounce-interval = <15>;
+ };
+
+ home {
+ label = "home";
+ gpios = <&tlmm 86 0x1>;
+ linux,input-type = <1>;
+ linux,code = <102>;
+ debounce-interval = <15>;
+ };
+ };
+
+ hbtp {
+ compatible = "qcom,hbtp-input";
+ vcc_ana-supply = <&pm8937_l10>;
+ vcc_dig-supply = <&pm8937_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>;
+ };
+
+ usb_detect {
+ compatible = "qcom,gpio-usbdetect";
+ interrupt-names = "vbus_det_irq";
+ interrupt-parent = <&tlmm>;
+ interrupts = <130 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb_mode_select>;
+ qcom,gpio-mode-sel = <&tlmm 130 0>;
+ qcom,notify-host-mode;
+ status = "disabled";
+ };
+};
+
+&blsp1_uart2 {
+ status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart_console_active>;
+};
+
+#include "msm8937-mdss-panels.dtsi"
+
+&mdss_mdp {
+ qcom,mdss-pref-prim-intf = "dsi";
+};
+
+&mdss_dsi {
+ hw-config = "single_dsi";
+};
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_truly_720_vid>;
+ pinctrl-names = "mdss_default", "mdss_sleep";
+ pinctrl-0 = <&mdss_dsi_active &mdss_te_active>;
+ pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>;
+
+ qcom,platform-te-gpio = <&tlmm 24 0>;
+ qcom,platform-reset-gpio = <&tlmm 60 0>;
+ qcom,platform-bklight-en-gpio = <&tlmm 98 0>;
+};
+
+&dsi_truly_720_vid {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp";
+};
+
+&dsi_truly_720_cmd {
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,ulps-enabled;
+ qcom,partial-update-enabled;
+ qcom,panel-roi-alignment = <2 2 2 2 2 2>;
+};
+
+&tlmm {
+ tlmm_gpio_key {
+ gpio_key_active: gpio_key_active {
+ mux {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ };
+ };
+
+ gpio_key_suspend: gpio_key_suspend {
+ mux {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ function = "gpio";
+ };
+
+ config {
+ pins = "gpio86", "gpio91", "gpio127", "gpio128";
+ };
+ };
+ };
+};
+
+&sdhc_1 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l8>;
+ qcom,vdd-voltage-level = <2900000 2900000>;
+ qcom,vdd-current-level = <200 570000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_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";
+};
+
+&sdhc_2 {
+ /* device core power supply */
+ vdd-supply = <&pm8937_l11>;
+ qcom,vdd-voltage-level = <2950000 2950000>;
+ qcom,vdd-current-level = <15000 800000>;
+
+ /* device communication power supply */
+ vdd-io-supply = <&pm8937_l12>;
+ qcom,vdd-io-voltage-level = <1800000 2950000>;
+ qcom,vdd-io-current-level = <200 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>;
+
+ #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 67 0>;
+ interrupt-names = "hc_irq", "pwr_irq", "status_irq";
+ cd-gpios = <&tlmm 67 0x1>;
+
+ qcom,clk-rates = <400000 20000000 25000000 50000000 100000000
+ 200000000>;
+ qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104";
+
+ status = "ok";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi
new file mode 100644
index 0000000..87303c5
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi
@@ -0,0 +1,1039 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+&soc {
+ tmc_etr: tmc@6028000 {
+ compatible = "arm,primecell";
+ reg = <0x6028000 0x1000>,
+ <0x6044000 0x15000>;
+ reg-names = "tmc-base", "bam-base";
+
+ interrupts = <0 166 0>;
+ interrupt-names = "byte-cntr-irq";
+
+ arm,buffer-size = <0x100000>;
+ arm,sg-enable;
+ qcom,force-reg-dump;
+
+ coresight-name = "coresight-tmc-etr";
+ coresight-csr = <&csr>;
+ coresight-ctis = <&cti0 &cti8>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ tmc_etr_in_replicator: endpoint {
+ slave-mode;
+ remote-endpoint = <&replicator_out_tmc_etr>;
+ };
+ };
+ };
+
+ replicator: replicator@6026000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b909>;
+
+ reg = <0x6026000 0x1000>;
+ reg-names = "replicator-base";
+
+ coresight-name = "coresight-replicator";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ replicator_out_tmc_etr: endpoint {
+ remote-endpoint =
+ <&tmc_etr_in_replicator>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ replicator_in_tmc_etf: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tmc_etf_out_replicator>;
+ };
+ };
+ };
+ };
+
+ tmc_etf: tmc@6027000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b961>;
+
+ reg = <0x6027000 0x1000>;
+ reg-names = "tmc-base";
+
+ coresight-name = "coresight-tmc-etf";
+ coresight-csr = <&csr>;
+
+ arm,default-sink;
+ qcom,force-reg-dump;
+
+ coresight-ctis = <&cti0 &cti8>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ tmc_etf_out_replicator:endpoint {
+ remote-endpoint =
+ <&replicator_in_tmc_etf>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ tmc_etf_in_funnel_in0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_in0_out_tmc_etf>;
+ };
+ };
+ };
+ };
+
+ funnel_in0: funnel@6021000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6021000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-in0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_in0_out_tmc_etf: endpoint {
+ remote-endpoint =
+ <&tmc_etf_in_funnel_in0>;
+ };
+ };
+
+ port@1 {
+ reg = <7>;
+ funnel_in0_in_stm: endpoint {
+ slave-mode;
+ remote-endpoint = <&stm_out_funnel_in0>;
+ };
+ };
+
+ port@2 {
+ reg = <6>;
+ funnel_in0_in_tpda: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpda_out_funnel_in0>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ funnel_in0_in_funnel_center: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_center_out_funnel_in0>;
+ };
+ };
+
+ port@4 {
+ reg = <4>;
+ funnel_in0_in_funnel_right: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_right_out_funnel_in0>;
+ };
+ };
+
+ port@5 {
+ reg = <5>;
+ funnel_in0_in_funnel_mm: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_mm_out_funnel_in0>;
+ };
+ };
+ };
+ };
+
+ funnel_mm: funnel@6130000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6130000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-mm";
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_mm_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_mm>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_mm_in_wcn_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&wcn_etm0_out_funnel_mm>;
+ };
+ };
+
+ port@2 {
+ reg = <4>;
+ funnel_mm_in_funnel_cam: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_cam_out_funnel_mm>;
+ };
+ };
+
+ port@3 {
+ reg = <5>;
+ funnel_mm_in_audio_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&audio_etm0_out_funnel_mm>;
+ };
+ };
+ };
+ };
+
+ funnel_center: funnel@6100000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6100000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-center";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_center_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_center>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_center_in_rpm_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&rpm_etm0_out_funnel_center>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ funnel_center_in_dbgui: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&dbgui_out_funnel_center>;
+ };
+ };
+ };
+ };
+
+ funnel_right: funnel@6120000 {
+ compatible = "arm,primecell";
+
+ reg = <0x6120000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-right";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_right_out_funnel_in0: endpoint {
+ remote-endpoint =
+ <&funnel_in0_in_funnel_right>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ funnel_right_in_modem_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&modem_etm0_out_funnel_right>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ funnel_right_in_funnel_apss: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&funnel_apss_out_funnel_right>;
+ };
+ };
+ };
+ };
+
+ funnel_cam: funnel@6132000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x6132000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-cam";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ funnel_cam_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_mm_in_funnel_cam>;
+ };
+ };
+ };
+
+ funnel_apss: funnel@61a1000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b908>;
+
+ reg = <0x61a1000 0x1000>;
+ reg-names = "funnel-base";
+
+ coresight-name = "coresight-funnel-apss";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ funnel_apss_out_funnel_right: endpoint {
+ remote-endpoint =
+ <&funnel_right_in_funnel_apss>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ funnel_apss0_in_etm0: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm0_out_funnel_apss0>;
+ };
+ };
+
+ port@2 {
+ reg = <1>;
+ funnel_apss0_in_etm1: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm1_out_funnel_apss0>;
+ };
+ };
+
+ port@3 {
+ reg = <2>;
+ funnel_apss0_in_etm2: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm2_out_funnel_apss0>;
+ };
+ };
+
+ port@4 {
+ reg = <3>;
+ funnel_apss0_in_etm3: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&etm3_out_funnel_apss0>;
+ };
+ };
+ };
+ };
+
+ etm0: etm@61bc000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61bc000 0x1000>;
+ cpu = <&CPU0>;
+ reg-names = "etm-base";
+
+ coresight-name = "coresight-etm0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ port {
+ etm0_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm0>;
+ };
+ };
+ };
+
+ etm1: etm@61bd000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61bd000 0x1000>;
+ cpu = <&CPU1>;
+ coresight-name = "coresight-etm1";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm1_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm1>;
+ };
+ };
+ };
+
+ etm2: etm@61be000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61be000 0x1000>;
+ cpu = <&CPU2>;
+ coresight-name = "coresight-etm2";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm2_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm2>;
+ };
+ };
+ };
+
+ etm3: etm@61bf000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x000bb95d>;
+
+ reg = <0x61bf000 0x1000>;
+ cpu = <&CPU3>;
+ coresight-name = "coresight-etm3";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ etm3_out_funnel_apss0: endpoint {
+ remote-endpoint = <&funnel_apss0_in_etm3>;
+ };
+ };
+ };
+
+ stm: stm@6002000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b962>;
+
+ reg = <0x6002000 0x1000>,
+ <0x9280000 0x180000>;
+ reg-names = "stm-base", "stm-data-base";
+
+ coresight-name = "coresight-stm";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ stm_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_stm>;
+ };
+ };
+ };
+
+ cti0: cti@6010000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6010000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti1: cti@6011000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6011000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti1";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti2: cti@6012000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6012000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti2";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti3: cti@6013000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6013000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti3";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti4: cti@6014000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6014000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti4";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti5: cti@6015000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6015000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti5";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti6: cti@6016000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6016000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti6";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti7: cti@6017000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6017000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti7";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti8: cti@6018000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6018000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti8";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti9: cti@6019000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6019000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti9";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti10: cti@601a000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601a000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti10";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti11: cti@601b000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601b000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti11";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti12: cti@601c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601c000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti12";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti13: cti@601d000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601d000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti13";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti14: cti@601e000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601e000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti14";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti15: cti@601f000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x601f000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti15";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu0: cti@61b8000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61b8000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu0";
+ cpu = <&CPU0>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu1: cti@61b9000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61b9000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu1";
+ cpu = <&CPU1>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu2: cti@61ba000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61ba000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu2";
+ cpu = <&CPU2>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_cpu3: cti@61bb000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x61bb000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-cpu3";
+ cpu = <&CPU3>;
+ qcom,cti-save;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ cti_modem_cpu0: cti@6124000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6124000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-modem-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Proto CTI */
+ cti_wcn_cpu0: cti@6139000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6139000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-wcn-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Venus CTI */
+ cti_video_cpu0: cti@6134000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x6134000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-video-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* LPASS CTI */
+ cti_audio_cpu0: cti@613c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x613c000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-audio-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* RPM CTI */
+ cti_rpm_cpu0: cti@610c000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b966>;
+
+ reg = <0x610c000 0x1000>;
+ reg-names = "cti-base";
+
+ coresight-name = "coresight-cti-rpm-cpu0";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ /* Proto ETM */
+ wcn_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-wcn-etm0";
+ qcom,inst-id = <3>;
+
+ port {
+ wcn_etm0_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_mm_in_wcn_etm0>;
+ };
+ };
+ };
+
+ rpm_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-rpm-etm0";
+ qcom,inst-id = <4>;
+
+ port {
+ rpm_etm0_out_funnel_center: endpoint {
+ remote-endpoint = <&funnel_center_in_rpm_etm0>;
+ };
+ };
+ };
+
+ /* LPASS ETM */
+ audio_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-audio-etm0";
+ qcom,inst-id = <5>;
+
+ port {
+ audio_etm0_out_funnel_mm: endpoint {
+ remote-endpoint = <&funnel_mm_in_audio_etm0>;
+ };
+ };
+ };
+
+ modem_etm0 {
+ compatible = "qcom,coresight-remote-etm";
+ coresight-name = "coresight-modem-etm0";
+ qcom,inst-id = <11>;
+
+ port {
+ modem_etm0_out_funnel_right: endpoint {
+ remote-endpoint = <&funnel_right_in_modem_etm0>;
+ };
+ };
+ };
+
+ csr: csr@6001000 {
+ compatible = "qcom,coresight-csr";
+ reg = <0x6001000 0x1000>;
+ reg-names = "csr-base";
+
+ coresight-name = "coresight-csr";
+
+ qcom,usb-bam-support;
+ qcom,hwctrl-set-support;
+ qcom,set-byte-cntr-support;
+
+ qcom,blk-size = <1>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+
+ dbgui: dbgui@6108000 {
+ compatible = "qcom,coresight-dbgui";
+ reg = <0x6108000 0x1000>;
+ reg-names = "dbgui-base";
+
+ coresight-name = "coresight-dbgui";
+
+ qcom,dbgui-addr-offset = <0x30>;
+ qcom,dbgui-data-offset = <0x130>;
+ qcom,dbgui-size = <32>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ dbgui_out_funnel_center: endpoint {
+ remote-endpoint = <&funnel_center_in_dbgui>;
+ };
+ };
+ };
+
+ tpda: tpda@6003000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b969>;
+
+ reg = <0x6003000 0x1000>;
+ reg-names = "tpda-base";
+
+ coresight-name = "coresight-tpda";
+
+ qcom,tpda-atid = <64>;
+ qcom,cmb-elem-size = <0 32>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ tpda_out_funnel_in0: endpoint {
+ remote-endpoint = <&funnel_in0_in_tpda>;
+ };
+ };
+
+ port@1 {
+ reg = <0>;
+ tpda_in_tpdm_dcc: endpoint {
+ slave-mode;
+ remote-endpoint =
+ <&tpdm_dcc_out_tpda>;
+ };
+ };
+ };
+ };
+
+ tpdm_dcc: tpdm@6110000 {
+ compatible = "arm,primecell";
+ arm,primecell-periphid = <0x0003b968>;
+
+ reg = <0x6110000 0x1000>;
+ reg-names = "tpdm-base";
+
+ coresight-name = "coresight-tpdm-dcc";
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+
+ port {
+ tpdm_dcc_out_tpda: endpoint {
+ remote-endpoint = <&tpda_in_tpdm_dcc>;
+ };
+ };
+ };
+
+ hwevent: hwevent@6101000 {
+ compatible = "qcom,coresight-hwevent";
+ reg = <0x6101000 0x148>,
+ <0x6101fb0 0x4>,
+ <0x6121000 0x148>,
+ <0x6121fb0 0x4>,
+ <0x6131000 0x148>,
+ <0x6131fb0 0x4>,
+ <0x78c5010 0x4>,
+ <0x7885010 0x4>;
+ reg-names = "center-wrapper-mux", "center-wrapper-lockaccess",
+ "right-wrapper-mux", "right-wrapper-lockaccess",
+ "mm-wrapper-mux", "mm-wrapper-lockaccess",
+ "usbbam-mux", "blsp-mux";
+
+ coresight-name = "coresight-hwevent";
+ coresight-csr = <&csr>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "apb_pclk";
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
index 792d5d1..5a242db 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi
@@ -117,3 +117,46 @@
};
};
+
+&soc {
+ cpuss_dump {
+ compatible = "qcom,cpuss-dump";
+ qcom,l2_dump1 {
+ /* L2 cache dump for A53 cluster */
+ qcom,dump-node = <&L2_1>;
+ qcom,dump-id = <0xC1>;
+ };
+ qcom,l1_i_cache100 {
+ qcom,dump-node = <&L1_I_100>;
+ qcom,dump-id = <0x60>;
+ };
+ qcom,l1_i_cache101 {
+ qcom,dump-node = <&L1_I_101>;
+ qcom,dump-id = <0x61>;
+ };
+ qcom,l1_i_cache102 {
+ qcom,dump-node = <&L1_I_102>;
+ qcom,dump-id = <0x62>;
+ };
+ qcom,l1_i_cache103 {
+ qcom,dump-node = <&L1_I_103>;
+ qcom,dump-id = <0x63>;
+ };
+ qcom,l1_d_cache100 {
+ qcom,dump-node = <&L1_D_100>;
+ qcom,dump-id = <0x80>;
+ };
+ qcom,l1_d_cache101 {
+ qcom,dump-node = <&L1_D_101>;
+ qcom,dump-id = <0x81>;
+ };
+ qcom,l1_d_cache102 {
+ qcom,dump-node = <&L1_D_102>;
+ qcom,dump-id = <0x82>;
+ };
+ qcom,l1_d_cache103 {
+ qcom,dump-node = <&L1_D_103>;
+ qcom,dump-id = <0x83>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
index 800ea1c..164b781 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi
@@ -68,6 +68,20 @@
status = "ok";
};
+&soc {
+ hbtp {
+ compatible = "qcom,hbtp-input";
+ vcc_ana-supply = <&pm8937_l10>;
+ vcc_dig-supply = <&pm8937_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>;
+ };
+};
+
#include "msm8937-mdss-panels.dtsi"
&mdss_mdp {
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
index b9229e1..26fb25c 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pinctrl.dtsi
@@ -15,10 +15,11 @@
tlmm: pinctrl@1000000 {
compatible = "qcom,msm8917-pinctrl";
reg = <0x1000000 0x300000>;
- interrupts = <0 208 0>;
+ interrupts-extended = <&wakegic GIC_SPI 208 IRQ_TYPE_NONE>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
+ interrupt-parent = <&wakegpio>;
#interrupt-cells = <2>;
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
index 6200b4e..a3b4679 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi
@@ -31,7 +31,6 @@
qcom,lpm-levels {
compatible = "qcom,lpm-levels";
- qcom,use-psci;
#address-cells = <1>;
#size-cells = <0>;
@@ -40,8 +39,6 @@
#address-cells = <1>;
#size-cells = <0>;
label = "perf";
- qcom,spm-device-names = "l2";
- qcom,default-level=<0>;
qcom,psci-mode-shift = <4>;
qcom,psci-mode-mask = <0xf>;
@@ -98,11 +95,12 @@
#size-cells = <0>;
qcom,psci-mode-shift = <0>;
qcom,psci-mode-mask = <0xf>;
+ qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>;
qcom,pm-cpu-level@0 {
reg = <0>;
- qcom,psci-cpu-mode = <0>;
label = "wfi";
+ qcom,psci-cpu-mode = <1>;
qcom,latency-us = <12>;
qcom,ss-power = <463>;
qcom,energy-overhead = <23520>;
@@ -111,8 +109,8 @@
qcom,pm-cpu-level@1 {
reg = <1>;
- qcom,psci-cpu-mode = <3>;
label = "pc";
+ qcom,psci-cpu-mode = <3>;
qcom,latency-us = <180>;
qcom,ss-power = <429>;
qcom,energy-overhead = <162991>;
@@ -125,7 +123,17 @@
};
};
- qcom,cpu-sleep-status {
- compatible = "qcom,cpu-sleep-status";
+ qcom,rpm-stats@29dba0 {
+ compatible = "qcom,rpm-stats";
+ reg = <0x200000 0x1000>, <0x290014 0x4>;
+ reg-names = "phys_addr_base", "offset_addr";
+ };
+
+ qcom,rpm-master-stats@60150 {
+ compatible = "qcom,rpm-master-stats";
+ reg = <0x60150 0x5000>;
+ qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS";
+ qcom,master-stats-version = <2>;
+ qcom,master-offset = <4096>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts
new file mode 100644
index 0000000..9d8a2eb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8937 CDP";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id= <1 0>;
+ qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts
new file mode 100644
index 0000000..c7fe115
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8937.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8937 RCM";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id= <21 0>;
+ qcom,pmic-id = <0x10019 0x020037 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts
new file mode 100644
index 0000000..9785a4f
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8940.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8940 CDP";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id = <1 0>;
+ qcom,pmic-id = <0x10019 0x020040 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts
new file mode 100644
index 0000000..2cab716
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8940.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8940 RCM";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id = <21 0>;
+ qcom,pmic-id = <0x10019 0x020040 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts
new file mode 100644
index 0000000..ea6b24a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-pmi8950-cdp-mirror-lake-touch.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 CDP ML Touch";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id = <1 4>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi
new file mode 100644
index 0000000..4701101
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi
@@ -0,0 +1,104 @@
+/*
+ * 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 "pmi8950.dtsi"
+#include "msm8917-cdp-mirror-lake-touch.dtsi"
+#include "msm8917-audio-cdp.dtsi"
+
+&soc {
+ led_flash0: qcom,camera-flash {
+ cell-index = <0>;
+ compatible = "qcom,camera-flash";
+ qcom,flash-type = <1>;
+ qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>;
+ qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>;
+ qcom,switch-source = <&pmi8950_switch>;
+ };
+
+ bluetooth: bt_qca6174 {
+ compatible = "qca,qca6174";
+ qca,bt-reset-gpio = <&tlmm 129 0>; /* BT_EN */
+ };
+};
+
+&qpnp_smbcharger {
+ /delete-property/ dpdm-supply;
+};
+
+&pm8937_gpios {
+ gpio@c400 {
+ qcom,mode = <0>;
+ qcom,output-type = <0>;
+ qcom,pull = <0>;
+ qcom,vin-sel = <2>;
+ qcom,out-strength = <3>;
+ qcom,src-sel = <0>;
+ qcom,master-en = <1>;
+ status = "okay";
+ };
+};
+
+&i2c_5 { /* BLSP2 QUP1 */
+ 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>;
+ pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>;
+ clocks = <&clock_gcc clk_bb_clk2_pin>;
+ clock-names = "ref_clk";
+ };
+};
+
+&mdss_dsi0 {
+ lab-supply = <&lab_regulator>;
+ ibb-supply = <&ibb_regulator>;
+};
+
+&labibb {
+ status = "ok";
+ qpnp,qpnp-labibb-mode = "lcd";
+};
+
+&ibb_regulator {
+ qcom,qpnp-ibb-discharge-resistor = <32>;
+};
+
+&dsi_panel_pwr_supply {
+ qcom,panel-supply-entry@2 {
+ reg = <2>;
+ qcom,supply-name = "lab";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ };
+
+ qcom,panel-supply-entry@3 {
+ reg = <3>;
+ qcom,supply-name = "ibb";
+ qcom,supply-min-voltage = <4600000>;
+ qcom,supply-max-voltage = <6000000>;
+ qcom,supply-enable-load = <100000>;
+ qcom,supply-disable-load = <100>;
+ qcom,supply-post-on-sleep = <20>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts
new file mode 100644
index 0000000..a32e2b3
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 CDP";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id= <1 0>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts
new file mode 100644
index 0000000..91c4f3a
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917 External Audio Codec CDP";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id= <1 1>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
+
+&pm8937_gpios {
+ gpio@c000 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <2>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+
+ gpio@c600 {
+ status = "ok";
+ qcom,mode = <1>;
+ qcom,pull = <5>;
+ qcom,vin-sel = <0>;
+ qcom,src-sel = <0>;
+ qcom,master-en = <1>;
+ qcom,out-strength = <2>;
+ };
+};
+
+&slim_msm {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&clock_audio {
+ status = "okay";
+};
+
+&wcd9335 {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&ext_codec {
+ status = "okay";
+};
+
+&int_codec {
+ status = "disabled";
+};
+
+&wsa881x_i2c_f {
+ status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+ status = "disabled";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
index 3fe60a3..5b458b2 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts
@@ -14,7 +14,8 @@
/dts-v1/;
#include "msm8917.dtsi"
-#include "msm8917-pmi8950-mtp.dtsi"
+#include "msm8917-mtp.dtsi"
+#include "msm8917-pmi8950.dtsi"
/ {
model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 MTP";
@@ -22,3 +23,23 @@
qcom,board-id= <8 0>;
qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
};
+
+&blsp1_uart1 {
+ status = "ok";
+};
+
+&vendor {
+ mtp_batterydata: qcom,battery-data {
+ qcom,batt-id-range-pct = <15>;
+ #include "batterydata-itech-3000mah.dtsi"
+ #include "batterydata-ascent-3450mAh.dtsi"
+ };
+};
+
+&qpnp_fg {
+ qcom,battery-data = <&mtp_batterydata>;
+};
+
+&qpnp_smbcharger {
+ qcom,battery-data = <&mtp_batterydata>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts
new file mode 100644
index 0000000..a91bea1
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+
+#include "msm8917.dtsi"
+#include "msm8917-cdp.dtsi"
+#include "msm8917-pmi8950.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 RCM";
+ compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp";
+ qcom,board-id= <21 0>;
+ qcom,pmic-id = <0x10019 0x010011 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
new file mode 100644
index 0000000..9543133
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi
@@ -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.
+ */
+
+#include "pmi8950.dtsi"
+
+&qpnp_smbcharger {
+ qcom,chg-led-sw-controls;
+ qcom,chg-led-support;
+ /delete-property/ dpdm-supply;
+};
+
+&usb_otg {
+ extcon = <&qpnp_smbcharger>;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi
index f897b59..fae258d0 100644
--- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi
@@ -78,6 +78,12 @@
};
&soc {
+ int_codec: sound {
+ status = "okay";
+ qcom,msm-mbhc-hphl-swh = <1>;
+ qcom,msm-hs-micbias-type = "internal";
+ };
+
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi
index 36db486..d080539 100644
--- a/arch/arm64/boot/dts/qcom/msm8917.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi
@@ -21,7 +21,7 @@
model = "Qualcomm Technologies, Inc. MSM8917";
compatible = "qcom,msm8917";
qcom,msm-id = <303 0x0>, <308 0x0>, <309 0x0>;
- interrupt-parent = <&intc>;
+ interrupt-parent = <&wakegic>;
chosen {
bootargs = "sched_enable_hmp=1";
@@ -161,6 +161,7 @@
#include "msm8917-pm.dtsi"
#include "msm8917-ion.dtsi"
#include "msm8917-smp2p.dtsi"
+#include "msm8917-coresight.dtsi"
#include "msm8917-bus.dtsi"
#include "msm8917-mdss.dtsi"
#include "msm8917-mdss-pll.dtsi"
@@ -183,20 +184,32 @@
<0x0b002000 0x1000>;
};
+ dcc: dcc@b3000 {
+ compatible = "qcom,dcc";
+ reg = <0xb3000 0x1000>,
+ <0xb4000 0x2000>;
+ reg-names = "dcc-base", "dcc-ram-base";
+
+ clocks = <&clock_gcc clk_gcc_dcc_clk>;
+ clock-names = "apb_pclk";
+
+ qcom,save-reg;
+ };
+
wakegic: wake-gic {
- compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8937";
+ compatible = "qcom,mpm-gic-msm8937", "qcom,mpm-gic";
interrupts = <GIC_SPI 171 IRQ_TYPE_EDGE_RISING>;
reg = <0x601d0 0x1000>,
<0xb011008 0x4>; /* MSM_APCS_GCC_BASE 4K */
reg-names = "vmpm", "ipc";
- qcom,num-mpm-irqs = <96>;
+ qcom,num-mpm-irqs = <64>;
interrupt-controller;
interrupt-parent = <&intc>;
#interrupt-cells = <3>;
};
wakegpio: wake-gpio {
- compatible = "qcom,mpm-gpio", "qcom,mpm-gpio-msm8937";
+ compatible = "qcom,mpm-gpio-msm8937", "qcom,mpm-gpio";
interrupt-controller;
interrupt-parent = <&intc>;
#interrupt-cells = <2>;
@@ -482,6 +495,23 @@
#clock-cells = <1>;
};
+ msm_cpufreq: qcom,msm-cpufreq {
+ compatible = "qcom,msm-cpufreq";
+ clock-names = "cpu0_clk", "cpu1_clk", "cpu2_clk",
+ "cpu3_clk";
+ clocks = <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_bc_clk>,
+ <&clock_cpu clk_a53_bc_clk>;
+
+ qcom,cpufreq-table =
+ < 960000 >,
+ < 1094400 >,
+ < 1248000 >,
+ < 1401000 >,
+ < 1497600 >;
+ };
+
i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */
compatible = "qcom,i2c-msm-v2";
#address-cells = <1>;
@@ -713,6 +743,24 @@
qcom,target-dev = <&cpubw>;
};
+ devfreq-cpufreq {
+ cpubw-cpufreq {
+ target-dev = <&cpubw>;
+ cpu-to-dev-map =
+ < 998400 4248 >,
+ < 1094400 4541 >,
+ < 1497600 5645 >;
+ };
+
+ mincpubw-cpufreq {
+ target-dev = <&mincpubw>;
+ cpu-to-dev-map =
+ < 998400 2270 >,
+ < 1094400 4248 >,
+ < 1497600 4248 >;
+ };
+ };
+
qcom,wdt@b017000 {
compatible = "qcom,msm-watchdog";
reg = <0xb017000 0x1000>;
@@ -724,6 +772,32 @@
qcom,wakeup-enable;
};
+ qcom,memshare {
+ compatible = "qcom,memshare";
+
+ qcom,client_1 {
+ compatible = "qcom,memshare-peripheral";
+ qcom,peripheral-size = <0x200000>;
+ qcom,client-id = <0>;
+ qcom,allocate-boot-time;
+ label = "modem";
+ };
+
+ qcom,client_2 {
+ compatible = "qcom,memshare-peripheral";
+ qcom,peripheral-size = <0x300000>;
+ qcom,client-id = <2>;
+ label = "modem";
+ };
+
+ mem_client_3_size: qcom,client_3 {
+ compatible = "qcom,memshare-peripheral";
+ qcom,peripheral-size = <0x0>;
+ qcom,client-id = <1>;
+ label = "modem";
+ };
+ };
+
spmi_bus: qcom,spmi@200f000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0x200f000 0x1000>,
@@ -782,6 +856,64 @@
};
+ jtag_fuse: jtagfuse@a601c {
+ compatible = "qcom,jtag-fuse-v2";
+ reg = <0xa601c 0x8>;
+ reg-names = "fuse-base";
+ };
+
+ jtag_mm0: jtagmm@61bc000 {
+ compatible = "qcom,jtagv8-mm";
+ reg = <0x61bc000 0x1000>,
+ <0x61b0000 0x1000>;
+ reg-names = "etm-base", "debug-base";
+
+ qcom,coresight-jtagmm-cpu = <&CPU0>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ jtag_mm1: jtagmm@61bd000 {
+ compatible = "qcom,jtagv8-mm";
+ reg = <0x61bd000 0x1000>,
+ <0x61b2000 0x1000>;
+ reg-names = "etm-base", "debug-base";
+
+ qcom,coresight-jtagmm-cpu = <&CPU1>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ jtag_mm2: jtagmm@61be000 {
+ compatible = "qcom,jtagv8-mm";
+ reg = <0x61be000 0x1000>,
+ <0x61b4000 0x1000>;
+ reg-names = "etm-base", "debug-base";
+
+ qcom,coresight-jtagmm-cpu = <&CPU2>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
+ jtag_mm3: jtagmm@61bf000 {
+ compatible = "qcom,jtagv8-mm";
+ reg = <0x61bf000 0x1000>,
+ <0x61b6000 0x1000>;
+ reg-names = "etm-base", "debug-base";
+
+ qcom,coresight-jtagmm-cpu = <&CPU3>;
+
+ clocks = <&clock_gcc clk_qdss_clk>,
+ <&clock_gcc clk_qdss_a_clk>;
+ clock-names = "core_clk", "core_a_clk";
+ };
+
qcom,ipc-spinlock@1905000 {
compatible = "qcom,ipc-spinlock-sfpb";
reg = <0x1905000 0x8000>;
@@ -1141,6 +1273,10 @@
qcom,ce-opp-freq = <100000000>;
};
+ qcom,iris-fm {
+ compatible = "qcom,iris_fm";
+ };
+
qcom,mss@4080000 {
compatible = "qcom,pil-q6v55-mss";
reg = <0x04080000 0x100>,
diff --git a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
index 2e4d38e..ffc266f 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi
@@ -240,16 +240,23 @@
"SpkrRight IN", "SPK2 OUT";
qcom,tasha-mclk-clk-freq = <9600000>;
+ qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
+ qcom,msm-mbhc-hphl-swh = <0>;
+ qcom,msm-mbhc-gnd-swh = <0>;
+ qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>;
+ qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>;
asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>,
<&loopback>, <&compress>, <&hostless>,
- <&afe>, <&lsm>, <&routing>;
+ <&afe>, <&lsm>, <&routing>, <&cpe>,
+ <&pcm_noirq>;
asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1",
"msm-pcm-dsp.2", "msm-voip-dsp",
"msm-pcm-voice", "msm-pcm-loopback",
"msm-compress-dsp", "msm-pcm-hostless",
"msm-pcm-afe", "msm-lsm-client",
- "msm-pcm-routing";
+ "msm-pcm-routing", "msm-cpe-lsm",
+ "msm-pcm-dsp-noirq";
asoc-cpu = <&dai_pri_auxpcm>,
<&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>,
@@ -281,9 +288,6 @@
asoc-codec = <&stub_codec>, <&hdmi_dba>;
asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx";
- qcom,cdc-us-euro-gpios = <&tlmm 63 0>;
- qcom,msm-mbhc-hphl-swh = <0>;
- qcom,msm-mbhc-gnd-swh = <0>;
qcom,wsa-max-devs = <2>;
qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>,
@@ -292,11 +296,19 @@
"SpkrLeft", "SpkrRight";
};
+ cpe: qcom,msm-cpe-lsm {
+ compatible = "qcom,msm-cpe-lsm";
+ };
+
wcd9xxx_intc: wcd9xxx-irq {
status = "disabled";
+ compatible = "qcom,wcd9xxx-irq";
+ interrupt-controller;
+ #interrupt-cells = <1>;
interrupt-parent = <&tlmm>;
- interrupts = <73 0>;
qcom,gpio-connect = <&tlmm 73 0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wcd_intr_default>;
};
clock_audio: audio_ext_clk {
@@ -306,28 +318,61 @@
qcom,node_has_rpm_clock;
#clock-cells = <1>;
qcom,audio-ref-clk-gpio = <&pm8937_gpios 1 0>;
- qcom,lpass-mclk-id = "pri_mclk";
clocks = <&clock_gcc clk_div_clk2>;
pinctrl-0 = <&cdc_mclk2_sleep>;
pinctrl-1 = <&cdc_mclk2_active>;
};
- wcd_rst_gpio: wcd_gpio_ctrl {
+ wcd_rst_gpio: msm_cdc_pinctrl {
status = "disabled";
- qcom,cdc-rst-n-gpio = <&tlmm 68 0>;
+ compatible = "qcom,msm-cdc-pinctrl";
+ pinctrl-names = "aud_active", "aud_sleep";
+ pinctrl-0 = <&cdc_reset_active>;
+ pinctrl-1 = <&cdc_reset_sleep>;
};
};
&slim_msm {
status = "disabled";
+
+ dai_slim: msm_dai_slim {
+ status = "disabled";
+ compatible = "qcom,msm-dai-slim";
+ elemental-addr = [ff ff ff fe 17 02];
+ };
+
wcd9335: tasha_codec {
status = "disabled";
compatible = "qcom,tasha-slim-pgd";
+ elemental-addr = [00 01 A0 01 17 02];
+
+ qcom,cdc-slim-ifd = "tasha-slim-ifd";
+ qcom,cdc-slim-ifd-elemental-addr = [00 00 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 clk_audio_pmi_clk>,
<&clock_audio clk_audio_ap_clk2>;
- qcom,cdc-reset-gpio = <&tlmm 68 0>;
+ qcom,cdc-static-supplies =
+ "cdc-vdd-buck",
+ "cdc-buck-sido",
+ "cdc-vdd-tx-h",
+ "cdc-vdd-rx-h",
+ "cdc-vdd-px";
+ qcom,cdc-on-demand-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-dmic-sample-rate = <2400000>;
+ qcom,cdc-mclk-clk-rate = <9600000>;
cdc-vdd-buck-supply = <&eldo2_pm8937>;
qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
@@ -355,18 +400,6 @@
};
};
-&pm8937_gpios {
- gpio@c000 {
- status = "ok";
- qcom,mode = <1>;
- qcom,pull = <5>;
- qcom,vin-sel = <0>;
- qcom,src-sel = <2>;
- qcom,master-en = <1>;
- qcom,out-strength = <2>;
- };
-};
-
&pm8937_1 {
pmic_analog_codec: analog-codec@f000 {
status = "okay";
diff --git a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
index 57823b8..90685e9 100644
--- a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi
@@ -156,6 +156,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";
+ };
+};
+
&thermal_zones {
quiet-therm-step {
status = "disabled";
diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi
index d22101f..66c7e7c 100644
--- a/arch/arm64/boot/dts/qcom/msm8937.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi
@@ -30,6 +30,11 @@
firmware: firmware {
android {
compatible = "android,firmware";
+ vbmeta {
+ compatible = "android,vbmeta";
+ parts = "vbmeta,boot,system,vendor,dtbo,recovery";
+ };
+
fstab {
compatible = "android,fstab";
vendor {
@@ -37,7 +42,7 @@
dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor";
type = "ext4";
mnt_flags = "ro,barrier=1,discard";
- fsmgr_flags = "wait";
+ fsmgr_flags = "wait,avb";
status = "ok";
};
system {
@@ -45,7 +50,7 @@
dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system";
type = "ext4";
mnt_flags = "ro,barrier=1,discard";
- fsmgr_flags = "wait";
+ fsmgr_flags = "wait,avb";
status = "ok";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts
index 39c76cc..c3d4cc5 100644
--- a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts
+++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts
@@ -25,3 +25,18 @@
qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
};
+&kgsl_smmu {
+ qcom,hibernation-support;
+ qcom,static-ns-cbs = <0>;
+ /delete-property/ qcom,skip-init;
+};
+
+&apps_iommu {
+ qcom,hibernation-support;
+ qcom,static-ns-cbs =
+ <15 16 17 18 19>,
+ <20 21 22 23 24 25 26 27 28 29 30>,
+ <31>;
+
+ /delete-property/ qcom,skip-init;
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi
index cd0afec..67fd75f 100644
--- a/arch/arm64/boot/dts/qcom/msm8953.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi
@@ -17,6 +17,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/regulator/qcom,rpm-smd-regulator.h>
#include <dt-bindings/clock/msm-clocks-8953.h>
+#include <dt-bindings/msm/msm-bus-ids.h>
/ {
model = "Qualcomm Technologies, Inc. MSM8953";
@@ -68,7 +69,7 @@
modem_mem: modem_region@0 {
compatible = "removed-dma-pool";
- no-map-fixup;
+ no-map;
reg = <0x0 0x86c00000 0x0 0x6a00000>;
};
@@ -168,7 +169,18 @@
spi3 = &spi_3;
};
- soc: soc { };
+ soc: soc {
+ /*
+ * The ordering of these devices is important to boot time
+ * for iot projects.
+ */
+ smem: qcom,smem@86300000 {};
+ rpm_bus: qcom,rpm-smd {};
+ clock_gcc: qcom,gcc@1800000 {};
+ ad_hoc_bus: ad-hoc-bus@580000 {};
+ tlmm: pinctrl@1000000 {};
+ sdhc_1: sdhci@7824900 {};
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi
index 80480f1..0b1a50a 100644
--- a/arch/arm64/boot/dts/qcom/pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi
@@ -44,8 +44,6 @@
interrupt-names = "eoc-int-en-set";
qcom,adc-vdd-reference = <1875>;
qcom,adc-full-scale-code = <0x70e4>;
- pinctrl-names = "default";
- pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
chan@0 {
label = "ref_gnd";
@@ -305,21 +303,6 @@
gpio-controller;
#gpio-cells = <2>;
qcom,gpios-disallowed = <1>;
-
- quiet_therm {
- quiet_therm_default: quiet_therm_default {
- pins = "gpio3";
- bias-high-impedance;
- };
- };
-
- smb_therm {
- smb_therm_default: smb_therm_default {
- pins = "gpio4";
- bias-high-impedance;
- };
- };
-
};
pmi632_charger: qcom,qpnp-smb5 {
@@ -331,6 +314,7 @@
qcom,pmic-revid = <&pmi632_revid>;
dpdm-supply = <&qusb_phy>;
qcom,auto-recharge-soc = <98>;
+ qcom,chg-vadc = <&pmi632_vadc>;
qcom,thermal-mitigation
= <3000000 2500000 2000000 1500000
@@ -480,6 +464,7 @@
"ilim1-s1",
"ilim2-s2",
"vreg-ok";
+ qcom,flash-disable-soc = <10>;
};
smb5_vbus: qcom,smb5-vbus {
diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi
index be88a5d..747593f 100644
--- a/arch/arm64/boot/dts/qcom/qcs605.dtsi
+++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi
@@ -19,39 +19,39 @@
};
&pil_modem_mem {
- reg = <0 0x8b000000 0 0x3e00000>;
+ reg = <0 0x8b000000 0 0x3100000>;
};
&pil_video_mem {
- reg = <0 0x8ee00000 0 0x500000>;
+ reg = <0 0x8e100000 0 0x500000>;
};
&wlan_msa_mem {
- reg = <0 0x8f300000 0 0x100000>;
+ reg = <0 0x8e600000 0 0x100000>;
};
&pil_cdsp_mem {
- reg = <0 0x8f400000 0 0x800000>;
+ reg = <0 0x8e700000 0 0x800000>;
};
&pil_mba_mem {
- reg = <0 0x8fc00000 0 0x200000>;
+ reg = <0 0x8ef00000 0 0x200000>;
};
&pil_adsp_mem {
- reg = <0 0x8fe00000 0 0x1e00000>;
+ reg = <0 0x8f100000 0 0x1e00000>;
};
&pil_ipa_fw_mem {
- reg = <0 0x91c00000 0 0x10000>;
+ reg = <0 0x90f00000 0 0x10000>;
};
&pil_ipa_gsi_mem {
- reg = <0 0x91c10000 0 0x5000>;
+ reg = <0 0x90f10000 0 0x5000>;
};
&pil_gpu_mem {
- reg = <0 0x91c15000 0 0x2000>;
+ reg = <0 0x90f15000 0 0x2000>;
};
&adsp_mem {
diff --git a/arch/arm64/boot/dts/qcom/sda429.dts b/arch/arm64/boot/dts/qcom/sda429.dts
new file mode 100644
index 0000000..6a26f23
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda429.dts
@@ -0,0 +1,23 @@
+/*
+ * 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 "sda429.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA429 CDP";
+ compatible = "qcom,sda429-cdp", "qcom,sda429", "qcom,cdp";
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+ qcom.pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda439.dts b/arch/arm64/boot/dts/qcom/sda439.dts
new file mode 100644
index 0000000..a124c75
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sda439.dts
@@ -0,0 +1,23 @@
+/*
+ * 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 "sda439.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDA439";
+ compatible = "qcom,sda439";
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+ qcom.pmic-name = "PMI632";
+};
diff --git a/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts
index c907977..f20c2ba 100644
--- a/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sda450-pmi632-mtp-s3.dts
@@ -14,8 +14,8 @@
/dts-v1/;
#include "sda450.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDA450 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
index 0b678a8..c4b4a50 100644
--- a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi
@@ -32,7 +32,6 @@
/* MDM PON conrol*/
pins = "gpio10";
function = "normal";
- output-low;
power-source = <0>;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
index ce62781..ed2ad69 100644
--- a/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sda845-svr.dtsi
@@ -14,9 +14,12 @@
#include "sdm845-pinctrl-overlay.dtsi"
#include "sda845-svr-pinctrl-overlay.dtsi"
#include "sdm845-camera-sensor-svr.dtsi"
-#include "smb1355.dtsi"
#include <dt-bindings/clock/mdss-10nm-pll-clk.h>
+&qupv3_se10_i2c {
+#include "smb1355.dtsi"
+};
+
&vendor {
bluetooth: bt_wcn3990 {
compatible = "qca,wcn3990";
diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts
index 93a9ae9..c55c2a5 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts
@@ -22,5 +22,4 @@
/ {
model = "CDP";
qcom,board-id = <1 3>;
- qcom,msm-id = <354 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts
index 3a339da..7735b35 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts
@@ -22,5 +22,4 @@
/ {
model = "MTP";
qcom,board-id = <8 2>;
- qcom,msm-id = <354 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts
index 8abccb7..fae68c9 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts
@@ -22,5 +22,4 @@
/ {
model = "QRD";
qcom,board-id = <0xb 3>;
- qcom,msm-id = <354 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
index 7116662..dde9c56 100644
--- a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi
@@ -12,3 +12,7 @@
*/
#include "sdm439-qrd.dtsi"
+
+&mdss_dsi0 {
+ qcom,dsi-pref-prim-pan = <&dsi_hx8399c_hd_vid>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi
index 24e9905..19df054 100644
--- a/arch/arm64/boot/dts/qcom/sdm429.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi
@@ -207,3 +207,9 @@
"byte1_src";
#clock-cells = <1>;
};
+
+/* GPU overrides */
+&msm_gpu {
+ /* Update GPU chip ID*/
+ qcom,chipid = <0x05000400>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
index f6751d2..a6b2371 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi
@@ -15,6 +15,7 @@
int_codec: sound {
qcom,model = "sdm439-snd-card-mtp";
qcom,msm-hs-micbias-type = "internal";
+ qcom,msm-micbias2-ext-cap;
asoc-codec = <&stub_codec>, <&msm_digital_codec>,
<&pmic_analog_codec>;
@@ -24,6 +25,65 @@
qcom,msm-vdd-wsa-switch-voltage = <1800000>;
qcom,msm-vdd-wsa-switch-current = <10000>;
};
+
+ clock_audio_native: audio_ext_clk_native {
+ status = "disabled";
+ compatible = "qcom,audio-ref-clk";
+ #clock-cells = <1>;
+ qcom,codec-mclk-clk-freq = <11289600>;
+ qcom,audio-ref-clk-gpio = <&tlmm 66 0>;
+ qcom,lpass-mclk-id = "pri_mclk";
+ pinctrl-names = "sleep", "active";
+ pinctrl-0 = <&cdc_mclk2_sleep>;
+ pinctrl-1 = <&cdc_mclk2_active>;
+ };
+};
+
+
+&clock_audio {
+ pinctrl-names = "active", "sleep";
+ pinctrl-0 = <&tasha_mclk_default>;
+ pinctrl-1 = <&tasha_mclk_default>;
+ qcom,audio-ref-clk-gpio = <&pm8953_gpios 1 0>;
+};
+
+&wcd9335 {
+ cdc-vdd-buck-supply = <&dbu1>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&dbu1>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <150000>;
+
+ cdc-vdd-tx-h-supply = <&dbu1>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&dbu1>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vdd-px-supply = <&dbu1>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+
+ cdc-vdd-mic-bias-supply = <&pm8953_l13>;
+ qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>;
+ qcom,cdc-vdd-mic-bias-current = <15000>;
+};
+
+&pm8953_gpios {
+ tasha_mclk {
+ tasha_mclk_default: tasha_mclk_default{
+ pins = "gpio1";
+ function = "func1";
+ qcom,drive-strength = <2>;
+ power-source = <0>;
+ bias-disable;
+ output-low;
+ };
+ };
};
&pm8953_1 {
@@ -76,7 +136,7 @@
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-voltage = <3075000 3075000>;
qcom,cdc-vdd-mic-bias-current = <5000>;
qcom,cdc-mclk-clk-rate = <9600000>;
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts
index 6d6f99b..5e86672 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts
@@ -22,5 +22,4 @@
/ {
model = "CDP";
qcom,board-id = <1 2>;
- qcom,msm-id = <353 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
index 08745cd..6ecd0dd 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi
@@ -150,6 +150,30 @@
};
};
+&cdc_pdm_lines_2_act {
+ mux {
+ pins = "gpio70", "gpio71", "gpio72";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio70", "gpio71", "gpio72";
+ drive-strength = <16>;
+ };
+};
+
+&cdc_pdm_lines_act {
+ mux {
+ pins = "gpio69", "gpio73", "gpio74";
+ function = "cdc_pdm0";
+ };
+
+ config {
+ pins = "gpio69", "gpio73", "gpio74";
+ drive-strength = <16>;
+ };
+};
+
&pm8953_pwm {
status = "ok";
};
@@ -215,6 +239,19 @@
qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
qcom,mdss-dsi-bl-pmic-bank-select = <0>;
qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-status-read-length = <4>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+ qcom,mdss-dsi-min-refresh-rate = <48>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
};
&dsi_nt35695b_truly_fhd_cmd {
diff --git a/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi
new file mode 100644
index 0000000..a74fb75
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+&int_codec {
+ status = "disabled";
+};
+
+&wsa881x_i2c_f {
+ status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+ status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+ status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+ status = "disabled";
+};
+
+&slim_msm {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&clock_audio {
+ status = "okay";
+};
+
+&wcd9335 {
+ status = "okay";
+};
+
+&cdc_us_euro_sw {
+ status = "okay";
+};
+
+&cdc_quin_mi2s_gpios {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&ext_codec {
+ status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts
new file mode 100644
index 0000000..468f514
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.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/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/msm-clocks-8953.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "sdm439-mtp.dtsi"
+#include "sdm439-external-codec.dtsi"
+
+/ {
+ model = "MTP";
+ qcom,board-id = <8 3>;
+ qcom,msm-id = <353 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts
new file mode 100644
index 0000000..e2a86bb
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts
@@ -0,0 +1,25 @@
+/* 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 "sdm439.dtsi"
+#include "sdm439-mtp.dtsi"
+#include "sdm439-external-codec.dtsi"
+
+/ {
+ model = "Qualcomm Technologies, Inc. SDM439 Audio Codec MTP";
+ compatible = "qcom,sdm439-mtp", "qcom,sdm439", "qcom,mtp";
+ qcom,board-id = <8 3>;
+ qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi
new file mode 100644
index 0000000..83864ef
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi
@@ -0,0 +1,12 @@
+/* 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 "sdm439-ext-audio-mtp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts
index df8a0d7..8b6c6fb 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts
@@ -22,5 +22,4 @@
/ {
model = "MTP";
qcom,board-id = <8 1>;
- qcom,msm-id = <353 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
index 29e0d72..9a9603d 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi
@@ -214,4 +214,74 @@
qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
qcom,mdss-dsi-bl-pmic-bank-select = <0>;
qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-status-read-length = <4>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+ qcom,mdss-dsi-min-refresh-rate = <48>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
+};
+
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+ smb_en {
+ smb_en_default: smb_en_default {
+ pins = "gpio2";
+ function = "func1";
+ output-enable;
+ };
+ };
+};
+
+&tlmm {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio59";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio59";
+ drive-strength = <2>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+};
+
+&smb1355_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_0: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
+
+&smb1355_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_1: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
index bc2ba9f..68bf1d2 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi
@@ -43,6 +43,27 @@
qcom,battery-data = <&mtp_batterydata>;
};
+&pmi632_vadc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
+};
+
+&pmi632_gpios {
+ quiet_therm {
+ quiet_therm_default: quiet_therm_default {
+ pins = "gpio3";
+ bias-high-impedance;
+ };
+ };
+
+ smb_therm {
+ smb_therm_default: smb_therm_default {
+ pins = "gpio4";
+ bias-high-impedance;
+ };
+ };
+};
+
&pm8953_typec {
status = "disabled";
};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts
index ac059c4d..ed6b2ad 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts
@@ -22,5 +22,4 @@
/ {
model = "QRD";
qcom,board-id = <0xb 2>;
- qcom,msm-id = <353 0x0>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
index 18714ce..5662e17 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi
@@ -51,6 +51,11 @@
qcom,msm-mbhc-hphl-swh = <1>;
qcom,msm-mbhc-gnd-swh = <0>;
qcom,msm-hs-micbias-type = "external";
+ /delete-property/ qcom,quin-mi2s-gpios;
+};
+
+&cdc_quin_mi2s_gpios {
+ status = "disabled";
};
&wsa881x_i2c_f {
@@ -297,3 +302,83 @@
qcom,mdss-dsi-pan-fps-update =
"dfps_immediate_porch_mode_vfp";
};
+
+&dsi_hx8399c_hd_vid {
+ /delete-property/ qcom,mdss-dsi-panel-timings;
+ qcom,mdss-dsi-panel-timings-phy-12nm = [08 06 0a 02 00 04 02 08];
+ qcom,panel-supply-entries = <&dsi_panel_pwr_supply>;
+ qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm";
+ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>;
+ qcom,mdss-dsi-bl-pmic-bank-select = <0>;
+ qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
+ qcom,esd-check-enabled;
+ qcom,mdss-dsi-panel-status-check-mode = "reg_read";
+ qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a];
+ qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
+ qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>;
+ qcom,mdss-dsi-panel-status-read-length = <4>;
+ qcom,mdss-dsi-panel-max-error-count = <3>;
+ qcom,mdss-dsi-min-refresh-rate = <48>;
+ qcom,mdss-dsi-max-refresh-rate = <60>;
+ qcom,mdss-dsi-pan-enable-dynamic-fps;
+ qcom,mdss-dsi-pan-fps-update =
+ "dfps_immediate_porch_mode_vfp";
+};
+
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+ smb_en {
+ smb_en_default: smb_en_default {
+ pins = "gpio2";
+ function = "func1";
+ output-enable;
+ };
+ };
+};
+
+&tlmm {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio59";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio59";
+ drive-strength = <2>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+};
+
+&smb1355_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_0: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
+
+&smb1355_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_1: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
index f325925..e2f2dea 100644
--- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi
@@ -468,5 +468,26 @@
qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>;
qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>;
qcom,cpr-scaled-init-voltage-as-ceiling;
+
+ qcom,cpr-fuse-version-map =
+ /* <Speed-bin pvs-version cpr-rev ... ... ...> */
+ <(-1) (-1) ( 0) (-1) (-1) (-1)>,
+ <(-1) (-1) (-1) (-1) (-1) (-1)>;
+
+ qcom,cpr-quotient-adjustment =
+ <66 77 66>, /* SVSP_30mV, NOM_35mV, TUR_30mV */
+ <0 0 0>;
+
+ qcom,cpr-voltage-ceiling-override =
+ <(-1) (-1) 795000 795000 835000 910000 910000>;
+
+ qcom,cpr-enable;
+ };
+
+ dbu1: dbu1 {
+ compatible = "regulator-fixed";
+ regulator-name = "dbu1";
+ startup-delay-us = <0>;
+ enable-active-high;
};
};
diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi
index 2df468f..0b01035 100644
--- a/arch/arm64/boot/dts/qcom/sdm439.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi
@@ -14,6 +14,7 @@
#include "msm8937.dtsi"
#include "sdm439-pm8953.dtsi"
#include "sdm439-pmi632.dtsi"
+#include "sdm439-audio.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM439";
@@ -340,10 +341,10 @@
reg = <0x001a94400 0x400>,
<0x0184d074 0x8>;
reg-names = "pll_base", "gdsc_base";
- /delete-property/ qcom,dsi-pll-ssc-en;
- /delete-property/ qcom,dsi-pll-ssc-mode;
- /delete-property/ qcom,ssc-frequency-hz;
- /delete-property/ qcom,ssc-ppm;
+ qcom,dsi-pll-ssc-en;
+ qcom,dsi-pll-ssc-mode = "down-spread";
+ qcom,ssc-frequency-hz = <31500>;
+ qcom,ssc-ppm = <5000>;
};
&mdss_dsi1_pll {
@@ -351,10 +352,10 @@
reg = <0x001a96400 0x400>,
<0x0184d074 0x8>;
reg-names = "pll_base", "gdsc_base";
- /delete-property/ qcom,dsi-pll-ssc-en;
- /delete-property/ qcom,dsi-pll-ssc-mode;
- /delete-property/ qcom,ssc-frequency-hz;
- /delete-property/ qcom,ssc-ppm;
+ qcom,dsi-pll-ssc-en;
+ qcom,dsi-pll-ssc-mode = "down-spread";
+ qcom,ssc-frequency-hz = <31500>;
+ qcom,ssc-ppm = <5000>;
};
&mdss_dsi {
diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
index e12ad51..97c9389 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts
@@ -18,7 +18,6 @@
/ {
model = "CDP S2";
- compatible = "qcom,cdp";
qcom,board-id = <1 2>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
index ae522a5..3dd7200 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts
@@ -18,7 +18,6 @@
/ {
model = "MTP S3";
- compatible = "qcom,mtp";
qcom,board-id = <8 3>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
index b9aadc1..b73b49a 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dts
@@ -14,8 +14,8 @@
/dts-v1/;
#include "sdm450.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM450 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
index 64d9e64..265a86d 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632-mtp-s3.dtsi
@@ -46,3 +46,60 @@
qcom,mdss-dsi-bl-pmic-bank-select = <0>;
qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>;
};
+
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+ smb_en {
+ smb_en_default: smb_en_default {
+ pins = "gpio2";
+ function = "func1";
+ output-enable;
+ };
+ };
+};
+
+&tlmm {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio59";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio59";
+ drive-strength = <2>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+};
+
+&smb1355_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_0: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
+
+&smb1355_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_1: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
index 5c127bc..6e39327 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi
@@ -41,6 +41,27 @@
};
};
+&pmi632_vadc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&quiet_therm_default &smb_therm_default>;
+};
+
+&pmi632_gpios {
+ quiet_therm {
+ quiet_therm_default: quiet_therm_default {
+ pins = "gpio3";
+ bias-high-impedance;
+ };
+ };
+
+ smb_therm {
+ smb_therm_default: smb_therm_default {
+ pins = "gpio4";
+ bias-high-impedance;
+ };
+ };
+};
+
&pmi632_qg {
qcom,battery-data = <&mtp_batterydata>;
};
@@ -351,3 +372,24 @@
};
};
};
+
+&tlmm {
+ pmx_mdss {
+ mdss_dsi_active: mdss_dsi_active {
+ mux {
+ pins = "gpio61";
+ };
+ config {
+ pins = "gpio61";
+ };
+ };
+ mdss_dsi_suspend: mdss_dsi_suspend {
+ mux {
+ pins = "gpio61";
+ };
+ config {
+ pins = "gpio61";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
index 558c3c6..e8dca18 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts
@@ -18,7 +18,6 @@
/ {
model = "QRD SKU4";
- compatible = "qcom,qrd";
qcom,board-id = <0xb 1>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
index 386bd71..c5eff7b4 100644
--- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4.dtsi
@@ -177,3 +177,59 @@
};
};
+&i2c_2 {
+#include "smb1355.dtsi"
+};
+
+&pmi632_gpios {
+ smb_en {
+ smb_en_default: smb_en_default {
+ pins = "gpio2";
+ function = "func1";
+ output-enable;
+ };
+ };
+};
+
+&tlmm {
+ smb_int_default: smb_int_default {
+ mux {
+ pins = "gpio59";
+ function = "gpio";
+ };
+ config {
+ pins = "gpio59";
+ drive-strength = <2>;
+ bias-pull-up;
+ input-enable;
+ };
+ };
+};
+
+&smb1355_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_0: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
+
+&smb1355_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smb_int_default
+ &smb_en_default>;
+ interrupt-parent = <&tlmm>;
+ interrupts = <59 IRQ_TYPE_LEVEL_LOW>;
+ smb1355_charger_1: qcom,smb1355-charger@1000 {
+ status ="ok";
+ /delete-property/ io-channels;
+ /delete-property/ io-channels-names;
+ qcom,parallel-mode = <1>;
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
index 2669d1f..9d6543f 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-cdp-s2.dts
@@ -24,33 +24,3 @@
qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
};
-
-&soc {
- gpio_keys {
- /delete-node/home;
- };
-};
-
-&tlmm {
- tlmm_gpio_key {
- gpio_key_active: gpio_key_active {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
-
- gpio_key_suspend: gpio_key_suspend {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
index de1bd1f..c37750a 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi
@@ -258,7 +258,7 @@
busy-cost-data = <
633600 722
902400 1287
- 1036800 1739
+ 1094400 1739
1401600 2819
1555200 3532
1804800 5038
@@ -287,7 +287,7 @@
busy-cost-data = <
633600 68
902400 103
- 1036800 132
+ 1094400 132
1401600 193
1555200 233
1804800 292
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi
new file mode 100644
index 0000000..b34e3d8
--- /dev/null
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+&int_codec {
+ status = "disabled";
+};
+
+&pmic_analog_codec {
+ status = "disabled";
+};
+
+&wsa881x_i2c_f {
+ status = "disabled";
+};
+
+&wsa881x_i2c_45 {
+ status = "disabled";
+};
+
+&cdc_pri_mi2s_gpios {
+ status = "disabled";
+};
+
+&wsa881x_analog_vi_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_clk_gpio {
+ status = "disabled";
+};
+
+&wsa881x_analog_reset_gpio {
+ status = "disabled";
+};
+
+&cdc_comp_gpios {
+ status = "disabled";
+};
+
+&slim_msm {
+ status = "okay";
+};
+
+&dai_slim {
+ status = "okay";
+};
+
+&wcd9xxx_intc {
+ status = "okay";
+};
+
+&clock_audio {
+ status = "okay";
+};
+
+&wcd9335 {
+ status = "okay";
+
+ dc-vdd-buck-supply = <&dbu3>;
+ qcom,cdc-vdd-buck-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-buck-current = <650000>;
+
+ cdc-buck-sido-supply = <&dbu3>;
+ qcom,cdc-buck-sido-voltage = <1800000 1800000>;
+ qcom,cdc-buck-sido-current = <150000>;
+
+ cdc-vdd-tx-h-supply = <&dbu3>;
+ qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-tx-h-current = <25000>;
+
+ cdc-vdd-rx-h-supply = <&dbu3>;
+ qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-rx-h-current = <25000>;
+
+ cdc-vdd-px-supply = <&dbu3>;
+ qcom,cdc-vdd-px-voltage = <1800000 1800000>;
+ qcom,cdc-vdd-px-current = <10000>;
+};
+
+&cdc_us_euro_sw {
+ status = "okay";
+};
+
+&cdc_quin_mi2s_gpios {
+ status = "okay";
+};
+
+&wcd_rst_gpio {
+ status = "okay";
+};
+
+&ext_codec {
+ qcom,model = "msm8953-tasha-snd-card";
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts
index eb5afbd..c3e0ba9 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts
@@ -18,7 +18,6 @@
/ {
model = "Ext Codec CDP S3";
- compatible = "qcom,cdp";
qcom,board-id = <1 3>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3.dts
index 17ae9d1..60b149d 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3.dts
@@ -24,34 +24,3 @@
qcom,pmic-id = <0x010016 0x25 0x0 0x0>;
};
-
-&soc {
- gpio_keys {
- /delete-node/home;
- };
-};
-
-&tlmm {
- tlmm_gpio_key {
- gpio_key_active: gpio_key_active {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
-
- gpio_key_suspend: gpio_key_suspend {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
- };
-};
-
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts
index 5656fd0..63b51ab 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts
@@ -18,7 +18,6 @@
/ {
model = "Ext Codec MTP S4";
- compatible = "qcom,mtp";
qcom,board-id = <8 4>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi
index d8326ff..fd1eb3d 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi
@@ -12,4 +12,5 @@
*/
#include "sdm450-pmi632-mtp-s3.dtsi"
+#include "sdm632-ext-audio-mtp.dtsi"
diff --git a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
index 3662cf3..1dd1163 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-mtp-s3.dts
@@ -14,8 +14,8 @@
/dts-v1/;
#include "sdm632.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
/ {
model = "Qualcomm Technologies, Inc. SDM632 + PMI632 MTP S3";
diff --git a/arch/arm64/boot/dts/qcom/sdm632-pm8004-cdp-s2.dts b/arch/arm64/boot/dts/qcom/sdm632-pm8004-cdp-s2.dts
index 4d68901..e0e6b4b 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-pm8004-cdp-s2.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-pm8004-cdp-s2.dts
@@ -25,34 +25,3 @@
qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
};
-
-&soc {
- gpio_keys {
- /delete-node/home;
- };
-};
-
-&tlmm {
- tlmm_gpio_key {
- gpio_key_active: gpio_key_active {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
-
- gpio_key_suspend: gpio_key_suspend {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
- };
-};
-
diff --git a/arch/arm64/boot/dts/qcom/sdm632-pm8004-ext-codec-cdp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-pm8004-ext-codec-cdp-s3.dts
index 6ca2940..413e85f 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-pm8004-ext-codec-cdp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-pm8004-ext-codec-cdp-s3.dts
@@ -25,34 +25,3 @@
qcom,pmic-id = <0x010016 0x25 0xC 0x0>;
};
-
-&soc {
- gpio_keys {
- /delete-node/home;
- };
-};
-
-&tlmm {
- tlmm_gpio_key {
- gpio_key_active: gpio_key_active {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
-
- gpio_key_suspend: gpio_key_suspend {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
- };
-};
-
diff --git a/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts b/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts
index d2a9cf1..aea6bff 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-pm8004-mtp-s3.dts
@@ -14,8 +14,8 @@
/dts-v1/;
#include "sdm632.dtsi"
-#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm450-pmi632.dtsi"
+#include "sdm450-pmi632-mtp-s3.dtsi"
#include "sdm632-pm8004.dtsi"
/ {
diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts
index e6217e5..4b7f6b2 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts
@@ -18,7 +18,6 @@
/ {
model = "QRD";
- compatible = "qcom,qrd";
qcom,board-id = <0xb 3>;
};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rcm.dts b/arch/arm64/boot/dts/qcom/sdm632-rcm.dts
index fe7ab38..68f0ea0 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-rcm.dts
+++ b/arch/arm64/boot/dts/qcom/sdm632-rcm.dts
@@ -24,32 +24,3 @@
qcom,pmic-id = <0x010016 0x010011 0x0 0x0>;
};
-&soc {
- gpio_keys {
- /delete-node/home;
- };
-};
-
-&tlmm {
- tlmm_gpio_key {
- gpio_key_active: gpio_key_active {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
-
- gpio_key_suspend: gpio_key_suspend {
- mux {
- pins = "gpio85", "gpio86", "gpio87";
- };
-
- config {
- pins = "gpio85", "gpio86", "gpio87";
- };
- };
- };
-};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-rcm.dtsi b/arch/arm64/boot/dts/qcom/sdm632-rcm.dtsi
index 14ba3b4..aa20680 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-rcm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-rcm.dtsi
@@ -13,3 +13,34 @@
#include "sdm450-pmi632-cdp-s2.dtsi"
+&soc {
+ gpio_keys {
+ home {
+ status = "disabled";
+ };
+ };
+};
+
+&tlmm {
+ tlmm_gpio_key {
+ gpio_key_active {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+ };
+
+ gpio_key_suspend {
+ mux {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+
+ config {
+ pins = "gpio85", "gpio86", "gpio87";
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
index a7580e0..33ac930 100644
--- a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi
@@ -114,6 +114,8 @@
qcom,cpr-count-repeat = <14>;
qcom,cpr-down-error-step-limit = <1>;
qcom,cpr-up-error-step-limit = <1>;
+ qcom,cpr-reset-step-quot-loop-en;
+ qcom,cpr-thread-has-always-vote-en;
qcom,apm-ctrl = <&apc_apm>;
qcom,apm-threshold-voltage = <875000>;
@@ -131,10 +133,13 @@
"APCS_ALIAS0_APM_CTLER_STATUS",
"APCS0_CPR_CORE_ADJ_MODE_REG";
+ qcom,cpr-enable;
+ qcom,cpr-hw-closed-loop;
+
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <0>;
- qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-consecutive-down = <0>;
qcom,cpr-up-threshold = <2>;
qcom,cpr-down-threshold = <1>;
@@ -156,6 +161,10 @@
<500000 500000 500000 500000 500000
500000 500000>;
+ qcom,cpr-floor-to-ceiling-max-range =
+ <50000 50000 50000 50000 50000
+ 50000 50000>;
+
qcom,mem-acc-voltage = <1 1 2 2 2 2 3>;
qcom,corner-frequencies =
@@ -176,13 +185,19 @@
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-scaled-open-loop-voltage-as-ceiling;
+
+ qcom,cpr-open-loop-voltage-fuse-adjustment =
+ < 0 0 0 10000>;
+
+ qcom,cpr-closed-loop-voltage-fuse-adjustment =
+ <(-10000) 0 0 10000>;
};
};
thread@1 {
qcom,cpr-thread-id = <1>;
qcom,cpr-consecutive-up = <0>;
- qcom,cpr-consecutive-down = <2>;
+ qcom,cpr-consecutive-down = <0>;
qcom,cpr-up-threshold = <2>;
qcom,cpr-down-threshold = <1>;
@@ -204,6 +219,10 @@
<500000 500000 500000 500000 500000
500000 500000>;
+ qcom,cpr-floor-to-ceiling-max-range =
+ <50000 50000 50000 50000 50000
+ 50000 50000>;
+
qcom,mem-acc-voltage = <1 1 2 2 2 2 3>;
qcom,corner-frequencies =
@@ -227,9 +246,9 @@
qcom,cpr-open-loop-voltage-fuse-adjustment =
/* Speed bin 0; CPR rev 0..7 */
- < 30000 0 0 0>,
- < 30000 0 0 0>,
- < 0 0 0 0>,
+ < 30000 0 10000 20000>,
+ < 30000 0 10000 20000>,
+ < 0 0 10000 20000>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
@@ -247,9 +266,9 @@
< 0 0 0 0>,
/* Speed bin 2; CPR rev 0..7 */
- < 30000 0 0 0>,
- < 30000 0 0 0>,
- < 0 0 0 0>,
+ < 30000 0 10000 20000>,
+ < 30000 0 10000 20000>,
+ < 0 0 10000 20000>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
@@ -287,9 +306,9 @@
< 0 0 0 0>,
/* Speed bin 6; CPR rev 0..7 */
- < 30000 0 0 0>,
- < 30000 0 0 0>,
- < 0 0 0 0>,
+ < 30000 0 10000 20000>,
+ < 30000 0 10000 20000>,
+ < 0 0 10000 20000>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
@@ -310,7 +329,7 @@
/* Speed bin 0; CPR rev 0..7 */
< 30000 0 0 0>,
< 30000 0 0 0>,
- < 0 0 0 0>,
+ <(-10000) 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
@@ -330,7 +349,7 @@
/* Speed bin 2; CPR rev 0..7 */
< 30000 0 0 0>,
< 30000 0 0 0>,
- < 0 0 0 0>,
+ <(-10000) 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
@@ -370,7 +389,7 @@
/* Speed bin 6; CPR rev 0..7 */
< 30000 0 0 0>,
< 30000 0 0 0>,
- < 0 0 0 0>,
+ <(-10000) 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
@@ -432,4 +451,11 @@
mem-acc-supply = <&gfx_mem_acc>;
qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>;
};
+
+ dbu3: dbu3 {
+ compatible = "regulator-fixed";
+ regulator-name = "dbu3";
+ startup-delay-us = <0>;
+ enable-active-high;
+ };
};
diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi
index b54e831..67efe0f 100644
--- a/arch/arm64/boot/dts/qcom/sdm632.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi
@@ -40,6 +40,17 @@
&clock_gcc_gfx {
compatible = "qcom,gcc-gfx-sdm632";
+ qcom,gfxfreq-corner =
+ < 0 0 >,
+ < 133330000 1 >, /* Min SVS */
+ < 216000000 2 >, /* Low SVS */
+ < 320000000 3 >, /* SVS */
+ < 400000000 4 >, /* SVS Plus */
+ < 510000000 5 >, /* NOM */
+ < 560000000 6 >, /* Nom Plus */
+ < 650000000 7 >, /* Turbo */
+ < 700000000 7 >, /* Turbo */
+ < 725000000 7 >; /* Turbo */
};
&thermal_zones {
diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
index bd88087..da4d27d 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi
@@ -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
@@ -143,7 +143,7 @@
cam_snapshot {
label = "cam_snapshot";
- gpios = <&tlmm 91 0>;
+ gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
linux,code = <766>;
gpio-key,wakeup;
@@ -153,7 +153,7 @@
cam_focus {
label = "cam_focus";
- gpios = <&tlmm 92 0>;
+ gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
linux,input-type = <1>;
linux,code = <528>;
gpio-key,wakeup;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
index cc55127..dbc3651 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi
@@ -14,7 +14,10 @@
#include "sdm670-pmic-overlay.dtsi"
#include "sdm670-sde-display.dtsi"
#include "sdm670-camera-sensor-mtp.dtsi"
+
+&qupv3_se10_i2c {
#include "smb1355.dtsi"
+};
&ufsphy_mem {
compatible = "qcom,ufs-phy-qmp-v3";
@@ -202,7 +205,7 @@
cam_snapshot {
label = "cam_snapshot";
- gpios = <&tlmm 91 0>;
+ gpios = <&tlmm 91 GPIO_ACTIVE_LOW>;
linux,input-type = <1>;
linux,code = <766>;
gpio-key,wakeup;
@@ -212,7 +215,7 @@
cam_focus {
label = "cam_focus";
- gpios = <&tlmm 92 0>;
+ gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>;
linux,input-type = <1>;
linux,code = <528>;
gpio-key,wakeup;
diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
index bdcd039..8ed821a 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi
@@ -134,7 +134,9 @@
#size-cells = <0>;
qcom,psci-mode-shift = <0>;
qcom,psci-mode-mask = <0xf>;
- qcom,disable-prediction;
+ qcom,ref-stddev = <100>;
+ qcom,tmr-add = <100>;
+ qcom,ref-premature-cnt = <3>;
qcom,cpu = <&CPU6 &CPU7>;
qcom,pm-cpu-level@0 { /* C1 */
diff --git a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
index 43f1465..3b8b375 100644
--- a/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm670-qrd.dtsi
@@ -14,9 +14,12 @@
#include "sdm670-camera-sensor-qrd.dtsi"
#include "sdm670-pmic-overlay.dtsi"
#include "sdm670-audio-overlay.dtsi"
-#include "smb1355.dtsi"
#include "sdm670-sde-display.dtsi"
+&qupv3_se10_i2c {
+#include "smb1355.dtsi"
+};
+
&qupv3_se9_2uart {
status = "disabled";
};
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 9903d19..0c37bf1 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -36,6 +36,7 @@
qcom,dwc-usb3-msm-tx-fifo-size = <21288>;
qcom,num-gsi-evt-buffs = <0x3>;
qcom,use-pdc-interrupts;
+ qcom,pm-qos-latency = <44>;
extcon = <0>, <0>, <&eud>, <0>, <0>;
clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>,
diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
index 349c4c0..812a313 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi
@@ -14,7 +14,10 @@
#include "sdm845-pmic-overlay.dtsi"
#include "sdm845-pinctrl-overlay.dtsi"
#include "sdm845-camera-sensor-mtp.dtsi"
+
+&qupv3_se10_i2c {
#include "smb1355.dtsi"
+};
&vendor {
bluetooth: bt_wcn3990 {
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
index 6034b6d..f5a979c 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qrd.dtsi
@@ -13,9 +13,12 @@
#include "sdm845-pmic-overlay.dtsi"
#include "sdm845-pinctrl-overlay.dtsi"
#include "sdm845-camera-sensor-qrd.dtsi"
-#include "smb1355.dtsi"
#include <dt-bindings/gpio/gpio.h>
+&qupv3_se10_i2c {
+#include "smb1355.dtsi"
+};
+
&vendor {
bluetooth: bt_wcn3990 {
compatible = "qca,wcn3990";
diff --git a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
index a5c6ab5..b2b0000 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-qvr.dtsi
@@ -18,7 +18,10 @@
#include "sdm845-pmic-overlay.dtsi"
#include "sdm845-pinctrl-overlay.dtsi"
+
+&qupv3_se10_i2c {
#include "smb1355.dtsi"
+};
&vendor {
bluetooth: bt_wcn3990 {
diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi
index 3412b25d..5939440 100644
--- a/arch/arm64/boot/dts/qcom/smb1355.dtsi
+++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -12,98 +12,96 @@
#include <dt-bindings/interrupt-controller/irq.h>
-&qupv3_se10_i2c {
- smb1355_0: qcom,smb1355@8 {
- compatible = "qcom,i2c-pmic";
- reg = <0x8>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupt-parent = <&spmi_bus>;
- interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
- interrupt_names = "smb1355_0";
- interrupt-controller;
- #interrupt-cells = <3>;
- qcom,periph-map = <0x10 0x12 0x13 0x16>;
+smb1355_0: qcom,smb1355@8 {
+ compatible = "qcom,i2c-pmic";
+ reg = <0x8>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt_names = "smb1355_0";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ qcom,periph-map = <0x10 0x12 0x13 0x16>;
- smb1355_revid_0: qcom,revid@100 {
- compatible = "qcom,qpnp-revid";
- reg = <0x100 0x100>;
- };
-
- smb1355_charger_0: qcom,smb1355-charger@1000 {
- compatible = "qcom,smb1355";
- qcom,pmic-revid = <&smb1355_revid_0>;
- reg = <0x1000 0x700>;
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&smb1355_0>;
- status = "disabled";
-
- io-channels = <&pmi8998_rradc 2>,
- <&pmi8998_rradc 12>;
- io-channel-names = "charger_temp",
- "charger_temp_max";
-
- qcom,chgr@1000 {
- reg = <0x1000 0x100>;
- interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "chg-state-change";
- };
-
- qcom,chgr-misc@1600 {
- reg = <0x1600 0x100>;
- interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
- <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "wdog-bark",
- "temperature-change";
- };
- };
+ smb1355_revid_0: qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
};
- smb1355_1: qcom,smb1355@c {
- compatible = "qcom,i2c-pmic";
- reg = <0xc>;
+ smb1355_charger_0: qcom,smb1355-charger@1000 {
+ compatible = "qcom,smb1355";
+ qcom,pmic-revid = <&smb1355_revid_0>;
+ reg = <0x1000 0x700>;
#address-cells = <1>;
- #size-cells = <0>;
- interrupt-parent = <&spmi_bus>;
- interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
- interrupt_names = "smb1355_1";
- interrupt-controller;
- #interrupt-cells = <3>;
- qcom,periph-map = <0x10 0x12 0x13 0x16>;
+ #size-cells = <1>;
+ interrupt-parent = <&smb1355_0>;
+ status = "disabled";
- smb1355_revid_1: qcom,revid@100 {
- compatible = "qcom,qpnp-revid";
- reg = <0x100 0x100>;
+ io-channels = <&pmi8998_rradc 2>,
+ <&pmi8998_rradc 12>;
+ io-channel-names = "charger_temp",
+ "charger_temp_max";
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "chg-state-change";
};
- smb1355_charger_1: qcom,smb1355-charger@1000 {
- compatible = "qcom,smb1355";
- qcom,pmic-revid = <&smb1355_revid_1>;
- reg = <0x1000 0x700>;
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&smb1355_1>;
- status = "disabled";
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog-bark",
+ "temperature-change";
+ };
+ };
+};
- io-channels = <&pmi8998_rradc 2>,
- <&pmi8998_rradc 12>;
- io-channel-names = "charger_temp",
- "charger_temp_max";
+smb1355_1: qcom,smb1355@c {
+ compatible = "qcom,i2c-pmic";
+ reg = <0xc>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&spmi_bus>;
+ interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>;
+ interrupt_names = "smb1355_1";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ qcom,periph-map = <0x10 0x12 0x13 0x16>;
- qcom,chgr@1000 {
- reg = <0x1000 0x100>;
- interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "chg-state-change";
- };
+ smb1355_revid_1: qcom,revid@100 {
+ compatible = "qcom,qpnp-revid";
+ reg = <0x100 0x100>;
+ };
- qcom,chgr-misc@1600 {
- reg = <0x1600 0x100>;
- interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
- <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
- interrupt-names = "wdog-bark",
- "temperature-change";
- };
+ smb1355_charger_1: qcom,smb1355-charger@1000 {
+ compatible = "qcom,smb1355";
+ qcom,pmic-revid = <&smb1355_revid_1>;
+ reg = <0x1000 0x700>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&smb1355_1>;
+ status = "disabled";
+
+ io-channels = <&pmi8998_rradc 2>,
+ <&pmi8998_rradc 12>;
+ io-channel-names = "charger_temp",
+ "charger_temp_max";
+
+ qcom,chgr@1000 {
+ reg = <0x1000 0x100>;
+ interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "chg-state-change";
+ };
+
+ qcom,chgr-misc@1600 {
+ reg = <0x1600 0x100>;
+ interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>,
+ <0x16 0x6 IRQ_TYPE_EDGE_RISING>;
+ interrupt-names = "wdog-bark",
+ "temperature-change";
};
};
};
diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig
index 4c6b6a1..48d2bec 100644
--- a/arch/arm64/configs/msm8937-perf_defconfig
+++ b/arch/arm64/configs/msm8937-perf_defconfig
@@ -18,7 +18,6 @@
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_RT_GROUP_SCHED=y
@@ -68,7 +67,6 @@
CONFIG_ZSMALLOC=y
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
-CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -148,6 +146,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
@@ -224,6 +223,8 @@
CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -242,7 +243,6 @@
CONFIG_HDCP_QSEECOM=y
CONFIG_QSEECOM=y
CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -254,10 +254,8 @@
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_DEBUG=y
CONFIG_DM_CRYPT=y
CONFIG_DM_REQ_CRYPT=y
CONFIG_DM_UEVENT=y
@@ -309,6 +307,10 @@
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26=y
+CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
@@ -341,12 +343,12 @@
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
@@ -368,6 +370,7 @@
CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_QTI_BCL_PMIC5=y
CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -414,7 +417,6 @@
CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
CONFIG_MSM_VIDC_3X_V4L2=y
CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
@@ -428,7 +430,7 @@
CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
@@ -489,11 +491,12 @@
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
CONFIG_MMC_PARANOID_SD_INIT=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
@@ -578,6 +581,7 @@
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_SPDM_SCM=y
CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_PWM_QTI_LPG=y
@@ -589,6 +593,8 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -596,8 +602,6 @@
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
CONFIG_SDCARD_FS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig
index 11bd200..acb4a25 100644
--- a/arch/arm64/configs/msm8937_defconfig
+++ b/arch/arm64/configs/msm8937_defconfig
@@ -19,7 +19,6 @@
CONFIG_LOG_CPU_MAX_BUF_SHIFT=17
CONFIG_CGROUP_DEBUG=y
CONFIG_CGROUP_FREEZER=y
-CONFIG_CPUSETS=y
CONFIG_CGROUP_CPUACCT=y
CONFIG_CGROUP_SCHEDTUNE=y
CONFIG_RT_GROUP_SCHED=y
@@ -71,7 +70,6 @@
CONFIG_ZSMALLOC=y
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
-CONFIG_HARDEN_BRANCH_PREDICTOR=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -152,6 +150,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
@@ -230,6 +229,8 @@
CONFIG_RMNET_DATA_FC=y
CONFIG_RMNET_DATA_DEBUG_PKT=y
CONFIG_BT=y
+# CONFIG_BT_BREDR is not set
+# CONFIG_BT_LE is not set
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_CFG80211_INTERNAL_REGDB=y
@@ -248,7 +249,6 @@
CONFIG_HDCP_QSEECOM=y
CONFIG_QSEECOM=y
CONFIG_UID_SYS_STATS=y
-CONFIG_MEMORY_STATE_TIME=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
@@ -260,10 +260,8 @@
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_DEBUG=y
CONFIG_DM_CRYPT=y
CONFIG_DM_REQ_CRYPT=y
CONFIG_DM_UEVENT=y
@@ -315,6 +313,10 @@
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_JOYSTICK=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y
+CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26=y
+CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_HBTP_INPUT=y
CONFIG_INPUT_QPNP_POWER_ON=y
@@ -349,12 +351,12 @@
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_QPNP_PIN=y
-CONFIG_GPIO_QPNP_PIN_DEBUG=y
CONFIG_POWER_RESET_QCOM=y
CONFIG_QCOM_DLOAD_MODE=y
CONFIG_POWER_RESET_SYSCON=y
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
@@ -376,6 +378,7 @@
CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_QTI_BCL_PMIC5=y
CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -422,7 +425,6 @@
CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y
CONFIG_MSMB_JPEG=y
CONFIG_MSM_FD=y
-CONFIG_MSM_JPEGDMA=y
CONFIG_MSM_VIDC_3X_V4L2=y
CONFIG_MSM_VIDC_3X_GOVERNORS=y
CONFIG_MSM_SDE_ROTATOR=y
@@ -437,7 +439,7 @@
CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y
CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_DYNAMIC_MINORS=y
@@ -498,12 +500,13 @@
CONFIG_USB_CONFIGFS_F_QDSS=y
CONFIG_MMC=y
CONFIG_MMC_PERF_PROFILING=y
+# CONFIG_PWRSEQ_EMMC is not set
+# CONFIG_PWRSEQ_SIMPLE is not set
CONFIG_MMC_RING_BUFFER=y
CONFIG_MMC_PARANOID_SD_INIT=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
@@ -596,6 +599,7 @@
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_SPDM_SCM=y
CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_PWM_QTI_LPG=y
@@ -607,6 +611,8 @@
CONFIG_MSM_TZ_LOG=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_SECURITY=y
+CONFIG_F2FS_FS=y
+CONFIG_F2FS_FS_SECURITY=y
CONFIG_QUOTA=y
CONFIG_QUOTA_NETLINK_INTERFACE=y
CONFIG_QFMT_V2=y
@@ -615,8 +621,6 @@
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_ECRYPT_FS=y
-CONFIG_ECRYPT_FS_MESSAGING=y
CONFIG_SDCARD_FS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_NLS_CODEPAGE_437=y
diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig
index 7d64ca7..02902fa 100644
--- a/arch/arm64/configs/msm8953-perf_defconfig
+++ b/arch/arm64/configs/msm8953-perf_defconfig
@@ -67,6 +67,7 @@
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -344,6 +345,7 @@
CONFIG_POWER_RESET_SYSCON=y
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
@@ -365,6 +367,7 @@
CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_QTI_BCL_PMIC5=y
CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -578,12 +581,14 @@
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_BIG_CLUSTER_MIN_FREQ_ADJUST=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
CONFIG_DEVFREQ_SIMPLE_DEV=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_SPDM_SCM=y
CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_PWM_QTI_LPG=y
diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig
index de329bd..3b378f1 100644
--- a/arch/arm64/configs/msm8953_defconfig
+++ b/arch/arm64/configs/msm8953_defconfig
@@ -70,6 +70,7 @@
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -353,6 +354,7 @@
CONFIG_POWER_RESET_SYSCON=y
CONFIG_QPNP_FG=y
CONFIG_SMB135X_CHARGER=y
+CONFIG_SMB1355_SLAVE_CHARGER=y
CONFIG_SMB1351_USB_CHARGER=y
CONFIG_QPNP_SMB5=y
CONFIG_QPNP_SMBCHARGER=y
@@ -374,6 +376,7 @@
CONFIG_REGULATOR_COOLING_DEVICE=y
CONFIG_QTI_BCL_PMIC5=y
CONFIG_QTI_BCL_SOC_DRIVER=y
+CONFIG_MFD_I2C_PMIC=y
CONFIG_MFD_SPMI_PMIC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -598,12 +601,14 @@
CONFIG_WCNSS_CORE=y
CONFIG_WCNSS_CORE_PRONTO=y
CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y
+CONFIG_BIG_CLUSTER_MIN_FREQ_ADJUST=y
CONFIG_QCOM_BIMC_BWMON=y
CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y
CONFIG_DEVFREQ_SIMPLE_DEV=y
CONFIG_QCOM_DEVFREQ_DEVBW=y
CONFIG_SPDM_SCM=y
CONFIG_DEVFREQ_SPDM=y
+CONFIG_IIO=y
CONFIG_PWM=y
CONFIG_PWM_QPNP=y
CONFIG_PWM_QTI_LPG=y
diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig
index a411a88..8e7c369 100644
--- a/arch/arm64/configs/sdm670-perf_defconfig
+++ b/arch/arm64/configs/sdm670-perf_defconfig
@@ -67,6 +67,7 @@
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -287,6 +288,7 @@
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_LAN78XX=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig
index 3e8d865..5fb8fdb 100644
--- a/arch/arm64/configs/sdm670_defconfig
+++ b/arch/arm64/configs/sdm670_defconfig
@@ -72,6 +72,7 @@
CONFIG_PROCESS_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
@@ -293,6 +294,7 @@
CONFIG_PPPOPNS=y
CONFIG_PPP_ASYNC=y
CONFIG_PPP_SYNC_TTY=y
+CONFIG_USB_LAN78XX=y
CONFIG_USB_USBNET=y
CONFIG_WCNSS_MEM_PRE_ALLOC=y
CONFIG_CLD_LL_CORE=y
diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig
index a1fd1dc..fe5b5b5 100644
--- a/arch/arm64/configs/sdm845-perf_defconfig
+++ b/arch/arm64/configs/sdm845-perf_defconfig
@@ -65,6 +65,7 @@
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig
index 04608cd..666f350 100644
--- a/arch/arm64/configs/sdm845_defconfig
+++ b/arch/arm64/configs/sdm845_defconfig
@@ -69,6 +69,7 @@
CONFIG_BALANCE_ANON_FILE_RECLAIM=y
CONFIG_SECCOMP=y
CONFIG_HARDEN_BRANCH_PREDICTOR=y
+CONFIG_PSCI_BP_HARDENING=y
CONFIG_ARMV8_DEPRECATED=y
CONFIG_SWP_EMULATION=y
CONFIG_CP15_BARRIER_EMULATION=y
diff --git a/arch/arm64/crypto/sha256-core.S b/arch/arm64/crypto/sha256-core.S
new file mode 100644
index 0000000..3ce82cc
--- /dev/null
+++ b/arch/arm64/crypto/sha256-core.S
@@ -0,0 +1,2061 @@
+// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the OpenSSL license (the "License"). You may not use
+// this file except in compliance with the License. You can obtain a copy
+// in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+
+// ====================================================================
+// Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// project. The module is, however, dual licensed under OpenSSL and
+// CRYPTOGAMS licenses depending on where you obtain it. For further
+// details see http://www.openssl.org/~appro/cryptogams/.
+//
+// Permission to use under GPLv2 terms is granted.
+// ====================================================================
+//
+// SHA256/512 for ARMv8.
+//
+// Performance in cycles per processed byte and improvement coefficient
+// over code generated with "default" compiler:
+//
+// SHA256-hw SHA256(*) SHA512
+// Apple A7 1.97 10.5 (+33%) 6.73 (-1%(**))
+// Cortex-A53 2.38 15.5 (+115%) 10.0 (+150%(***))
+// Cortex-A57 2.31 11.6 (+86%) 7.51 (+260%(***))
+// Denver 2.01 10.5 (+26%) 6.70 (+8%)
+// X-Gene 20.0 (+100%) 12.8 (+300%(***))
+// Mongoose 2.36 13.0 (+50%) 8.36 (+33%)
+//
+// (*) Software SHA256 results are of lesser relevance, presented
+// mostly for informational purposes.
+// (**) The result is a trade-off: it's possible to improve it by
+// 10% (or by 1 cycle per round), but at the cost of 20% loss
+// on Cortex-A53 (or by 4 cycles per round).
+// (***) Super-impressive coefficients over gcc-generated code are
+// indication of some compiler "pathology", most notably code
+// generated with -mgeneral-regs-only is significanty faster
+// and the gap is only 40-90%.
+//
+// October 2016.
+//
+// Originally it was reckoned that it makes no sense to implement NEON
+// version of SHA256 for 64-bit processors. This is because performance
+// improvement on most wide-spread Cortex-A5x processors was observed
+// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
+// observed that 32-bit NEON SHA256 performs significantly better than
+// 64-bit scalar version on *some* of the more recent processors. As
+// result 64-bit NEON version of SHA256 was added to provide best
+// all-round performance. For example it executes ~30% faster on X-Gene
+// and Mongoose. [For reference, NEON version of SHA512 is bound to
+// deliver much less improvement, likely *negative* on Cortex-A5x.
+// Which is why NEON support is limited to SHA256.]
+
+#ifndef __KERNEL__
+# include "arm_arch.h"
+#endif
+
+.text
+
+.extern OPENSSL_armcap_P
+.globl sha256_block_data_order
+.type sha256_block_data_order,%function
+.align 6
+sha256_block_data_order:
+#ifndef __KERNEL__
+# ifdef __ILP32__
+ ldrsw x16,.LOPENSSL_armcap_P
+# else
+ ldr x16,.LOPENSSL_armcap_P
+# endif
+ adr x17,.LOPENSSL_armcap_P
+ add x16,x16,x17
+ ldr w16,[x16]
+ tst w16,#ARMV8_SHA256
+ b.ne .Lv8_entry
+ tst w16,#ARMV7_NEON
+ b.ne .Lneon_entry
+#endif
+ stp x29,x30,[sp,#-128]!
+ add x29,sp,#0
+
+ stp x19,x20,[sp,#16]
+ stp x21,x22,[sp,#32]
+ stp x23,x24,[sp,#48]
+ stp x25,x26,[sp,#64]
+ stp x27,x28,[sp,#80]
+ sub sp,sp,#4*4
+
+ ldp w20,w21,[x0] // load context
+ ldp w22,w23,[x0,#2*4]
+ ldp w24,w25,[x0,#4*4]
+ add x2,x1,x2,lsl#6 // end of input
+ ldp w26,w27,[x0,#6*4]
+ adr x30,.LK256
+ stp x0,x2,[x29,#96]
+
+.Loop:
+ ldp w3,w4,[x1],#2*4
+ ldr w19,[x30],#4 // *K++
+ eor w28,w21,w22 // magic seed
+ str x1,[x29,#112]
+#ifndef __AARCH64EB__
+ rev w3,w3 // 0
+#endif
+ ror w16,w24,#6
+ add w27,w27,w19 // h+=K[i]
+ eor w6,w24,w24,ror#14
+ and w17,w25,w24
+ bic w19,w26,w24
+ add w27,w27,w3 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w20,w21 // a^b, b^c in next round
+ eor w16,w16,w6,ror#11 // Sigma1(e)
+ ror w6,w20,#2
+ add w27,w27,w17 // h+=Ch(e,f,g)
+ eor w17,w20,w20,ror#9
+ add w27,w27,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w23,w23,w27 // d+=h
+ eor w28,w28,w21 // Maj(a,b,c)
+ eor w17,w6,w17,ror#13 // Sigma0(a)
+ add w27,w27,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w27,w27,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w4,w4 // 1
+#endif
+ ldp w5,w6,[x1],#2*4
+ add w27,w27,w17 // h+=Sigma0(a)
+ ror w16,w23,#6
+ add w26,w26,w28 // h+=K[i]
+ eor w7,w23,w23,ror#14
+ and w17,w24,w23
+ bic w28,w25,w23
+ add w26,w26,w4 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w27,w20 // a^b, b^c in next round
+ eor w16,w16,w7,ror#11 // Sigma1(e)
+ ror w7,w27,#2
+ add w26,w26,w17 // h+=Ch(e,f,g)
+ eor w17,w27,w27,ror#9
+ add w26,w26,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w22,w22,w26 // d+=h
+ eor w19,w19,w20 // Maj(a,b,c)
+ eor w17,w7,w17,ror#13 // Sigma0(a)
+ add w26,w26,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w26,w26,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w5,w5 // 2
+#endif
+ add w26,w26,w17 // h+=Sigma0(a)
+ ror w16,w22,#6
+ add w25,w25,w19 // h+=K[i]
+ eor w8,w22,w22,ror#14
+ and w17,w23,w22
+ bic w19,w24,w22
+ add w25,w25,w5 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w26,w27 // a^b, b^c in next round
+ eor w16,w16,w8,ror#11 // Sigma1(e)
+ ror w8,w26,#2
+ add w25,w25,w17 // h+=Ch(e,f,g)
+ eor w17,w26,w26,ror#9
+ add w25,w25,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w21,w21,w25 // d+=h
+ eor w28,w28,w27 // Maj(a,b,c)
+ eor w17,w8,w17,ror#13 // Sigma0(a)
+ add w25,w25,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w25,w25,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w6,w6 // 3
+#endif
+ ldp w7,w8,[x1],#2*4
+ add w25,w25,w17 // h+=Sigma0(a)
+ ror w16,w21,#6
+ add w24,w24,w28 // h+=K[i]
+ eor w9,w21,w21,ror#14
+ and w17,w22,w21
+ bic w28,w23,w21
+ add w24,w24,w6 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w25,w26 // a^b, b^c in next round
+ eor w16,w16,w9,ror#11 // Sigma1(e)
+ ror w9,w25,#2
+ add w24,w24,w17 // h+=Ch(e,f,g)
+ eor w17,w25,w25,ror#9
+ add w24,w24,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w20,w20,w24 // d+=h
+ eor w19,w19,w26 // Maj(a,b,c)
+ eor w17,w9,w17,ror#13 // Sigma0(a)
+ add w24,w24,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w24,w24,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w7,w7 // 4
+#endif
+ add w24,w24,w17 // h+=Sigma0(a)
+ ror w16,w20,#6
+ add w23,w23,w19 // h+=K[i]
+ eor w10,w20,w20,ror#14
+ and w17,w21,w20
+ bic w19,w22,w20
+ add w23,w23,w7 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w24,w25 // a^b, b^c in next round
+ eor w16,w16,w10,ror#11 // Sigma1(e)
+ ror w10,w24,#2
+ add w23,w23,w17 // h+=Ch(e,f,g)
+ eor w17,w24,w24,ror#9
+ add w23,w23,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w27,w27,w23 // d+=h
+ eor w28,w28,w25 // Maj(a,b,c)
+ eor w17,w10,w17,ror#13 // Sigma0(a)
+ add w23,w23,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w23,w23,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w8,w8 // 5
+#endif
+ ldp w9,w10,[x1],#2*4
+ add w23,w23,w17 // h+=Sigma0(a)
+ ror w16,w27,#6
+ add w22,w22,w28 // h+=K[i]
+ eor w11,w27,w27,ror#14
+ and w17,w20,w27
+ bic w28,w21,w27
+ add w22,w22,w8 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w23,w24 // a^b, b^c in next round
+ eor w16,w16,w11,ror#11 // Sigma1(e)
+ ror w11,w23,#2
+ add w22,w22,w17 // h+=Ch(e,f,g)
+ eor w17,w23,w23,ror#9
+ add w22,w22,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w26,w26,w22 // d+=h
+ eor w19,w19,w24 // Maj(a,b,c)
+ eor w17,w11,w17,ror#13 // Sigma0(a)
+ add w22,w22,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w22,w22,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w9,w9 // 6
+#endif
+ add w22,w22,w17 // h+=Sigma0(a)
+ ror w16,w26,#6
+ add w21,w21,w19 // h+=K[i]
+ eor w12,w26,w26,ror#14
+ and w17,w27,w26
+ bic w19,w20,w26
+ add w21,w21,w9 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w22,w23 // a^b, b^c in next round
+ eor w16,w16,w12,ror#11 // Sigma1(e)
+ ror w12,w22,#2
+ add w21,w21,w17 // h+=Ch(e,f,g)
+ eor w17,w22,w22,ror#9
+ add w21,w21,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w25,w25,w21 // d+=h
+ eor w28,w28,w23 // Maj(a,b,c)
+ eor w17,w12,w17,ror#13 // Sigma0(a)
+ add w21,w21,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w21,w21,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w10,w10 // 7
+#endif
+ ldp w11,w12,[x1],#2*4
+ add w21,w21,w17 // h+=Sigma0(a)
+ ror w16,w25,#6
+ add w20,w20,w28 // h+=K[i]
+ eor w13,w25,w25,ror#14
+ and w17,w26,w25
+ bic w28,w27,w25
+ add w20,w20,w10 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w21,w22 // a^b, b^c in next round
+ eor w16,w16,w13,ror#11 // Sigma1(e)
+ ror w13,w21,#2
+ add w20,w20,w17 // h+=Ch(e,f,g)
+ eor w17,w21,w21,ror#9
+ add w20,w20,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w24,w24,w20 // d+=h
+ eor w19,w19,w22 // Maj(a,b,c)
+ eor w17,w13,w17,ror#13 // Sigma0(a)
+ add w20,w20,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w20,w20,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w11,w11 // 8
+#endif
+ add w20,w20,w17 // h+=Sigma0(a)
+ ror w16,w24,#6
+ add w27,w27,w19 // h+=K[i]
+ eor w14,w24,w24,ror#14
+ and w17,w25,w24
+ bic w19,w26,w24
+ add w27,w27,w11 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w20,w21 // a^b, b^c in next round
+ eor w16,w16,w14,ror#11 // Sigma1(e)
+ ror w14,w20,#2
+ add w27,w27,w17 // h+=Ch(e,f,g)
+ eor w17,w20,w20,ror#9
+ add w27,w27,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w23,w23,w27 // d+=h
+ eor w28,w28,w21 // Maj(a,b,c)
+ eor w17,w14,w17,ror#13 // Sigma0(a)
+ add w27,w27,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w27,w27,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w12,w12 // 9
+#endif
+ ldp w13,w14,[x1],#2*4
+ add w27,w27,w17 // h+=Sigma0(a)
+ ror w16,w23,#6
+ add w26,w26,w28 // h+=K[i]
+ eor w15,w23,w23,ror#14
+ and w17,w24,w23
+ bic w28,w25,w23
+ add w26,w26,w12 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w27,w20 // a^b, b^c in next round
+ eor w16,w16,w15,ror#11 // Sigma1(e)
+ ror w15,w27,#2
+ add w26,w26,w17 // h+=Ch(e,f,g)
+ eor w17,w27,w27,ror#9
+ add w26,w26,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w22,w22,w26 // d+=h
+ eor w19,w19,w20 // Maj(a,b,c)
+ eor w17,w15,w17,ror#13 // Sigma0(a)
+ add w26,w26,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w26,w26,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w13,w13 // 10
+#endif
+ add w26,w26,w17 // h+=Sigma0(a)
+ ror w16,w22,#6
+ add w25,w25,w19 // h+=K[i]
+ eor w0,w22,w22,ror#14
+ and w17,w23,w22
+ bic w19,w24,w22
+ add w25,w25,w13 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w26,w27 // a^b, b^c in next round
+ eor w16,w16,w0,ror#11 // Sigma1(e)
+ ror w0,w26,#2
+ add w25,w25,w17 // h+=Ch(e,f,g)
+ eor w17,w26,w26,ror#9
+ add w25,w25,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w21,w21,w25 // d+=h
+ eor w28,w28,w27 // Maj(a,b,c)
+ eor w17,w0,w17,ror#13 // Sigma0(a)
+ add w25,w25,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w25,w25,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w14,w14 // 11
+#endif
+ ldp w15,w0,[x1],#2*4
+ add w25,w25,w17 // h+=Sigma0(a)
+ str w6,[sp,#12]
+ ror w16,w21,#6
+ add w24,w24,w28 // h+=K[i]
+ eor w6,w21,w21,ror#14
+ and w17,w22,w21
+ bic w28,w23,w21
+ add w24,w24,w14 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w25,w26 // a^b, b^c in next round
+ eor w16,w16,w6,ror#11 // Sigma1(e)
+ ror w6,w25,#2
+ add w24,w24,w17 // h+=Ch(e,f,g)
+ eor w17,w25,w25,ror#9
+ add w24,w24,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w20,w20,w24 // d+=h
+ eor w19,w19,w26 // Maj(a,b,c)
+ eor w17,w6,w17,ror#13 // Sigma0(a)
+ add w24,w24,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w24,w24,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w15,w15 // 12
+#endif
+ add w24,w24,w17 // h+=Sigma0(a)
+ str w7,[sp,#0]
+ ror w16,w20,#6
+ add w23,w23,w19 // h+=K[i]
+ eor w7,w20,w20,ror#14
+ and w17,w21,w20
+ bic w19,w22,w20
+ add w23,w23,w15 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w24,w25 // a^b, b^c in next round
+ eor w16,w16,w7,ror#11 // Sigma1(e)
+ ror w7,w24,#2
+ add w23,w23,w17 // h+=Ch(e,f,g)
+ eor w17,w24,w24,ror#9
+ add w23,w23,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w27,w27,w23 // d+=h
+ eor w28,w28,w25 // Maj(a,b,c)
+ eor w17,w7,w17,ror#13 // Sigma0(a)
+ add w23,w23,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w23,w23,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w0,w0 // 13
+#endif
+ ldp w1,w2,[x1]
+ add w23,w23,w17 // h+=Sigma0(a)
+ str w8,[sp,#4]
+ ror w16,w27,#6
+ add w22,w22,w28 // h+=K[i]
+ eor w8,w27,w27,ror#14
+ and w17,w20,w27
+ bic w28,w21,w27
+ add w22,w22,w0 // h+=X[i]
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w23,w24 // a^b, b^c in next round
+ eor w16,w16,w8,ror#11 // Sigma1(e)
+ ror w8,w23,#2
+ add w22,w22,w17 // h+=Ch(e,f,g)
+ eor w17,w23,w23,ror#9
+ add w22,w22,w16 // h+=Sigma1(e)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ add w26,w26,w22 // d+=h
+ eor w19,w19,w24 // Maj(a,b,c)
+ eor w17,w8,w17,ror#13 // Sigma0(a)
+ add w22,w22,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ //add w22,w22,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w1,w1 // 14
+#endif
+ ldr w6,[sp,#12]
+ add w22,w22,w17 // h+=Sigma0(a)
+ str w9,[sp,#8]
+ ror w16,w26,#6
+ add w21,w21,w19 // h+=K[i]
+ eor w9,w26,w26,ror#14
+ and w17,w27,w26
+ bic w19,w20,w26
+ add w21,w21,w1 // h+=X[i]
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w22,w23 // a^b, b^c in next round
+ eor w16,w16,w9,ror#11 // Sigma1(e)
+ ror w9,w22,#2
+ add w21,w21,w17 // h+=Ch(e,f,g)
+ eor w17,w22,w22,ror#9
+ add w21,w21,w16 // h+=Sigma1(e)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ add w25,w25,w21 // d+=h
+ eor w28,w28,w23 // Maj(a,b,c)
+ eor w17,w9,w17,ror#13 // Sigma0(a)
+ add w21,w21,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ //add w21,w21,w17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev w2,w2 // 15
+#endif
+ ldr w7,[sp,#0]
+ add w21,w21,w17 // h+=Sigma0(a)
+ str w10,[sp,#12]
+ ror w16,w25,#6
+ add w20,w20,w28 // h+=K[i]
+ ror w9,w4,#7
+ and w17,w26,w25
+ ror w8,w1,#17
+ bic w28,w27,w25
+ ror w10,w21,#2
+ add w20,w20,w2 // h+=X[i]
+ eor w16,w16,w25,ror#11
+ eor w9,w9,w4,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w21,w22 // a^b, b^c in next round
+ eor w16,w16,w25,ror#25 // Sigma1(e)
+ eor w10,w10,w21,ror#13
+ add w20,w20,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w8,w8,w1,ror#19
+ eor w9,w9,w4,lsr#3 // sigma0(X[i+1])
+ add w20,w20,w16 // h+=Sigma1(e)
+ eor w19,w19,w22 // Maj(a,b,c)
+ eor w17,w10,w21,ror#22 // Sigma0(a)
+ eor w8,w8,w1,lsr#10 // sigma1(X[i+14])
+ add w3,w3,w12
+ add w24,w24,w20 // d+=h
+ add w20,w20,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w3,w3,w9
+ add w20,w20,w17 // h+=Sigma0(a)
+ add w3,w3,w8
+.Loop_16_xx:
+ ldr w8,[sp,#4]
+ str w11,[sp,#0]
+ ror w16,w24,#6
+ add w27,w27,w19 // h+=K[i]
+ ror w10,w5,#7
+ and w17,w25,w24
+ ror w9,w2,#17
+ bic w19,w26,w24
+ ror w11,w20,#2
+ add w27,w27,w3 // h+=X[i]
+ eor w16,w16,w24,ror#11
+ eor w10,w10,w5,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w20,w21 // a^b, b^c in next round
+ eor w16,w16,w24,ror#25 // Sigma1(e)
+ eor w11,w11,w20,ror#13
+ add w27,w27,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w9,w9,w2,ror#19
+ eor w10,w10,w5,lsr#3 // sigma0(X[i+1])
+ add w27,w27,w16 // h+=Sigma1(e)
+ eor w28,w28,w21 // Maj(a,b,c)
+ eor w17,w11,w20,ror#22 // Sigma0(a)
+ eor w9,w9,w2,lsr#10 // sigma1(X[i+14])
+ add w4,w4,w13
+ add w23,w23,w27 // d+=h
+ add w27,w27,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w4,w4,w10
+ add w27,w27,w17 // h+=Sigma0(a)
+ add w4,w4,w9
+ ldr w9,[sp,#8]
+ str w12,[sp,#4]
+ ror w16,w23,#6
+ add w26,w26,w28 // h+=K[i]
+ ror w11,w6,#7
+ and w17,w24,w23
+ ror w10,w3,#17
+ bic w28,w25,w23
+ ror w12,w27,#2
+ add w26,w26,w4 // h+=X[i]
+ eor w16,w16,w23,ror#11
+ eor w11,w11,w6,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w27,w20 // a^b, b^c in next round
+ eor w16,w16,w23,ror#25 // Sigma1(e)
+ eor w12,w12,w27,ror#13
+ add w26,w26,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w10,w10,w3,ror#19
+ eor w11,w11,w6,lsr#3 // sigma0(X[i+1])
+ add w26,w26,w16 // h+=Sigma1(e)
+ eor w19,w19,w20 // Maj(a,b,c)
+ eor w17,w12,w27,ror#22 // Sigma0(a)
+ eor w10,w10,w3,lsr#10 // sigma1(X[i+14])
+ add w5,w5,w14
+ add w22,w22,w26 // d+=h
+ add w26,w26,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w5,w5,w11
+ add w26,w26,w17 // h+=Sigma0(a)
+ add w5,w5,w10
+ ldr w10,[sp,#12]
+ str w13,[sp,#8]
+ ror w16,w22,#6
+ add w25,w25,w19 // h+=K[i]
+ ror w12,w7,#7
+ and w17,w23,w22
+ ror w11,w4,#17
+ bic w19,w24,w22
+ ror w13,w26,#2
+ add w25,w25,w5 // h+=X[i]
+ eor w16,w16,w22,ror#11
+ eor w12,w12,w7,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w26,w27 // a^b, b^c in next round
+ eor w16,w16,w22,ror#25 // Sigma1(e)
+ eor w13,w13,w26,ror#13
+ add w25,w25,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w11,w11,w4,ror#19
+ eor w12,w12,w7,lsr#3 // sigma0(X[i+1])
+ add w25,w25,w16 // h+=Sigma1(e)
+ eor w28,w28,w27 // Maj(a,b,c)
+ eor w17,w13,w26,ror#22 // Sigma0(a)
+ eor w11,w11,w4,lsr#10 // sigma1(X[i+14])
+ add w6,w6,w15
+ add w21,w21,w25 // d+=h
+ add w25,w25,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w6,w6,w12
+ add w25,w25,w17 // h+=Sigma0(a)
+ add w6,w6,w11
+ ldr w11,[sp,#0]
+ str w14,[sp,#12]
+ ror w16,w21,#6
+ add w24,w24,w28 // h+=K[i]
+ ror w13,w8,#7
+ and w17,w22,w21
+ ror w12,w5,#17
+ bic w28,w23,w21
+ ror w14,w25,#2
+ add w24,w24,w6 // h+=X[i]
+ eor w16,w16,w21,ror#11
+ eor w13,w13,w8,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w25,w26 // a^b, b^c in next round
+ eor w16,w16,w21,ror#25 // Sigma1(e)
+ eor w14,w14,w25,ror#13
+ add w24,w24,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w12,w12,w5,ror#19
+ eor w13,w13,w8,lsr#3 // sigma0(X[i+1])
+ add w24,w24,w16 // h+=Sigma1(e)
+ eor w19,w19,w26 // Maj(a,b,c)
+ eor w17,w14,w25,ror#22 // Sigma0(a)
+ eor w12,w12,w5,lsr#10 // sigma1(X[i+14])
+ add w7,w7,w0
+ add w20,w20,w24 // d+=h
+ add w24,w24,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w7,w7,w13
+ add w24,w24,w17 // h+=Sigma0(a)
+ add w7,w7,w12
+ ldr w12,[sp,#4]
+ str w15,[sp,#0]
+ ror w16,w20,#6
+ add w23,w23,w19 // h+=K[i]
+ ror w14,w9,#7
+ and w17,w21,w20
+ ror w13,w6,#17
+ bic w19,w22,w20
+ ror w15,w24,#2
+ add w23,w23,w7 // h+=X[i]
+ eor w16,w16,w20,ror#11
+ eor w14,w14,w9,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w24,w25 // a^b, b^c in next round
+ eor w16,w16,w20,ror#25 // Sigma1(e)
+ eor w15,w15,w24,ror#13
+ add w23,w23,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w13,w13,w6,ror#19
+ eor w14,w14,w9,lsr#3 // sigma0(X[i+1])
+ add w23,w23,w16 // h+=Sigma1(e)
+ eor w28,w28,w25 // Maj(a,b,c)
+ eor w17,w15,w24,ror#22 // Sigma0(a)
+ eor w13,w13,w6,lsr#10 // sigma1(X[i+14])
+ add w8,w8,w1
+ add w27,w27,w23 // d+=h
+ add w23,w23,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w8,w8,w14
+ add w23,w23,w17 // h+=Sigma0(a)
+ add w8,w8,w13
+ ldr w13,[sp,#8]
+ str w0,[sp,#4]
+ ror w16,w27,#6
+ add w22,w22,w28 // h+=K[i]
+ ror w15,w10,#7
+ and w17,w20,w27
+ ror w14,w7,#17
+ bic w28,w21,w27
+ ror w0,w23,#2
+ add w22,w22,w8 // h+=X[i]
+ eor w16,w16,w27,ror#11
+ eor w15,w15,w10,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w23,w24 // a^b, b^c in next round
+ eor w16,w16,w27,ror#25 // Sigma1(e)
+ eor w0,w0,w23,ror#13
+ add w22,w22,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w14,w14,w7,ror#19
+ eor w15,w15,w10,lsr#3 // sigma0(X[i+1])
+ add w22,w22,w16 // h+=Sigma1(e)
+ eor w19,w19,w24 // Maj(a,b,c)
+ eor w17,w0,w23,ror#22 // Sigma0(a)
+ eor w14,w14,w7,lsr#10 // sigma1(X[i+14])
+ add w9,w9,w2
+ add w26,w26,w22 // d+=h
+ add w22,w22,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w9,w9,w15
+ add w22,w22,w17 // h+=Sigma0(a)
+ add w9,w9,w14
+ ldr w14,[sp,#12]
+ str w1,[sp,#8]
+ ror w16,w26,#6
+ add w21,w21,w19 // h+=K[i]
+ ror w0,w11,#7
+ and w17,w27,w26
+ ror w15,w8,#17
+ bic w19,w20,w26
+ ror w1,w22,#2
+ add w21,w21,w9 // h+=X[i]
+ eor w16,w16,w26,ror#11
+ eor w0,w0,w11,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w22,w23 // a^b, b^c in next round
+ eor w16,w16,w26,ror#25 // Sigma1(e)
+ eor w1,w1,w22,ror#13
+ add w21,w21,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w15,w15,w8,ror#19
+ eor w0,w0,w11,lsr#3 // sigma0(X[i+1])
+ add w21,w21,w16 // h+=Sigma1(e)
+ eor w28,w28,w23 // Maj(a,b,c)
+ eor w17,w1,w22,ror#22 // Sigma0(a)
+ eor w15,w15,w8,lsr#10 // sigma1(X[i+14])
+ add w10,w10,w3
+ add w25,w25,w21 // d+=h
+ add w21,w21,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w10,w10,w0
+ add w21,w21,w17 // h+=Sigma0(a)
+ add w10,w10,w15
+ ldr w15,[sp,#0]
+ str w2,[sp,#12]
+ ror w16,w25,#6
+ add w20,w20,w28 // h+=K[i]
+ ror w1,w12,#7
+ and w17,w26,w25
+ ror w0,w9,#17
+ bic w28,w27,w25
+ ror w2,w21,#2
+ add w20,w20,w10 // h+=X[i]
+ eor w16,w16,w25,ror#11
+ eor w1,w1,w12,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w21,w22 // a^b, b^c in next round
+ eor w16,w16,w25,ror#25 // Sigma1(e)
+ eor w2,w2,w21,ror#13
+ add w20,w20,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w0,w0,w9,ror#19
+ eor w1,w1,w12,lsr#3 // sigma0(X[i+1])
+ add w20,w20,w16 // h+=Sigma1(e)
+ eor w19,w19,w22 // Maj(a,b,c)
+ eor w17,w2,w21,ror#22 // Sigma0(a)
+ eor w0,w0,w9,lsr#10 // sigma1(X[i+14])
+ add w11,w11,w4
+ add w24,w24,w20 // d+=h
+ add w20,w20,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w11,w11,w1
+ add w20,w20,w17 // h+=Sigma0(a)
+ add w11,w11,w0
+ ldr w0,[sp,#4]
+ str w3,[sp,#0]
+ ror w16,w24,#6
+ add w27,w27,w19 // h+=K[i]
+ ror w2,w13,#7
+ and w17,w25,w24
+ ror w1,w10,#17
+ bic w19,w26,w24
+ ror w3,w20,#2
+ add w27,w27,w11 // h+=X[i]
+ eor w16,w16,w24,ror#11
+ eor w2,w2,w13,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w20,w21 // a^b, b^c in next round
+ eor w16,w16,w24,ror#25 // Sigma1(e)
+ eor w3,w3,w20,ror#13
+ add w27,w27,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w1,w1,w10,ror#19
+ eor w2,w2,w13,lsr#3 // sigma0(X[i+1])
+ add w27,w27,w16 // h+=Sigma1(e)
+ eor w28,w28,w21 // Maj(a,b,c)
+ eor w17,w3,w20,ror#22 // Sigma0(a)
+ eor w1,w1,w10,lsr#10 // sigma1(X[i+14])
+ add w12,w12,w5
+ add w23,w23,w27 // d+=h
+ add w27,w27,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w12,w12,w2
+ add w27,w27,w17 // h+=Sigma0(a)
+ add w12,w12,w1
+ ldr w1,[sp,#8]
+ str w4,[sp,#4]
+ ror w16,w23,#6
+ add w26,w26,w28 // h+=K[i]
+ ror w3,w14,#7
+ and w17,w24,w23
+ ror w2,w11,#17
+ bic w28,w25,w23
+ ror w4,w27,#2
+ add w26,w26,w12 // h+=X[i]
+ eor w16,w16,w23,ror#11
+ eor w3,w3,w14,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w27,w20 // a^b, b^c in next round
+ eor w16,w16,w23,ror#25 // Sigma1(e)
+ eor w4,w4,w27,ror#13
+ add w26,w26,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w2,w2,w11,ror#19
+ eor w3,w3,w14,lsr#3 // sigma0(X[i+1])
+ add w26,w26,w16 // h+=Sigma1(e)
+ eor w19,w19,w20 // Maj(a,b,c)
+ eor w17,w4,w27,ror#22 // Sigma0(a)
+ eor w2,w2,w11,lsr#10 // sigma1(X[i+14])
+ add w13,w13,w6
+ add w22,w22,w26 // d+=h
+ add w26,w26,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w13,w13,w3
+ add w26,w26,w17 // h+=Sigma0(a)
+ add w13,w13,w2
+ ldr w2,[sp,#12]
+ str w5,[sp,#8]
+ ror w16,w22,#6
+ add w25,w25,w19 // h+=K[i]
+ ror w4,w15,#7
+ and w17,w23,w22
+ ror w3,w12,#17
+ bic w19,w24,w22
+ ror w5,w26,#2
+ add w25,w25,w13 // h+=X[i]
+ eor w16,w16,w22,ror#11
+ eor w4,w4,w15,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w26,w27 // a^b, b^c in next round
+ eor w16,w16,w22,ror#25 // Sigma1(e)
+ eor w5,w5,w26,ror#13
+ add w25,w25,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w3,w3,w12,ror#19
+ eor w4,w4,w15,lsr#3 // sigma0(X[i+1])
+ add w25,w25,w16 // h+=Sigma1(e)
+ eor w28,w28,w27 // Maj(a,b,c)
+ eor w17,w5,w26,ror#22 // Sigma0(a)
+ eor w3,w3,w12,lsr#10 // sigma1(X[i+14])
+ add w14,w14,w7
+ add w21,w21,w25 // d+=h
+ add w25,w25,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w14,w14,w4
+ add w25,w25,w17 // h+=Sigma0(a)
+ add w14,w14,w3
+ ldr w3,[sp,#0]
+ str w6,[sp,#12]
+ ror w16,w21,#6
+ add w24,w24,w28 // h+=K[i]
+ ror w5,w0,#7
+ and w17,w22,w21
+ ror w4,w13,#17
+ bic w28,w23,w21
+ ror w6,w25,#2
+ add w24,w24,w14 // h+=X[i]
+ eor w16,w16,w21,ror#11
+ eor w5,w5,w0,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w25,w26 // a^b, b^c in next round
+ eor w16,w16,w21,ror#25 // Sigma1(e)
+ eor w6,w6,w25,ror#13
+ add w24,w24,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w4,w4,w13,ror#19
+ eor w5,w5,w0,lsr#3 // sigma0(X[i+1])
+ add w24,w24,w16 // h+=Sigma1(e)
+ eor w19,w19,w26 // Maj(a,b,c)
+ eor w17,w6,w25,ror#22 // Sigma0(a)
+ eor w4,w4,w13,lsr#10 // sigma1(X[i+14])
+ add w15,w15,w8
+ add w20,w20,w24 // d+=h
+ add w24,w24,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w15,w15,w5
+ add w24,w24,w17 // h+=Sigma0(a)
+ add w15,w15,w4
+ ldr w4,[sp,#4]
+ str w7,[sp,#0]
+ ror w16,w20,#6
+ add w23,w23,w19 // h+=K[i]
+ ror w6,w1,#7
+ and w17,w21,w20
+ ror w5,w14,#17
+ bic w19,w22,w20
+ ror w7,w24,#2
+ add w23,w23,w15 // h+=X[i]
+ eor w16,w16,w20,ror#11
+ eor w6,w6,w1,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w24,w25 // a^b, b^c in next round
+ eor w16,w16,w20,ror#25 // Sigma1(e)
+ eor w7,w7,w24,ror#13
+ add w23,w23,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w5,w5,w14,ror#19
+ eor w6,w6,w1,lsr#3 // sigma0(X[i+1])
+ add w23,w23,w16 // h+=Sigma1(e)
+ eor w28,w28,w25 // Maj(a,b,c)
+ eor w17,w7,w24,ror#22 // Sigma0(a)
+ eor w5,w5,w14,lsr#10 // sigma1(X[i+14])
+ add w0,w0,w9
+ add w27,w27,w23 // d+=h
+ add w23,w23,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w0,w0,w6
+ add w23,w23,w17 // h+=Sigma0(a)
+ add w0,w0,w5
+ ldr w5,[sp,#8]
+ str w8,[sp,#4]
+ ror w16,w27,#6
+ add w22,w22,w28 // h+=K[i]
+ ror w7,w2,#7
+ and w17,w20,w27
+ ror w6,w15,#17
+ bic w28,w21,w27
+ ror w8,w23,#2
+ add w22,w22,w0 // h+=X[i]
+ eor w16,w16,w27,ror#11
+ eor w7,w7,w2,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w23,w24 // a^b, b^c in next round
+ eor w16,w16,w27,ror#25 // Sigma1(e)
+ eor w8,w8,w23,ror#13
+ add w22,w22,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w6,w6,w15,ror#19
+ eor w7,w7,w2,lsr#3 // sigma0(X[i+1])
+ add w22,w22,w16 // h+=Sigma1(e)
+ eor w19,w19,w24 // Maj(a,b,c)
+ eor w17,w8,w23,ror#22 // Sigma0(a)
+ eor w6,w6,w15,lsr#10 // sigma1(X[i+14])
+ add w1,w1,w10
+ add w26,w26,w22 // d+=h
+ add w22,w22,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w1,w1,w7
+ add w22,w22,w17 // h+=Sigma0(a)
+ add w1,w1,w6
+ ldr w6,[sp,#12]
+ str w9,[sp,#8]
+ ror w16,w26,#6
+ add w21,w21,w19 // h+=K[i]
+ ror w8,w3,#7
+ and w17,w27,w26
+ ror w7,w0,#17
+ bic w19,w20,w26
+ ror w9,w22,#2
+ add w21,w21,w1 // h+=X[i]
+ eor w16,w16,w26,ror#11
+ eor w8,w8,w3,ror#18
+ orr w17,w17,w19 // Ch(e,f,g)
+ eor w19,w22,w23 // a^b, b^c in next round
+ eor w16,w16,w26,ror#25 // Sigma1(e)
+ eor w9,w9,w22,ror#13
+ add w21,w21,w17 // h+=Ch(e,f,g)
+ and w28,w28,w19 // (b^c)&=(a^b)
+ eor w7,w7,w0,ror#19
+ eor w8,w8,w3,lsr#3 // sigma0(X[i+1])
+ add w21,w21,w16 // h+=Sigma1(e)
+ eor w28,w28,w23 // Maj(a,b,c)
+ eor w17,w9,w22,ror#22 // Sigma0(a)
+ eor w7,w7,w0,lsr#10 // sigma1(X[i+14])
+ add w2,w2,w11
+ add w25,w25,w21 // d+=h
+ add w21,w21,w28 // h+=Maj(a,b,c)
+ ldr w28,[x30],#4 // *K++, w19 in next round
+ add w2,w2,w8
+ add w21,w21,w17 // h+=Sigma0(a)
+ add w2,w2,w7
+ ldr w7,[sp,#0]
+ str w10,[sp,#12]
+ ror w16,w25,#6
+ add w20,w20,w28 // h+=K[i]
+ ror w9,w4,#7
+ and w17,w26,w25
+ ror w8,w1,#17
+ bic w28,w27,w25
+ ror w10,w21,#2
+ add w20,w20,w2 // h+=X[i]
+ eor w16,w16,w25,ror#11
+ eor w9,w9,w4,ror#18
+ orr w17,w17,w28 // Ch(e,f,g)
+ eor w28,w21,w22 // a^b, b^c in next round
+ eor w16,w16,w25,ror#25 // Sigma1(e)
+ eor w10,w10,w21,ror#13
+ add w20,w20,w17 // h+=Ch(e,f,g)
+ and w19,w19,w28 // (b^c)&=(a^b)
+ eor w8,w8,w1,ror#19
+ eor w9,w9,w4,lsr#3 // sigma0(X[i+1])
+ add w20,w20,w16 // h+=Sigma1(e)
+ eor w19,w19,w22 // Maj(a,b,c)
+ eor w17,w10,w21,ror#22 // Sigma0(a)
+ eor w8,w8,w1,lsr#10 // sigma1(X[i+14])
+ add w3,w3,w12
+ add w24,w24,w20 // d+=h
+ add w20,w20,w19 // h+=Maj(a,b,c)
+ ldr w19,[x30],#4 // *K++, w28 in next round
+ add w3,w3,w9
+ add w20,w20,w17 // h+=Sigma0(a)
+ add w3,w3,w8
+ cbnz w19,.Loop_16_xx
+
+ ldp x0,x2,[x29,#96]
+ ldr x1,[x29,#112]
+ sub x30,x30,#260 // rewind
+
+ ldp w3,w4,[x0]
+ ldp w5,w6,[x0,#2*4]
+ add x1,x1,#14*4 // advance input pointer
+ ldp w7,w8,[x0,#4*4]
+ add w20,w20,w3
+ ldp w9,w10,[x0,#6*4]
+ add w21,w21,w4
+ add w22,w22,w5
+ add w23,w23,w6
+ stp w20,w21,[x0]
+ add w24,w24,w7
+ add w25,w25,w8
+ stp w22,w23,[x0,#2*4]
+ add w26,w26,w9
+ add w27,w27,w10
+ cmp x1,x2
+ stp w24,w25,[x0,#4*4]
+ stp w26,w27,[x0,#6*4]
+ b.ne .Loop
+
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#4*4
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#128
+ ret
+.size sha256_block_data_order,.-sha256_block_data_order
+
+.align 6
+.type .LK256,%object
+.LK256:
+ .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
+ .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
+ .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
+ .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
+ .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
+ .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
+ .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
+ .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
+ .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
+ .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
+ .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
+ .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
+ .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
+ .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
+ .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
+ .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
+ .long 0 //terminator
+.size .LK256,.-.LK256
+#ifndef __KERNEL__
+.align 3
+.LOPENSSL_armcap_P:
+# ifdef __ILP32__
+ .long OPENSSL_armcap_P-.
+# else
+ .quad OPENSSL_armcap_P-.
+# endif
+#endif
+.asciz "SHA256 block transform for ARMv8, CRYPTOGAMS by <appro@openssl.org>"
+.align 2
+#ifndef __KERNEL__
+.type sha256_block_armv8,%function
+.align 6
+sha256_block_armv8:
+.Lv8_entry:
+ stp x29,x30,[sp,#-16]!
+ add x29,sp,#0
+
+ ld1 {v0.4s,v1.4s},[x0]
+ adr x3,.LK256
+
+.Loop_hw:
+ ld1 {v4.16b-v7.16b},[x1],#64
+ sub x2,x2,#1
+ ld1 {v16.4s},[x3],#16
+ rev32 v4.16b,v4.16b
+ rev32 v5.16b,v5.16b
+ rev32 v6.16b,v6.16b
+ rev32 v7.16b,v7.16b
+ orr v18.16b,v0.16b,v0.16b // offload
+ orr v19.16b,v1.16b,v1.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v4.4s
+ .inst 0x5e2828a4 //sha256su0 v4.16b,v5.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+ .inst 0x5e0760c4 //sha256su1 v4.16b,v6.16b,v7.16b
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v5.4s
+ .inst 0x5e2828c5 //sha256su0 v5.16b,v6.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+ .inst 0x5e0460e5 //sha256su1 v5.16b,v7.16b,v4.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v6.4s
+ .inst 0x5e2828e6 //sha256su0 v6.16b,v7.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+ .inst 0x5e056086 //sha256su1 v6.16b,v4.16b,v5.16b
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v7.4s
+ .inst 0x5e282887 //sha256su0 v7.16b,v4.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+ .inst 0x5e0660a7 //sha256su1 v7.16b,v5.16b,v6.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v4.4s
+ .inst 0x5e2828a4 //sha256su0 v4.16b,v5.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+ .inst 0x5e0760c4 //sha256su1 v4.16b,v6.16b,v7.16b
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v5.4s
+ .inst 0x5e2828c5 //sha256su0 v5.16b,v6.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+ .inst 0x5e0460e5 //sha256su1 v5.16b,v7.16b,v4.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v6.4s
+ .inst 0x5e2828e6 //sha256su0 v6.16b,v7.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+ .inst 0x5e056086 //sha256su1 v6.16b,v4.16b,v5.16b
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v7.4s
+ .inst 0x5e282887 //sha256su0 v7.16b,v4.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+ .inst 0x5e0660a7 //sha256su1 v7.16b,v5.16b,v6.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v4.4s
+ .inst 0x5e2828a4 //sha256su0 v4.16b,v5.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+ .inst 0x5e0760c4 //sha256su1 v4.16b,v6.16b,v7.16b
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v5.4s
+ .inst 0x5e2828c5 //sha256su0 v5.16b,v6.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+ .inst 0x5e0460e5 //sha256su1 v5.16b,v7.16b,v4.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v6.4s
+ .inst 0x5e2828e6 //sha256su0 v6.16b,v7.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+ .inst 0x5e056086 //sha256su1 v6.16b,v4.16b,v5.16b
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v7.4s
+ .inst 0x5e282887 //sha256su0 v7.16b,v4.16b
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+ .inst 0x5e0660a7 //sha256su1 v7.16b,v5.16b,v6.16b
+ ld1 {v17.4s},[x3],#16
+ add v16.4s,v16.4s,v4.4s
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+
+ ld1 {v16.4s},[x3],#16
+ add v17.4s,v17.4s,v5.4s
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+
+ ld1 {v17.4s},[x3]
+ add v16.4s,v16.4s,v6.4s
+ sub x3,x3,#64*4-16 // rewind
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s
+ .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s
+
+ add v17.4s,v17.4s,v7.4s
+ orr v2.16b,v0.16b,v0.16b
+ .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s
+ .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s
+
+ add v0.4s,v0.4s,v18.4s
+ add v1.4s,v1.4s,v19.4s
+
+ cbnz x2,.Loop_hw
+
+ st1 {v0.4s,v1.4s},[x0]
+
+ ldr x29,[sp],#16
+ ret
+.size sha256_block_armv8,.-sha256_block_armv8
+#endif
+#ifdef __KERNEL__
+.globl sha256_block_neon
+#endif
+.type sha256_block_neon,%function
+.align 4
+sha256_block_neon:
+.Lneon_entry:
+ stp x29, x30, [sp, #-16]!
+ mov x29, sp
+ sub sp,sp,#16*4
+
+ adr x16,.LK256
+ add x2,x1,x2,lsl#6 // len to point at the end of inp
+
+ ld1 {v0.16b},[x1], #16
+ ld1 {v1.16b},[x1], #16
+ ld1 {v2.16b},[x1], #16
+ ld1 {v3.16b},[x1], #16
+ ld1 {v4.4s},[x16], #16
+ ld1 {v5.4s},[x16], #16
+ ld1 {v6.4s},[x16], #16
+ ld1 {v7.4s},[x16], #16
+ rev32 v0.16b,v0.16b // yes, even on
+ rev32 v1.16b,v1.16b // big-endian
+ rev32 v2.16b,v2.16b
+ rev32 v3.16b,v3.16b
+ mov x17,sp
+ add v4.4s,v4.4s,v0.4s
+ add v5.4s,v5.4s,v1.4s
+ add v6.4s,v6.4s,v2.4s
+ st1 {v4.4s-v5.4s},[x17], #32
+ add v7.4s,v7.4s,v3.4s
+ st1 {v6.4s-v7.4s},[x17]
+ sub x17,x17,#32
+
+ ldp w3,w4,[x0]
+ ldp w5,w6,[x0,#8]
+ ldp w7,w8,[x0,#16]
+ ldp w9,w10,[x0,#24]
+ ldr w12,[sp,#0]
+ mov w13,wzr
+ eor w14,w4,w5
+ mov w15,wzr
+ b .L_00_48
+
+.align 4
+.L_00_48:
+ ext v4.16b,v0.16b,v1.16b,#4
+ add w10,w10,w12
+ add w3,w3,w15
+ and w12,w8,w7
+ bic w15,w9,w7
+ ext v7.16b,v2.16b,v3.16b,#4
+ eor w11,w7,w7,ror#5
+ add w3,w3,w13
+ mov d19,v3.d[1]
+ orr w12,w12,w15
+ eor w11,w11,w7,ror#19
+ ushr v6.4s,v4.4s,#7
+ eor w15,w3,w3,ror#11
+ ushr v5.4s,v4.4s,#3
+ add w10,w10,w12
+ add v0.4s,v0.4s,v7.4s
+ ror w11,w11,#6
+ sli v6.4s,v4.4s,#25
+ eor w13,w3,w4
+ eor w15,w15,w3,ror#20
+ ushr v7.4s,v4.4s,#18
+ add w10,w10,w11
+ ldr w12,[sp,#4]
+ and w14,w14,w13
+ eor v5.16b,v5.16b,v6.16b
+ ror w15,w15,#2
+ add w6,w6,w10
+ sli v7.4s,v4.4s,#14
+ eor w14,w14,w4
+ ushr v16.4s,v19.4s,#17
+ add w9,w9,w12
+ add w10,w10,w15
+ and w12,w7,w6
+ eor v5.16b,v5.16b,v7.16b
+ bic w15,w8,w6
+ eor w11,w6,w6,ror#5
+ sli v16.4s,v19.4s,#15
+ add w10,w10,w14
+ orr w12,w12,w15
+ ushr v17.4s,v19.4s,#10
+ eor w11,w11,w6,ror#19
+ eor w15,w10,w10,ror#11
+ ushr v7.4s,v19.4s,#19
+ add w9,w9,w12
+ ror w11,w11,#6
+ add v0.4s,v0.4s,v5.4s
+ eor w14,w10,w3
+ eor w15,w15,w10,ror#20
+ sli v7.4s,v19.4s,#13
+ add w9,w9,w11
+ ldr w12,[sp,#8]
+ and w13,w13,w14
+ eor v17.16b,v17.16b,v16.16b
+ ror w15,w15,#2
+ add w5,w5,w9
+ eor w13,w13,w3
+ eor v17.16b,v17.16b,v7.16b
+ add w8,w8,w12
+ add w9,w9,w15
+ and w12,w6,w5
+ add v0.4s,v0.4s,v17.4s
+ bic w15,w7,w5
+ eor w11,w5,w5,ror#5
+ add w9,w9,w13
+ ushr v18.4s,v0.4s,#17
+ orr w12,w12,w15
+ ushr v19.4s,v0.4s,#10
+ eor w11,w11,w5,ror#19
+ eor w15,w9,w9,ror#11
+ sli v18.4s,v0.4s,#15
+ add w8,w8,w12
+ ushr v17.4s,v0.4s,#19
+ ror w11,w11,#6
+ eor w13,w9,w10
+ eor v19.16b,v19.16b,v18.16b
+ eor w15,w15,w9,ror#20
+ add w8,w8,w11
+ sli v17.4s,v0.4s,#13
+ ldr w12,[sp,#12]
+ and w14,w14,w13
+ ror w15,w15,#2
+ ld1 {v4.4s},[x16], #16
+ add w4,w4,w8
+ eor v19.16b,v19.16b,v17.16b
+ eor w14,w14,w10
+ eor v17.16b,v17.16b,v17.16b
+ add w7,w7,w12
+ add w8,w8,w15
+ and w12,w5,w4
+ mov v17.d[1],v19.d[0]
+ bic w15,w6,w4
+ eor w11,w4,w4,ror#5
+ add w8,w8,w14
+ add v0.4s,v0.4s,v17.4s
+ orr w12,w12,w15
+ eor w11,w11,w4,ror#19
+ eor w15,w8,w8,ror#11
+ add v4.4s,v4.4s,v0.4s
+ add w7,w7,w12
+ ror w11,w11,#6
+ eor w14,w8,w9
+ eor w15,w15,w8,ror#20
+ add w7,w7,w11
+ ldr w12,[sp,#16]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w3,w3,w7
+ eor w13,w13,w9
+ st1 {v4.4s},[x17], #16
+ ext v4.16b,v1.16b,v2.16b,#4
+ add w6,w6,w12
+ add w7,w7,w15
+ and w12,w4,w3
+ bic w15,w5,w3
+ ext v7.16b,v3.16b,v0.16b,#4
+ eor w11,w3,w3,ror#5
+ add w7,w7,w13
+ mov d19,v0.d[1]
+ orr w12,w12,w15
+ eor w11,w11,w3,ror#19
+ ushr v6.4s,v4.4s,#7
+ eor w15,w7,w7,ror#11
+ ushr v5.4s,v4.4s,#3
+ add w6,w6,w12
+ add v1.4s,v1.4s,v7.4s
+ ror w11,w11,#6
+ sli v6.4s,v4.4s,#25
+ eor w13,w7,w8
+ eor w15,w15,w7,ror#20
+ ushr v7.4s,v4.4s,#18
+ add w6,w6,w11
+ ldr w12,[sp,#20]
+ and w14,w14,w13
+ eor v5.16b,v5.16b,v6.16b
+ ror w15,w15,#2
+ add w10,w10,w6
+ sli v7.4s,v4.4s,#14
+ eor w14,w14,w8
+ ushr v16.4s,v19.4s,#17
+ add w5,w5,w12
+ add w6,w6,w15
+ and w12,w3,w10
+ eor v5.16b,v5.16b,v7.16b
+ bic w15,w4,w10
+ eor w11,w10,w10,ror#5
+ sli v16.4s,v19.4s,#15
+ add w6,w6,w14
+ orr w12,w12,w15
+ ushr v17.4s,v19.4s,#10
+ eor w11,w11,w10,ror#19
+ eor w15,w6,w6,ror#11
+ ushr v7.4s,v19.4s,#19
+ add w5,w5,w12
+ ror w11,w11,#6
+ add v1.4s,v1.4s,v5.4s
+ eor w14,w6,w7
+ eor w15,w15,w6,ror#20
+ sli v7.4s,v19.4s,#13
+ add w5,w5,w11
+ ldr w12,[sp,#24]
+ and w13,w13,w14
+ eor v17.16b,v17.16b,v16.16b
+ ror w15,w15,#2
+ add w9,w9,w5
+ eor w13,w13,w7
+ eor v17.16b,v17.16b,v7.16b
+ add w4,w4,w12
+ add w5,w5,w15
+ and w12,w10,w9
+ add v1.4s,v1.4s,v17.4s
+ bic w15,w3,w9
+ eor w11,w9,w9,ror#5
+ add w5,w5,w13
+ ushr v18.4s,v1.4s,#17
+ orr w12,w12,w15
+ ushr v19.4s,v1.4s,#10
+ eor w11,w11,w9,ror#19
+ eor w15,w5,w5,ror#11
+ sli v18.4s,v1.4s,#15
+ add w4,w4,w12
+ ushr v17.4s,v1.4s,#19
+ ror w11,w11,#6
+ eor w13,w5,w6
+ eor v19.16b,v19.16b,v18.16b
+ eor w15,w15,w5,ror#20
+ add w4,w4,w11
+ sli v17.4s,v1.4s,#13
+ ldr w12,[sp,#28]
+ and w14,w14,w13
+ ror w15,w15,#2
+ ld1 {v4.4s},[x16], #16
+ add w8,w8,w4
+ eor v19.16b,v19.16b,v17.16b
+ eor w14,w14,w6
+ eor v17.16b,v17.16b,v17.16b
+ add w3,w3,w12
+ add w4,w4,w15
+ and w12,w9,w8
+ mov v17.d[1],v19.d[0]
+ bic w15,w10,w8
+ eor w11,w8,w8,ror#5
+ add w4,w4,w14
+ add v1.4s,v1.4s,v17.4s
+ orr w12,w12,w15
+ eor w11,w11,w8,ror#19
+ eor w15,w4,w4,ror#11
+ add v4.4s,v4.4s,v1.4s
+ add w3,w3,w12
+ ror w11,w11,#6
+ eor w14,w4,w5
+ eor w15,w15,w4,ror#20
+ add w3,w3,w11
+ ldr w12,[sp,#32]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w7,w7,w3
+ eor w13,w13,w5
+ st1 {v4.4s},[x17], #16
+ ext v4.16b,v2.16b,v3.16b,#4
+ add w10,w10,w12
+ add w3,w3,w15
+ and w12,w8,w7
+ bic w15,w9,w7
+ ext v7.16b,v0.16b,v1.16b,#4
+ eor w11,w7,w7,ror#5
+ add w3,w3,w13
+ mov d19,v1.d[1]
+ orr w12,w12,w15
+ eor w11,w11,w7,ror#19
+ ushr v6.4s,v4.4s,#7
+ eor w15,w3,w3,ror#11
+ ushr v5.4s,v4.4s,#3
+ add w10,w10,w12
+ add v2.4s,v2.4s,v7.4s
+ ror w11,w11,#6
+ sli v6.4s,v4.4s,#25
+ eor w13,w3,w4
+ eor w15,w15,w3,ror#20
+ ushr v7.4s,v4.4s,#18
+ add w10,w10,w11
+ ldr w12,[sp,#36]
+ and w14,w14,w13
+ eor v5.16b,v5.16b,v6.16b
+ ror w15,w15,#2
+ add w6,w6,w10
+ sli v7.4s,v4.4s,#14
+ eor w14,w14,w4
+ ushr v16.4s,v19.4s,#17
+ add w9,w9,w12
+ add w10,w10,w15
+ and w12,w7,w6
+ eor v5.16b,v5.16b,v7.16b
+ bic w15,w8,w6
+ eor w11,w6,w6,ror#5
+ sli v16.4s,v19.4s,#15
+ add w10,w10,w14
+ orr w12,w12,w15
+ ushr v17.4s,v19.4s,#10
+ eor w11,w11,w6,ror#19
+ eor w15,w10,w10,ror#11
+ ushr v7.4s,v19.4s,#19
+ add w9,w9,w12
+ ror w11,w11,#6
+ add v2.4s,v2.4s,v5.4s
+ eor w14,w10,w3
+ eor w15,w15,w10,ror#20
+ sli v7.4s,v19.4s,#13
+ add w9,w9,w11
+ ldr w12,[sp,#40]
+ and w13,w13,w14
+ eor v17.16b,v17.16b,v16.16b
+ ror w15,w15,#2
+ add w5,w5,w9
+ eor w13,w13,w3
+ eor v17.16b,v17.16b,v7.16b
+ add w8,w8,w12
+ add w9,w9,w15
+ and w12,w6,w5
+ add v2.4s,v2.4s,v17.4s
+ bic w15,w7,w5
+ eor w11,w5,w5,ror#5
+ add w9,w9,w13
+ ushr v18.4s,v2.4s,#17
+ orr w12,w12,w15
+ ushr v19.4s,v2.4s,#10
+ eor w11,w11,w5,ror#19
+ eor w15,w9,w9,ror#11
+ sli v18.4s,v2.4s,#15
+ add w8,w8,w12
+ ushr v17.4s,v2.4s,#19
+ ror w11,w11,#6
+ eor w13,w9,w10
+ eor v19.16b,v19.16b,v18.16b
+ eor w15,w15,w9,ror#20
+ add w8,w8,w11
+ sli v17.4s,v2.4s,#13
+ ldr w12,[sp,#44]
+ and w14,w14,w13
+ ror w15,w15,#2
+ ld1 {v4.4s},[x16], #16
+ add w4,w4,w8
+ eor v19.16b,v19.16b,v17.16b
+ eor w14,w14,w10
+ eor v17.16b,v17.16b,v17.16b
+ add w7,w7,w12
+ add w8,w8,w15
+ and w12,w5,w4
+ mov v17.d[1],v19.d[0]
+ bic w15,w6,w4
+ eor w11,w4,w4,ror#5
+ add w8,w8,w14
+ add v2.4s,v2.4s,v17.4s
+ orr w12,w12,w15
+ eor w11,w11,w4,ror#19
+ eor w15,w8,w8,ror#11
+ add v4.4s,v4.4s,v2.4s
+ add w7,w7,w12
+ ror w11,w11,#6
+ eor w14,w8,w9
+ eor w15,w15,w8,ror#20
+ add w7,w7,w11
+ ldr w12,[sp,#48]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w3,w3,w7
+ eor w13,w13,w9
+ st1 {v4.4s},[x17], #16
+ ext v4.16b,v3.16b,v0.16b,#4
+ add w6,w6,w12
+ add w7,w7,w15
+ and w12,w4,w3
+ bic w15,w5,w3
+ ext v7.16b,v1.16b,v2.16b,#4
+ eor w11,w3,w3,ror#5
+ add w7,w7,w13
+ mov d19,v2.d[1]
+ orr w12,w12,w15
+ eor w11,w11,w3,ror#19
+ ushr v6.4s,v4.4s,#7
+ eor w15,w7,w7,ror#11
+ ushr v5.4s,v4.4s,#3
+ add w6,w6,w12
+ add v3.4s,v3.4s,v7.4s
+ ror w11,w11,#6
+ sli v6.4s,v4.4s,#25
+ eor w13,w7,w8
+ eor w15,w15,w7,ror#20
+ ushr v7.4s,v4.4s,#18
+ add w6,w6,w11
+ ldr w12,[sp,#52]
+ and w14,w14,w13
+ eor v5.16b,v5.16b,v6.16b
+ ror w15,w15,#2
+ add w10,w10,w6
+ sli v7.4s,v4.4s,#14
+ eor w14,w14,w8
+ ushr v16.4s,v19.4s,#17
+ add w5,w5,w12
+ add w6,w6,w15
+ and w12,w3,w10
+ eor v5.16b,v5.16b,v7.16b
+ bic w15,w4,w10
+ eor w11,w10,w10,ror#5
+ sli v16.4s,v19.4s,#15
+ add w6,w6,w14
+ orr w12,w12,w15
+ ushr v17.4s,v19.4s,#10
+ eor w11,w11,w10,ror#19
+ eor w15,w6,w6,ror#11
+ ushr v7.4s,v19.4s,#19
+ add w5,w5,w12
+ ror w11,w11,#6
+ add v3.4s,v3.4s,v5.4s
+ eor w14,w6,w7
+ eor w15,w15,w6,ror#20
+ sli v7.4s,v19.4s,#13
+ add w5,w5,w11
+ ldr w12,[sp,#56]
+ and w13,w13,w14
+ eor v17.16b,v17.16b,v16.16b
+ ror w15,w15,#2
+ add w9,w9,w5
+ eor w13,w13,w7
+ eor v17.16b,v17.16b,v7.16b
+ add w4,w4,w12
+ add w5,w5,w15
+ and w12,w10,w9
+ add v3.4s,v3.4s,v17.4s
+ bic w15,w3,w9
+ eor w11,w9,w9,ror#5
+ add w5,w5,w13
+ ushr v18.4s,v3.4s,#17
+ orr w12,w12,w15
+ ushr v19.4s,v3.4s,#10
+ eor w11,w11,w9,ror#19
+ eor w15,w5,w5,ror#11
+ sli v18.4s,v3.4s,#15
+ add w4,w4,w12
+ ushr v17.4s,v3.4s,#19
+ ror w11,w11,#6
+ eor w13,w5,w6
+ eor v19.16b,v19.16b,v18.16b
+ eor w15,w15,w5,ror#20
+ add w4,w4,w11
+ sli v17.4s,v3.4s,#13
+ ldr w12,[sp,#60]
+ and w14,w14,w13
+ ror w15,w15,#2
+ ld1 {v4.4s},[x16], #16
+ add w8,w8,w4
+ eor v19.16b,v19.16b,v17.16b
+ eor w14,w14,w6
+ eor v17.16b,v17.16b,v17.16b
+ add w3,w3,w12
+ add w4,w4,w15
+ and w12,w9,w8
+ mov v17.d[1],v19.d[0]
+ bic w15,w10,w8
+ eor w11,w8,w8,ror#5
+ add w4,w4,w14
+ add v3.4s,v3.4s,v17.4s
+ orr w12,w12,w15
+ eor w11,w11,w8,ror#19
+ eor w15,w4,w4,ror#11
+ add v4.4s,v4.4s,v3.4s
+ add w3,w3,w12
+ ror w11,w11,#6
+ eor w14,w4,w5
+ eor w15,w15,w4,ror#20
+ add w3,w3,w11
+ ldr w12,[x16]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w7,w7,w3
+ eor w13,w13,w5
+ st1 {v4.4s},[x17], #16
+ cmp w12,#0 // check for K256 terminator
+ ldr w12,[sp,#0]
+ sub x17,x17,#64
+ bne .L_00_48
+
+ sub x16,x16,#256 // rewind x16
+ cmp x1,x2
+ mov x17, #64
+ csel x17, x17, xzr, eq
+ sub x1,x1,x17 // avoid SEGV
+ mov x17,sp
+ add w10,w10,w12
+ add w3,w3,w15
+ and w12,w8,w7
+ ld1 {v0.16b},[x1],#16
+ bic w15,w9,w7
+ eor w11,w7,w7,ror#5
+ ld1 {v4.4s},[x16],#16
+ add w3,w3,w13
+ orr w12,w12,w15
+ eor w11,w11,w7,ror#19
+ eor w15,w3,w3,ror#11
+ rev32 v0.16b,v0.16b
+ add w10,w10,w12
+ ror w11,w11,#6
+ eor w13,w3,w4
+ eor w15,w15,w3,ror#20
+ add v4.4s,v4.4s,v0.4s
+ add w10,w10,w11
+ ldr w12,[sp,#4]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w6,w6,w10
+ eor w14,w14,w4
+ add w9,w9,w12
+ add w10,w10,w15
+ and w12,w7,w6
+ bic w15,w8,w6
+ eor w11,w6,w6,ror#5
+ add w10,w10,w14
+ orr w12,w12,w15
+ eor w11,w11,w6,ror#19
+ eor w15,w10,w10,ror#11
+ add w9,w9,w12
+ ror w11,w11,#6
+ eor w14,w10,w3
+ eor w15,w15,w10,ror#20
+ add w9,w9,w11
+ ldr w12,[sp,#8]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w5,w5,w9
+ eor w13,w13,w3
+ add w8,w8,w12
+ add w9,w9,w15
+ and w12,w6,w5
+ bic w15,w7,w5
+ eor w11,w5,w5,ror#5
+ add w9,w9,w13
+ orr w12,w12,w15
+ eor w11,w11,w5,ror#19
+ eor w15,w9,w9,ror#11
+ add w8,w8,w12
+ ror w11,w11,#6
+ eor w13,w9,w10
+ eor w15,w15,w9,ror#20
+ add w8,w8,w11
+ ldr w12,[sp,#12]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w4,w4,w8
+ eor w14,w14,w10
+ add w7,w7,w12
+ add w8,w8,w15
+ and w12,w5,w4
+ bic w15,w6,w4
+ eor w11,w4,w4,ror#5
+ add w8,w8,w14
+ orr w12,w12,w15
+ eor w11,w11,w4,ror#19
+ eor w15,w8,w8,ror#11
+ add w7,w7,w12
+ ror w11,w11,#6
+ eor w14,w8,w9
+ eor w15,w15,w8,ror#20
+ add w7,w7,w11
+ ldr w12,[sp,#16]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w3,w3,w7
+ eor w13,w13,w9
+ st1 {v4.4s},[x17], #16
+ add w6,w6,w12
+ add w7,w7,w15
+ and w12,w4,w3
+ ld1 {v1.16b},[x1],#16
+ bic w15,w5,w3
+ eor w11,w3,w3,ror#5
+ ld1 {v4.4s},[x16],#16
+ add w7,w7,w13
+ orr w12,w12,w15
+ eor w11,w11,w3,ror#19
+ eor w15,w7,w7,ror#11
+ rev32 v1.16b,v1.16b
+ add w6,w6,w12
+ ror w11,w11,#6
+ eor w13,w7,w8
+ eor w15,w15,w7,ror#20
+ add v4.4s,v4.4s,v1.4s
+ add w6,w6,w11
+ ldr w12,[sp,#20]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w10,w10,w6
+ eor w14,w14,w8
+ add w5,w5,w12
+ add w6,w6,w15
+ and w12,w3,w10
+ bic w15,w4,w10
+ eor w11,w10,w10,ror#5
+ add w6,w6,w14
+ orr w12,w12,w15
+ eor w11,w11,w10,ror#19
+ eor w15,w6,w6,ror#11
+ add w5,w5,w12
+ ror w11,w11,#6
+ eor w14,w6,w7
+ eor w15,w15,w6,ror#20
+ add w5,w5,w11
+ ldr w12,[sp,#24]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w9,w9,w5
+ eor w13,w13,w7
+ add w4,w4,w12
+ add w5,w5,w15
+ and w12,w10,w9
+ bic w15,w3,w9
+ eor w11,w9,w9,ror#5
+ add w5,w5,w13
+ orr w12,w12,w15
+ eor w11,w11,w9,ror#19
+ eor w15,w5,w5,ror#11
+ add w4,w4,w12
+ ror w11,w11,#6
+ eor w13,w5,w6
+ eor w15,w15,w5,ror#20
+ add w4,w4,w11
+ ldr w12,[sp,#28]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w8,w8,w4
+ eor w14,w14,w6
+ add w3,w3,w12
+ add w4,w4,w15
+ and w12,w9,w8
+ bic w15,w10,w8
+ eor w11,w8,w8,ror#5
+ add w4,w4,w14
+ orr w12,w12,w15
+ eor w11,w11,w8,ror#19
+ eor w15,w4,w4,ror#11
+ add w3,w3,w12
+ ror w11,w11,#6
+ eor w14,w4,w5
+ eor w15,w15,w4,ror#20
+ add w3,w3,w11
+ ldr w12,[sp,#32]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w7,w7,w3
+ eor w13,w13,w5
+ st1 {v4.4s},[x17], #16
+ add w10,w10,w12
+ add w3,w3,w15
+ and w12,w8,w7
+ ld1 {v2.16b},[x1],#16
+ bic w15,w9,w7
+ eor w11,w7,w7,ror#5
+ ld1 {v4.4s},[x16],#16
+ add w3,w3,w13
+ orr w12,w12,w15
+ eor w11,w11,w7,ror#19
+ eor w15,w3,w3,ror#11
+ rev32 v2.16b,v2.16b
+ add w10,w10,w12
+ ror w11,w11,#6
+ eor w13,w3,w4
+ eor w15,w15,w3,ror#20
+ add v4.4s,v4.4s,v2.4s
+ add w10,w10,w11
+ ldr w12,[sp,#36]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w6,w6,w10
+ eor w14,w14,w4
+ add w9,w9,w12
+ add w10,w10,w15
+ and w12,w7,w6
+ bic w15,w8,w6
+ eor w11,w6,w6,ror#5
+ add w10,w10,w14
+ orr w12,w12,w15
+ eor w11,w11,w6,ror#19
+ eor w15,w10,w10,ror#11
+ add w9,w9,w12
+ ror w11,w11,#6
+ eor w14,w10,w3
+ eor w15,w15,w10,ror#20
+ add w9,w9,w11
+ ldr w12,[sp,#40]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w5,w5,w9
+ eor w13,w13,w3
+ add w8,w8,w12
+ add w9,w9,w15
+ and w12,w6,w5
+ bic w15,w7,w5
+ eor w11,w5,w5,ror#5
+ add w9,w9,w13
+ orr w12,w12,w15
+ eor w11,w11,w5,ror#19
+ eor w15,w9,w9,ror#11
+ add w8,w8,w12
+ ror w11,w11,#6
+ eor w13,w9,w10
+ eor w15,w15,w9,ror#20
+ add w8,w8,w11
+ ldr w12,[sp,#44]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w4,w4,w8
+ eor w14,w14,w10
+ add w7,w7,w12
+ add w8,w8,w15
+ and w12,w5,w4
+ bic w15,w6,w4
+ eor w11,w4,w4,ror#5
+ add w8,w8,w14
+ orr w12,w12,w15
+ eor w11,w11,w4,ror#19
+ eor w15,w8,w8,ror#11
+ add w7,w7,w12
+ ror w11,w11,#6
+ eor w14,w8,w9
+ eor w15,w15,w8,ror#20
+ add w7,w7,w11
+ ldr w12,[sp,#48]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w3,w3,w7
+ eor w13,w13,w9
+ st1 {v4.4s},[x17], #16
+ add w6,w6,w12
+ add w7,w7,w15
+ and w12,w4,w3
+ ld1 {v3.16b},[x1],#16
+ bic w15,w5,w3
+ eor w11,w3,w3,ror#5
+ ld1 {v4.4s},[x16],#16
+ add w7,w7,w13
+ orr w12,w12,w15
+ eor w11,w11,w3,ror#19
+ eor w15,w7,w7,ror#11
+ rev32 v3.16b,v3.16b
+ add w6,w6,w12
+ ror w11,w11,#6
+ eor w13,w7,w8
+ eor w15,w15,w7,ror#20
+ add v4.4s,v4.4s,v3.4s
+ add w6,w6,w11
+ ldr w12,[sp,#52]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w10,w10,w6
+ eor w14,w14,w8
+ add w5,w5,w12
+ add w6,w6,w15
+ and w12,w3,w10
+ bic w15,w4,w10
+ eor w11,w10,w10,ror#5
+ add w6,w6,w14
+ orr w12,w12,w15
+ eor w11,w11,w10,ror#19
+ eor w15,w6,w6,ror#11
+ add w5,w5,w12
+ ror w11,w11,#6
+ eor w14,w6,w7
+ eor w15,w15,w6,ror#20
+ add w5,w5,w11
+ ldr w12,[sp,#56]
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w9,w9,w5
+ eor w13,w13,w7
+ add w4,w4,w12
+ add w5,w5,w15
+ and w12,w10,w9
+ bic w15,w3,w9
+ eor w11,w9,w9,ror#5
+ add w5,w5,w13
+ orr w12,w12,w15
+ eor w11,w11,w9,ror#19
+ eor w15,w5,w5,ror#11
+ add w4,w4,w12
+ ror w11,w11,#6
+ eor w13,w5,w6
+ eor w15,w15,w5,ror#20
+ add w4,w4,w11
+ ldr w12,[sp,#60]
+ and w14,w14,w13
+ ror w15,w15,#2
+ add w8,w8,w4
+ eor w14,w14,w6
+ add w3,w3,w12
+ add w4,w4,w15
+ and w12,w9,w8
+ bic w15,w10,w8
+ eor w11,w8,w8,ror#5
+ add w4,w4,w14
+ orr w12,w12,w15
+ eor w11,w11,w8,ror#19
+ eor w15,w4,w4,ror#11
+ add w3,w3,w12
+ ror w11,w11,#6
+ eor w14,w4,w5
+ eor w15,w15,w4,ror#20
+ add w3,w3,w11
+ and w13,w13,w14
+ ror w15,w15,#2
+ add w7,w7,w3
+ eor w13,w13,w5
+ st1 {v4.4s},[x17], #16
+ add w3,w3,w15 // h+=Sigma0(a) from the past
+ ldp w11,w12,[x0,#0]
+ add w3,w3,w13 // h+=Maj(a,b,c) from the past
+ ldp w13,w14,[x0,#8]
+ add w3,w3,w11 // accumulate
+ add w4,w4,w12
+ ldp w11,w12,[x0,#16]
+ add w5,w5,w13
+ add w6,w6,w14
+ ldp w13,w14,[x0,#24]
+ add w7,w7,w11
+ add w8,w8,w12
+ ldr w12,[sp,#0]
+ stp w3,w4,[x0,#0]
+ add w9,w9,w13
+ mov w13,wzr
+ stp w5,w6,[x0,#8]
+ add w10,w10,w14
+ stp w7,w8,[x0,#16]
+ eor w14,w4,w5
+ stp w9,w10,[x0,#24]
+ mov w15,wzr
+ mov x17,sp
+ b.ne .L_00_48
+
+ ldr x29,[x29]
+ add sp,sp,#16*4+16
+ ret
+.size sha256_block_neon,.-sha256_block_neon
+#ifndef __KERNEL__
+.comm OPENSSL_armcap_P,4,4
+#endif
diff --git a/arch/arm64/crypto/sha512-core.S b/arch/arm64/crypto/sha512-core.S
new file mode 100644
index 0000000..bd0f59f
--- /dev/null
+++ b/arch/arm64/crypto/sha512-core.S
@@ -0,0 +1,1085 @@
+// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved.
+//
+// Licensed under the OpenSSL license (the "License"). You may not use
+// this file except in compliance with the License. You can obtain a copy
+// in the file LICENSE in the source distribution or at
+// https://www.openssl.org/source/license.html
+
+// ====================================================================
+// Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// project. The module is, however, dual licensed under OpenSSL and
+// CRYPTOGAMS licenses depending on where you obtain it. For further
+// details see http://www.openssl.org/~appro/cryptogams/.
+//
+// Permission to use under GPLv2 terms is granted.
+// ====================================================================
+//
+// SHA256/512 for ARMv8.
+//
+// Performance in cycles per processed byte and improvement coefficient
+// over code generated with "default" compiler:
+//
+// SHA256-hw SHA256(*) SHA512
+// Apple A7 1.97 10.5 (+33%) 6.73 (-1%(**))
+// Cortex-A53 2.38 15.5 (+115%) 10.0 (+150%(***))
+// Cortex-A57 2.31 11.6 (+86%) 7.51 (+260%(***))
+// Denver 2.01 10.5 (+26%) 6.70 (+8%)
+// X-Gene 20.0 (+100%) 12.8 (+300%(***))
+// Mongoose 2.36 13.0 (+50%) 8.36 (+33%)
+//
+// (*) Software SHA256 results are of lesser relevance, presented
+// mostly for informational purposes.
+// (**) The result is a trade-off: it's possible to improve it by
+// 10% (or by 1 cycle per round), but at the cost of 20% loss
+// on Cortex-A53 (or by 4 cycles per round).
+// (***) Super-impressive coefficients over gcc-generated code are
+// indication of some compiler "pathology", most notably code
+// generated with -mgeneral-regs-only is significanty faster
+// and the gap is only 40-90%.
+//
+// October 2016.
+//
+// Originally it was reckoned that it makes no sense to implement NEON
+// version of SHA256 for 64-bit processors. This is because performance
+// improvement on most wide-spread Cortex-A5x processors was observed
+// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was
+// observed that 32-bit NEON SHA256 performs significantly better than
+// 64-bit scalar version on *some* of the more recent processors. As
+// result 64-bit NEON version of SHA256 was added to provide best
+// all-round performance. For example it executes ~30% faster on X-Gene
+// and Mongoose. [For reference, NEON version of SHA512 is bound to
+// deliver much less improvement, likely *negative* on Cortex-A5x.
+// Which is why NEON support is limited to SHA256.]
+
+#ifndef __KERNEL__
+# include "arm_arch.h"
+#endif
+
+.text
+
+.extern OPENSSL_armcap_P
+.globl sha512_block_data_order
+.type sha512_block_data_order,%function
+.align 6
+sha512_block_data_order:
+ stp x29,x30,[sp,#-128]!
+ add x29,sp,#0
+
+ stp x19,x20,[sp,#16]
+ stp x21,x22,[sp,#32]
+ stp x23,x24,[sp,#48]
+ stp x25,x26,[sp,#64]
+ stp x27,x28,[sp,#80]
+ sub sp,sp,#4*8
+
+ ldp x20,x21,[x0] // load context
+ ldp x22,x23,[x0,#2*8]
+ ldp x24,x25,[x0,#4*8]
+ add x2,x1,x2,lsl#7 // end of input
+ ldp x26,x27,[x0,#6*8]
+ adr x30,.LK512
+ stp x0,x2,[x29,#96]
+
+.Loop:
+ ldp x3,x4,[x1],#2*8
+ ldr x19,[x30],#8 // *K++
+ eor x28,x21,x22 // magic seed
+ str x1,[x29,#112]
+#ifndef __AARCH64EB__
+ rev x3,x3 // 0
+#endif
+ ror x16,x24,#14
+ add x27,x27,x19 // h+=K[i]
+ eor x6,x24,x24,ror#23
+ and x17,x25,x24
+ bic x19,x26,x24
+ add x27,x27,x3 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x20,x21 // a^b, b^c in next round
+ eor x16,x16,x6,ror#18 // Sigma1(e)
+ ror x6,x20,#28
+ add x27,x27,x17 // h+=Ch(e,f,g)
+ eor x17,x20,x20,ror#5
+ add x27,x27,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x23,x23,x27 // d+=h
+ eor x28,x28,x21 // Maj(a,b,c)
+ eor x17,x6,x17,ror#34 // Sigma0(a)
+ add x27,x27,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x27,x27,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x4,x4 // 1
+#endif
+ ldp x5,x6,[x1],#2*8
+ add x27,x27,x17 // h+=Sigma0(a)
+ ror x16,x23,#14
+ add x26,x26,x28 // h+=K[i]
+ eor x7,x23,x23,ror#23
+ and x17,x24,x23
+ bic x28,x25,x23
+ add x26,x26,x4 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x27,x20 // a^b, b^c in next round
+ eor x16,x16,x7,ror#18 // Sigma1(e)
+ ror x7,x27,#28
+ add x26,x26,x17 // h+=Ch(e,f,g)
+ eor x17,x27,x27,ror#5
+ add x26,x26,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x22,x22,x26 // d+=h
+ eor x19,x19,x20 // Maj(a,b,c)
+ eor x17,x7,x17,ror#34 // Sigma0(a)
+ add x26,x26,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x26,x26,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x5,x5 // 2
+#endif
+ add x26,x26,x17 // h+=Sigma0(a)
+ ror x16,x22,#14
+ add x25,x25,x19 // h+=K[i]
+ eor x8,x22,x22,ror#23
+ and x17,x23,x22
+ bic x19,x24,x22
+ add x25,x25,x5 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x26,x27 // a^b, b^c in next round
+ eor x16,x16,x8,ror#18 // Sigma1(e)
+ ror x8,x26,#28
+ add x25,x25,x17 // h+=Ch(e,f,g)
+ eor x17,x26,x26,ror#5
+ add x25,x25,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x21,x21,x25 // d+=h
+ eor x28,x28,x27 // Maj(a,b,c)
+ eor x17,x8,x17,ror#34 // Sigma0(a)
+ add x25,x25,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x25,x25,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x6,x6 // 3
+#endif
+ ldp x7,x8,[x1],#2*8
+ add x25,x25,x17 // h+=Sigma0(a)
+ ror x16,x21,#14
+ add x24,x24,x28 // h+=K[i]
+ eor x9,x21,x21,ror#23
+ and x17,x22,x21
+ bic x28,x23,x21
+ add x24,x24,x6 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x25,x26 // a^b, b^c in next round
+ eor x16,x16,x9,ror#18 // Sigma1(e)
+ ror x9,x25,#28
+ add x24,x24,x17 // h+=Ch(e,f,g)
+ eor x17,x25,x25,ror#5
+ add x24,x24,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x20,x20,x24 // d+=h
+ eor x19,x19,x26 // Maj(a,b,c)
+ eor x17,x9,x17,ror#34 // Sigma0(a)
+ add x24,x24,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x24,x24,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x7,x7 // 4
+#endif
+ add x24,x24,x17 // h+=Sigma0(a)
+ ror x16,x20,#14
+ add x23,x23,x19 // h+=K[i]
+ eor x10,x20,x20,ror#23
+ and x17,x21,x20
+ bic x19,x22,x20
+ add x23,x23,x7 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x24,x25 // a^b, b^c in next round
+ eor x16,x16,x10,ror#18 // Sigma1(e)
+ ror x10,x24,#28
+ add x23,x23,x17 // h+=Ch(e,f,g)
+ eor x17,x24,x24,ror#5
+ add x23,x23,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x27,x27,x23 // d+=h
+ eor x28,x28,x25 // Maj(a,b,c)
+ eor x17,x10,x17,ror#34 // Sigma0(a)
+ add x23,x23,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x23,x23,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x8,x8 // 5
+#endif
+ ldp x9,x10,[x1],#2*8
+ add x23,x23,x17 // h+=Sigma0(a)
+ ror x16,x27,#14
+ add x22,x22,x28 // h+=K[i]
+ eor x11,x27,x27,ror#23
+ and x17,x20,x27
+ bic x28,x21,x27
+ add x22,x22,x8 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x23,x24 // a^b, b^c in next round
+ eor x16,x16,x11,ror#18 // Sigma1(e)
+ ror x11,x23,#28
+ add x22,x22,x17 // h+=Ch(e,f,g)
+ eor x17,x23,x23,ror#5
+ add x22,x22,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x26,x26,x22 // d+=h
+ eor x19,x19,x24 // Maj(a,b,c)
+ eor x17,x11,x17,ror#34 // Sigma0(a)
+ add x22,x22,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x22,x22,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x9,x9 // 6
+#endif
+ add x22,x22,x17 // h+=Sigma0(a)
+ ror x16,x26,#14
+ add x21,x21,x19 // h+=K[i]
+ eor x12,x26,x26,ror#23
+ and x17,x27,x26
+ bic x19,x20,x26
+ add x21,x21,x9 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x22,x23 // a^b, b^c in next round
+ eor x16,x16,x12,ror#18 // Sigma1(e)
+ ror x12,x22,#28
+ add x21,x21,x17 // h+=Ch(e,f,g)
+ eor x17,x22,x22,ror#5
+ add x21,x21,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x25,x25,x21 // d+=h
+ eor x28,x28,x23 // Maj(a,b,c)
+ eor x17,x12,x17,ror#34 // Sigma0(a)
+ add x21,x21,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x21,x21,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x10,x10 // 7
+#endif
+ ldp x11,x12,[x1],#2*8
+ add x21,x21,x17 // h+=Sigma0(a)
+ ror x16,x25,#14
+ add x20,x20,x28 // h+=K[i]
+ eor x13,x25,x25,ror#23
+ and x17,x26,x25
+ bic x28,x27,x25
+ add x20,x20,x10 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x21,x22 // a^b, b^c in next round
+ eor x16,x16,x13,ror#18 // Sigma1(e)
+ ror x13,x21,#28
+ add x20,x20,x17 // h+=Ch(e,f,g)
+ eor x17,x21,x21,ror#5
+ add x20,x20,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x24,x24,x20 // d+=h
+ eor x19,x19,x22 // Maj(a,b,c)
+ eor x17,x13,x17,ror#34 // Sigma0(a)
+ add x20,x20,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x20,x20,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x11,x11 // 8
+#endif
+ add x20,x20,x17 // h+=Sigma0(a)
+ ror x16,x24,#14
+ add x27,x27,x19 // h+=K[i]
+ eor x14,x24,x24,ror#23
+ and x17,x25,x24
+ bic x19,x26,x24
+ add x27,x27,x11 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x20,x21 // a^b, b^c in next round
+ eor x16,x16,x14,ror#18 // Sigma1(e)
+ ror x14,x20,#28
+ add x27,x27,x17 // h+=Ch(e,f,g)
+ eor x17,x20,x20,ror#5
+ add x27,x27,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x23,x23,x27 // d+=h
+ eor x28,x28,x21 // Maj(a,b,c)
+ eor x17,x14,x17,ror#34 // Sigma0(a)
+ add x27,x27,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x27,x27,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x12,x12 // 9
+#endif
+ ldp x13,x14,[x1],#2*8
+ add x27,x27,x17 // h+=Sigma0(a)
+ ror x16,x23,#14
+ add x26,x26,x28 // h+=K[i]
+ eor x15,x23,x23,ror#23
+ and x17,x24,x23
+ bic x28,x25,x23
+ add x26,x26,x12 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x27,x20 // a^b, b^c in next round
+ eor x16,x16,x15,ror#18 // Sigma1(e)
+ ror x15,x27,#28
+ add x26,x26,x17 // h+=Ch(e,f,g)
+ eor x17,x27,x27,ror#5
+ add x26,x26,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x22,x22,x26 // d+=h
+ eor x19,x19,x20 // Maj(a,b,c)
+ eor x17,x15,x17,ror#34 // Sigma0(a)
+ add x26,x26,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x26,x26,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x13,x13 // 10
+#endif
+ add x26,x26,x17 // h+=Sigma0(a)
+ ror x16,x22,#14
+ add x25,x25,x19 // h+=K[i]
+ eor x0,x22,x22,ror#23
+ and x17,x23,x22
+ bic x19,x24,x22
+ add x25,x25,x13 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x26,x27 // a^b, b^c in next round
+ eor x16,x16,x0,ror#18 // Sigma1(e)
+ ror x0,x26,#28
+ add x25,x25,x17 // h+=Ch(e,f,g)
+ eor x17,x26,x26,ror#5
+ add x25,x25,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x21,x21,x25 // d+=h
+ eor x28,x28,x27 // Maj(a,b,c)
+ eor x17,x0,x17,ror#34 // Sigma0(a)
+ add x25,x25,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x25,x25,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x14,x14 // 11
+#endif
+ ldp x15,x0,[x1],#2*8
+ add x25,x25,x17 // h+=Sigma0(a)
+ str x6,[sp,#24]
+ ror x16,x21,#14
+ add x24,x24,x28 // h+=K[i]
+ eor x6,x21,x21,ror#23
+ and x17,x22,x21
+ bic x28,x23,x21
+ add x24,x24,x14 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x25,x26 // a^b, b^c in next round
+ eor x16,x16,x6,ror#18 // Sigma1(e)
+ ror x6,x25,#28
+ add x24,x24,x17 // h+=Ch(e,f,g)
+ eor x17,x25,x25,ror#5
+ add x24,x24,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x20,x20,x24 // d+=h
+ eor x19,x19,x26 // Maj(a,b,c)
+ eor x17,x6,x17,ror#34 // Sigma0(a)
+ add x24,x24,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x24,x24,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x15,x15 // 12
+#endif
+ add x24,x24,x17 // h+=Sigma0(a)
+ str x7,[sp,#0]
+ ror x16,x20,#14
+ add x23,x23,x19 // h+=K[i]
+ eor x7,x20,x20,ror#23
+ and x17,x21,x20
+ bic x19,x22,x20
+ add x23,x23,x15 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x24,x25 // a^b, b^c in next round
+ eor x16,x16,x7,ror#18 // Sigma1(e)
+ ror x7,x24,#28
+ add x23,x23,x17 // h+=Ch(e,f,g)
+ eor x17,x24,x24,ror#5
+ add x23,x23,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x27,x27,x23 // d+=h
+ eor x28,x28,x25 // Maj(a,b,c)
+ eor x17,x7,x17,ror#34 // Sigma0(a)
+ add x23,x23,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x23,x23,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x0,x0 // 13
+#endif
+ ldp x1,x2,[x1]
+ add x23,x23,x17 // h+=Sigma0(a)
+ str x8,[sp,#8]
+ ror x16,x27,#14
+ add x22,x22,x28 // h+=K[i]
+ eor x8,x27,x27,ror#23
+ and x17,x20,x27
+ bic x28,x21,x27
+ add x22,x22,x0 // h+=X[i]
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x23,x24 // a^b, b^c in next round
+ eor x16,x16,x8,ror#18 // Sigma1(e)
+ ror x8,x23,#28
+ add x22,x22,x17 // h+=Ch(e,f,g)
+ eor x17,x23,x23,ror#5
+ add x22,x22,x16 // h+=Sigma1(e)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ add x26,x26,x22 // d+=h
+ eor x19,x19,x24 // Maj(a,b,c)
+ eor x17,x8,x17,ror#34 // Sigma0(a)
+ add x22,x22,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ //add x22,x22,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x1,x1 // 14
+#endif
+ ldr x6,[sp,#24]
+ add x22,x22,x17 // h+=Sigma0(a)
+ str x9,[sp,#16]
+ ror x16,x26,#14
+ add x21,x21,x19 // h+=K[i]
+ eor x9,x26,x26,ror#23
+ and x17,x27,x26
+ bic x19,x20,x26
+ add x21,x21,x1 // h+=X[i]
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x22,x23 // a^b, b^c in next round
+ eor x16,x16,x9,ror#18 // Sigma1(e)
+ ror x9,x22,#28
+ add x21,x21,x17 // h+=Ch(e,f,g)
+ eor x17,x22,x22,ror#5
+ add x21,x21,x16 // h+=Sigma1(e)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ add x25,x25,x21 // d+=h
+ eor x28,x28,x23 // Maj(a,b,c)
+ eor x17,x9,x17,ror#34 // Sigma0(a)
+ add x21,x21,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ //add x21,x21,x17 // h+=Sigma0(a)
+#ifndef __AARCH64EB__
+ rev x2,x2 // 15
+#endif
+ ldr x7,[sp,#0]
+ add x21,x21,x17 // h+=Sigma0(a)
+ str x10,[sp,#24]
+ ror x16,x25,#14
+ add x20,x20,x28 // h+=K[i]
+ ror x9,x4,#1
+ and x17,x26,x25
+ ror x8,x1,#19
+ bic x28,x27,x25
+ ror x10,x21,#28
+ add x20,x20,x2 // h+=X[i]
+ eor x16,x16,x25,ror#18
+ eor x9,x9,x4,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x21,x22 // a^b, b^c in next round
+ eor x16,x16,x25,ror#41 // Sigma1(e)
+ eor x10,x10,x21,ror#34
+ add x20,x20,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x8,x8,x1,ror#61
+ eor x9,x9,x4,lsr#7 // sigma0(X[i+1])
+ add x20,x20,x16 // h+=Sigma1(e)
+ eor x19,x19,x22 // Maj(a,b,c)
+ eor x17,x10,x21,ror#39 // Sigma0(a)
+ eor x8,x8,x1,lsr#6 // sigma1(X[i+14])
+ add x3,x3,x12
+ add x24,x24,x20 // d+=h
+ add x20,x20,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x3,x3,x9
+ add x20,x20,x17 // h+=Sigma0(a)
+ add x3,x3,x8
+.Loop_16_xx:
+ ldr x8,[sp,#8]
+ str x11,[sp,#0]
+ ror x16,x24,#14
+ add x27,x27,x19 // h+=K[i]
+ ror x10,x5,#1
+ and x17,x25,x24
+ ror x9,x2,#19
+ bic x19,x26,x24
+ ror x11,x20,#28
+ add x27,x27,x3 // h+=X[i]
+ eor x16,x16,x24,ror#18
+ eor x10,x10,x5,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x20,x21 // a^b, b^c in next round
+ eor x16,x16,x24,ror#41 // Sigma1(e)
+ eor x11,x11,x20,ror#34
+ add x27,x27,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x9,x9,x2,ror#61
+ eor x10,x10,x5,lsr#7 // sigma0(X[i+1])
+ add x27,x27,x16 // h+=Sigma1(e)
+ eor x28,x28,x21 // Maj(a,b,c)
+ eor x17,x11,x20,ror#39 // Sigma0(a)
+ eor x9,x9,x2,lsr#6 // sigma1(X[i+14])
+ add x4,x4,x13
+ add x23,x23,x27 // d+=h
+ add x27,x27,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x4,x4,x10
+ add x27,x27,x17 // h+=Sigma0(a)
+ add x4,x4,x9
+ ldr x9,[sp,#16]
+ str x12,[sp,#8]
+ ror x16,x23,#14
+ add x26,x26,x28 // h+=K[i]
+ ror x11,x6,#1
+ and x17,x24,x23
+ ror x10,x3,#19
+ bic x28,x25,x23
+ ror x12,x27,#28
+ add x26,x26,x4 // h+=X[i]
+ eor x16,x16,x23,ror#18
+ eor x11,x11,x6,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x27,x20 // a^b, b^c in next round
+ eor x16,x16,x23,ror#41 // Sigma1(e)
+ eor x12,x12,x27,ror#34
+ add x26,x26,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x10,x10,x3,ror#61
+ eor x11,x11,x6,lsr#7 // sigma0(X[i+1])
+ add x26,x26,x16 // h+=Sigma1(e)
+ eor x19,x19,x20 // Maj(a,b,c)
+ eor x17,x12,x27,ror#39 // Sigma0(a)
+ eor x10,x10,x3,lsr#6 // sigma1(X[i+14])
+ add x5,x5,x14
+ add x22,x22,x26 // d+=h
+ add x26,x26,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x5,x5,x11
+ add x26,x26,x17 // h+=Sigma0(a)
+ add x5,x5,x10
+ ldr x10,[sp,#24]
+ str x13,[sp,#16]
+ ror x16,x22,#14
+ add x25,x25,x19 // h+=K[i]
+ ror x12,x7,#1
+ and x17,x23,x22
+ ror x11,x4,#19
+ bic x19,x24,x22
+ ror x13,x26,#28
+ add x25,x25,x5 // h+=X[i]
+ eor x16,x16,x22,ror#18
+ eor x12,x12,x7,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x26,x27 // a^b, b^c in next round
+ eor x16,x16,x22,ror#41 // Sigma1(e)
+ eor x13,x13,x26,ror#34
+ add x25,x25,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x11,x11,x4,ror#61
+ eor x12,x12,x7,lsr#7 // sigma0(X[i+1])
+ add x25,x25,x16 // h+=Sigma1(e)
+ eor x28,x28,x27 // Maj(a,b,c)
+ eor x17,x13,x26,ror#39 // Sigma0(a)
+ eor x11,x11,x4,lsr#6 // sigma1(X[i+14])
+ add x6,x6,x15
+ add x21,x21,x25 // d+=h
+ add x25,x25,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x6,x6,x12
+ add x25,x25,x17 // h+=Sigma0(a)
+ add x6,x6,x11
+ ldr x11,[sp,#0]
+ str x14,[sp,#24]
+ ror x16,x21,#14
+ add x24,x24,x28 // h+=K[i]
+ ror x13,x8,#1
+ and x17,x22,x21
+ ror x12,x5,#19
+ bic x28,x23,x21
+ ror x14,x25,#28
+ add x24,x24,x6 // h+=X[i]
+ eor x16,x16,x21,ror#18
+ eor x13,x13,x8,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x25,x26 // a^b, b^c in next round
+ eor x16,x16,x21,ror#41 // Sigma1(e)
+ eor x14,x14,x25,ror#34
+ add x24,x24,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x12,x12,x5,ror#61
+ eor x13,x13,x8,lsr#7 // sigma0(X[i+1])
+ add x24,x24,x16 // h+=Sigma1(e)
+ eor x19,x19,x26 // Maj(a,b,c)
+ eor x17,x14,x25,ror#39 // Sigma0(a)
+ eor x12,x12,x5,lsr#6 // sigma1(X[i+14])
+ add x7,x7,x0
+ add x20,x20,x24 // d+=h
+ add x24,x24,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x7,x7,x13
+ add x24,x24,x17 // h+=Sigma0(a)
+ add x7,x7,x12
+ ldr x12,[sp,#8]
+ str x15,[sp,#0]
+ ror x16,x20,#14
+ add x23,x23,x19 // h+=K[i]
+ ror x14,x9,#1
+ and x17,x21,x20
+ ror x13,x6,#19
+ bic x19,x22,x20
+ ror x15,x24,#28
+ add x23,x23,x7 // h+=X[i]
+ eor x16,x16,x20,ror#18
+ eor x14,x14,x9,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x24,x25 // a^b, b^c in next round
+ eor x16,x16,x20,ror#41 // Sigma1(e)
+ eor x15,x15,x24,ror#34
+ add x23,x23,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x13,x13,x6,ror#61
+ eor x14,x14,x9,lsr#7 // sigma0(X[i+1])
+ add x23,x23,x16 // h+=Sigma1(e)
+ eor x28,x28,x25 // Maj(a,b,c)
+ eor x17,x15,x24,ror#39 // Sigma0(a)
+ eor x13,x13,x6,lsr#6 // sigma1(X[i+14])
+ add x8,x8,x1
+ add x27,x27,x23 // d+=h
+ add x23,x23,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x8,x8,x14
+ add x23,x23,x17 // h+=Sigma0(a)
+ add x8,x8,x13
+ ldr x13,[sp,#16]
+ str x0,[sp,#8]
+ ror x16,x27,#14
+ add x22,x22,x28 // h+=K[i]
+ ror x15,x10,#1
+ and x17,x20,x27
+ ror x14,x7,#19
+ bic x28,x21,x27
+ ror x0,x23,#28
+ add x22,x22,x8 // h+=X[i]
+ eor x16,x16,x27,ror#18
+ eor x15,x15,x10,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x23,x24 // a^b, b^c in next round
+ eor x16,x16,x27,ror#41 // Sigma1(e)
+ eor x0,x0,x23,ror#34
+ add x22,x22,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x14,x14,x7,ror#61
+ eor x15,x15,x10,lsr#7 // sigma0(X[i+1])
+ add x22,x22,x16 // h+=Sigma1(e)
+ eor x19,x19,x24 // Maj(a,b,c)
+ eor x17,x0,x23,ror#39 // Sigma0(a)
+ eor x14,x14,x7,lsr#6 // sigma1(X[i+14])
+ add x9,x9,x2
+ add x26,x26,x22 // d+=h
+ add x22,x22,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x9,x9,x15
+ add x22,x22,x17 // h+=Sigma0(a)
+ add x9,x9,x14
+ ldr x14,[sp,#24]
+ str x1,[sp,#16]
+ ror x16,x26,#14
+ add x21,x21,x19 // h+=K[i]
+ ror x0,x11,#1
+ and x17,x27,x26
+ ror x15,x8,#19
+ bic x19,x20,x26
+ ror x1,x22,#28
+ add x21,x21,x9 // h+=X[i]
+ eor x16,x16,x26,ror#18
+ eor x0,x0,x11,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x22,x23 // a^b, b^c in next round
+ eor x16,x16,x26,ror#41 // Sigma1(e)
+ eor x1,x1,x22,ror#34
+ add x21,x21,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x15,x15,x8,ror#61
+ eor x0,x0,x11,lsr#7 // sigma0(X[i+1])
+ add x21,x21,x16 // h+=Sigma1(e)
+ eor x28,x28,x23 // Maj(a,b,c)
+ eor x17,x1,x22,ror#39 // Sigma0(a)
+ eor x15,x15,x8,lsr#6 // sigma1(X[i+14])
+ add x10,x10,x3
+ add x25,x25,x21 // d+=h
+ add x21,x21,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x10,x10,x0
+ add x21,x21,x17 // h+=Sigma0(a)
+ add x10,x10,x15
+ ldr x15,[sp,#0]
+ str x2,[sp,#24]
+ ror x16,x25,#14
+ add x20,x20,x28 // h+=K[i]
+ ror x1,x12,#1
+ and x17,x26,x25
+ ror x0,x9,#19
+ bic x28,x27,x25
+ ror x2,x21,#28
+ add x20,x20,x10 // h+=X[i]
+ eor x16,x16,x25,ror#18
+ eor x1,x1,x12,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x21,x22 // a^b, b^c in next round
+ eor x16,x16,x25,ror#41 // Sigma1(e)
+ eor x2,x2,x21,ror#34
+ add x20,x20,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x0,x0,x9,ror#61
+ eor x1,x1,x12,lsr#7 // sigma0(X[i+1])
+ add x20,x20,x16 // h+=Sigma1(e)
+ eor x19,x19,x22 // Maj(a,b,c)
+ eor x17,x2,x21,ror#39 // Sigma0(a)
+ eor x0,x0,x9,lsr#6 // sigma1(X[i+14])
+ add x11,x11,x4
+ add x24,x24,x20 // d+=h
+ add x20,x20,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x11,x11,x1
+ add x20,x20,x17 // h+=Sigma0(a)
+ add x11,x11,x0
+ ldr x0,[sp,#8]
+ str x3,[sp,#0]
+ ror x16,x24,#14
+ add x27,x27,x19 // h+=K[i]
+ ror x2,x13,#1
+ and x17,x25,x24
+ ror x1,x10,#19
+ bic x19,x26,x24
+ ror x3,x20,#28
+ add x27,x27,x11 // h+=X[i]
+ eor x16,x16,x24,ror#18
+ eor x2,x2,x13,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x20,x21 // a^b, b^c in next round
+ eor x16,x16,x24,ror#41 // Sigma1(e)
+ eor x3,x3,x20,ror#34
+ add x27,x27,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x1,x1,x10,ror#61
+ eor x2,x2,x13,lsr#7 // sigma0(X[i+1])
+ add x27,x27,x16 // h+=Sigma1(e)
+ eor x28,x28,x21 // Maj(a,b,c)
+ eor x17,x3,x20,ror#39 // Sigma0(a)
+ eor x1,x1,x10,lsr#6 // sigma1(X[i+14])
+ add x12,x12,x5
+ add x23,x23,x27 // d+=h
+ add x27,x27,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x12,x12,x2
+ add x27,x27,x17 // h+=Sigma0(a)
+ add x12,x12,x1
+ ldr x1,[sp,#16]
+ str x4,[sp,#8]
+ ror x16,x23,#14
+ add x26,x26,x28 // h+=K[i]
+ ror x3,x14,#1
+ and x17,x24,x23
+ ror x2,x11,#19
+ bic x28,x25,x23
+ ror x4,x27,#28
+ add x26,x26,x12 // h+=X[i]
+ eor x16,x16,x23,ror#18
+ eor x3,x3,x14,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x27,x20 // a^b, b^c in next round
+ eor x16,x16,x23,ror#41 // Sigma1(e)
+ eor x4,x4,x27,ror#34
+ add x26,x26,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x2,x2,x11,ror#61
+ eor x3,x3,x14,lsr#7 // sigma0(X[i+1])
+ add x26,x26,x16 // h+=Sigma1(e)
+ eor x19,x19,x20 // Maj(a,b,c)
+ eor x17,x4,x27,ror#39 // Sigma0(a)
+ eor x2,x2,x11,lsr#6 // sigma1(X[i+14])
+ add x13,x13,x6
+ add x22,x22,x26 // d+=h
+ add x26,x26,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x13,x13,x3
+ add x26,x26,x17 // h+=Sigma0(a)
+ add x13,x13,x2
+ ldr x2,[sp,#24]
+ str x5,[sp,#16]
+ ror x16,x22,#14
+ add x25,x25,x19 // h+=K[i]
+ ror x4,x15,#1
+ and x17,x23,x22
+ ror x3,x12,#19
+ bic x19,x24,x22
+ ror x5,x26,#28
+ add x25,x25,x13 // h+=X[i]
+ eor x16,x16,x22,ror#18
+ eor x4,x4,x15,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x26,x27 // a^b, b^c in next round
+ eor x16,x16,x22,ror#41 // Sigma1(e)
+ eor x5,x5,x26,ror#34
+ add x25,x25,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x3,x3,x12,ror#61
+ eor x4,x4,x15,lsr#7 // sigma0(X[i+1])
+ add x25,x25,x16 // h+=Sigma1(e)
+ eor x28,x28,x27 // Maj(a,b,c)
+ eor x17,x5,x26,ror#39 // Sigma0(a)
+ eor x3,x3,x12,lsr#6 // sigma1(X[i+14])
+ add x14,x14,x7
+ add x21,x21,x25 // d+=h
+ add x25,x25,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x14,x14,x4
+ add x25,x25,x17 // h+=Sigma0(a)
+ add x14,x14,x3
+ ldr x3,[sp,#0]
+ str x6,[sp,#24]
+ ror x16,x21,#14
+ add x24,x24,x28 // h+=K[i]
+ ror x5,x0,#1
+ and x17,x22,x21
+ ror x4,x13,#19
+ bic x28,x23,x21
+ ror x6,x25,#28
+ add x24,x24,x14 // h+=X[i]
+ eor x16,x16,x21,ror#18
+ eor x5,x5,x0,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x25,x26 // a^b, b^c in next round
+ eor x16,x16,x21,ror#41 // Sigma1(e)
+ eor x6,x6,x25,ror#34
+ add x24,x24,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x4,x4,x13,ror#61
+ eor x5,x5,x0,lsr#7 // sigma0(X[i+1])
+ add x24,x24,x16 // h+=Sigma1(e)
+ eor x19,x19,x26 // Maj(a,b,c)
+ eor x17,x6,x25,ror#39 // Sigma0(a)
+ eor x4,x4,x13,lsr#6 // sigma1(X[i+14])
+ add x15,x15,x8
+ add x20,x20,x24 // d+=h
+ add x24,x24,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x15,x15,x5
+ add x24,x24,x17 // h+=Sigma0(a)
+ add x15,x15,x4
+ ldr x4,[sp,#8]
+ str x7,[sp,#0]
+ ror x16,x20,#14
+ add x23,x23,x19 // h+=K[i]
+ ror x6,x1,#1
+ and x17,x21,x20
+ ror x5,x14,#19
+ bic x19,x22,x20
+ ror x7,x24,#28
+ add x23,x23,x15 // h+=X[i]
+ eor x16,x16,x20,ror#18
+ eor x6,x6,x1,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x24,x25 // a^b, b^c in next round
+ eor x16,x16,x20,ror#41 // Sigma1(e)
+ eor x7,x7,x24,ror#34
+ add x23,x23,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x5,x5,x14,ror#61
+ eor x6,x6,x1,lsr#7 // sigma0(X[i+1])
+ add x23,x23,x16 // h+=Sigma1(e)
+ eor x28,x28,x25 // Maj(a,b,c)
+ eor x17,x7,x24,ror#39 // Sigma0(a)
+ eor x5,x5,x14,lsr#6 // sigma1(X[i+14])
+ add x0,x0,x9
+ add x27,x27,x23 // d+=h
+ add x23,x23,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x0,x0,x6
+ add x23,x23,x17 // h+=Sigma0(a)
+ add x0,x0,x5
+ ldr x5,[sp,#16]
+ str x8,[sp,#8]
+ ror x16,x27,#14
+ add x22,x22,x28 // h+=K[i]
+ ror x7,x2,#1
+ and x17,x20,x27
+ ror x6,x15,#19
+ bic x28,x21,x27
+ ror x8,x23,#28
+ add x22,x22,x0 // h+=X[i]
+ eor x16,x16,x27,ror#18
+ eor x7,x7,x2,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x23,x24 // a^b, b^c in next round
+ eor x16,x16,x27,ror#41 // Sigma1(e)
+ eor x8,x8,x23,ror#34
+ add x22,x22,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x6,x6,x15,ror#61
+ eor x7,x7,x2,lsr#7 // sigma0(X[i+1])
+ add x22,x22,x16 // h+=Sigma1(e)
+ eor x19,x19,x24 // Maj(a,b,c)
+ eor x17,x8,x23,ror#39 // Sigma0(a)
+ eor x6,x6,x15,lsr#6 // sigma1(X[i+14])
+ add x1,x1,x10
+ add x26,x26,x22 // d+=h
+ add x22,x22,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x1,x1,x7
+ add x22,x22,x17 // h+=Sigma0(a)
+ add x1,x1,x6
+ ldr x6,[sp,#24]
+ str x9,[sp,#16]
+ ror x16,x26,#14
+ add x21,x21,x19 // h+=K[i]
+ ror x8,x3,#1
+ and x17,x27,x26
+ ror x7,x0,#19
+ bic x19,x20,x26
+ ror x9,x22,#28
+ add x21,x21,x1 // h+=X[i]
+ eor x16,x16,x26,ror#18
+ eor x8,x8,x3,ror#8
+ orr x17,x17,x19 // Ch(e,f,g)
+ eor x19,x22,x23 // a^b, b^c in next round
+ eor x16,x16,x26,ror#41 // Sigma1(e)
+ eor x9,x9,x22,ror#34
+ add x21,x21,x17 // h+=Ch(e,f,g)
+ and x28,x28,x19 // (b^c)&=(a^b)
+ eor x7,x7,x0,ror#61
+ eor x8,x8,x3,lsr#7 // sigma0(X[i+1])
+ add x21,x21,x16 // h+=Sigma1(e)
+ eor x28,x28,x23 // Maj(a,b,c)
+ eor x17,x9,x22,ror#39 // Sigma0(a)
+ eor x7,x7,x0,lsr#6 // sigma1(X[i+14])
+ add x2,x2,x11
+ add x25,x25,x21 // d+=h
+ add x21,x21,x28 // h+=Maj(a,b,c)
+ ldr x28,[x30],#8 // *K++, x19 in next round
+ add x2,x2,x8
+ add x21,x21,x17 // h+=Sigma0(a)
+ add x2,x2,x7
+ ldr x7,[sp,#0]
+ str x10,[sp,#24]
+ ror x16,x25,#14
+ add x20,x20,x28 // h+=K[i]
+ ror x9,x4,#1
+ and x17,x26,x25
+ ror x8,x1,#19
+ bic x28,x27,x25
+ ror x10,x21,#28
+ add x20,x20,x2 // h+=X[i]
+ eor x16,x16,x25,ror#18
+ eor x9,x9,x4,ror#8
+ orr x17,x17,x28 // Ch(e,f,g)
+ eor x28,x21,x22 // a^b, b^c in next round
+ eor x16,x16,x25,ror#41 // Sigma1(e)
+ eor x10,x10,x21,ror#34
+ add x20,x20,x17 // h+=Ch(e,f,g)
+ and x19,x19,x28 // (b^c)&=(a^b)
+ eor x8,x8,x1,ror#61
+ eor x9,x9,x4,lsr#7 // sigma0(X[i+1])
+ add x20,x20,x16 // h+=Sigma1(e)
+ eor x19,x19,x22 // Maj(a,b,c)
+ eor x17,x10,x21,ror#39 // Sigma0(a)
+ eor x8,x8,x1,lsr#6 // sigma1(X[i+14])
+ add x3,x3,x12
+ add x24,x24,x20 // d+=h
+ add x20,x20,x19 // h+=Maj(a,b,c)
+ ldr x19,[x30],#8 // *K++, x28 in next round
+ add x3,x3,x9
+ add x20,x20,x17 // h+=Sigma0(a)
+ add x3,x3,x8
+ cbnz x19,.Loop_16_xx
+
+ ldp x0,x2,[x29,#96]
+ ldr x1,[x29,#112]
+ sub x30,x30,#648 // rewind
+
+ ldp x3,x4,[x0]
+ ldp x5,x6,[x0,#2*8]
+ add x1,x1,#14*8 // advance input pointer
+ ldp x7,x8,[x0,#4*8]
+ add x20,x20,x3
+ ldp x9,x10,[x0,#6*8]
+ add x21,x21,x4
+ add x22,x22,x5
+ add x23,x23,x6
+ stp x20,x21,[x0]
+ add x24,x24,x7
+ add x25,x25,x8
+ stp x22,x23,[x0,#2*8]
+ add x26,x26,x9
+ add x27,x27,x10
+ cmp x1,x2
+ stp x24,x25,[x0,#4*8]
+ stp x26,x27,[x0,#6*8]
+ b.ne .Loop
+
+ ldp x19,x20,[x29,#16]
+ add sp,sp,#4*8
+ ldp x21,x22,[x29,#32]
+ ldp x23,x24,[x29,#48]
+ ldp x25,x26,[x29,#64]
+ ldp x27,x28,[x29,#80]
+ ldp x29,x30,[sp],#128
+ ret
+.size sha512_block_data_order,.-sha512_block_data_order
+
+.align 6
+.type .LK512,%object
+.LK512:
+ .quad 0x428a2f98d728ae22,0x7137449123ef65cd
+ .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc
+ .quad 0x3956c25bf348b538,0x59f111f1b605d019
+ .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118
+ .quad 0xd807aa98a3030242,0x12835b0145706fbe
+ .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2
+ .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1
+ .quad 0x9bdc06a725c71235,0xc19bf174cf692694
+ .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3
+ .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65
+ .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483
+ .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5
+ .quad 0x983e5152ee66dfab,0xa831c66d2db43210
+ .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4
+ .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725
+ .quad 0x06ca6351e003826f,0x142929670a0e6e70
+ .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926
+ .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df
+ .quad 0x650a73548baf63de,0x766a0abb3c77b2a8
+ .quad 0x81c2c92e47edaee6,0x92722c851482353b
+ .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001
+ .quad 0xc24b8b70d0f89791,0xc76c51a30654be30
+ .quad 0xd192e819d6ef5218,0xd69906245565a910
+ .quad 0xf40e35855771202a,0x106aa07032bbd1b8
+ .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53
+ .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8
+ .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb
+ .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3
+ .quad 0x748f82ee5defb2fc,0x78a5636f43172f60
+ .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec
+ .quad 0x90befffa23631e28,0xa4506cebde82bde9
+ .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b
+ .quad 0xca273eceea26619c,0xd186b8c721c0c207
+ .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178
+ .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6
+ .quad 0x113f9804bef90dae,0x1b710b35131c471b
+ .quad 0x28db77f523047d84,0x32caab7b40c72493
+ .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c
+ .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a
+ .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817
+ .quad 0 // terminator
+.size .LK512,.-.LK512
+#ifndef __KERNEL__
+.align 3
+.LOPENSSL_armcap_P:
+# ifdef __ILP32__
+ .long OPENSSL_armcap_P-.
+# else
+ .quad OPENSSL_armcap_P-.
+# endif
+#endif
+.asciz "SHA512 block transform for ARMv8, CRYPTOGAMS by <appro@openssl.org>"
+.align 2
+#ifndef __KERNEL__
+.comm OPENSSL_armcap_P,4,4
+#endif
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 88a4d1e..c7749d8 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -109,6 +109,24 @@
.endm
/*
+ * Value prediction barrier
+ */
+ .macro csdb
+ hint #20
+ .endm
+
+/*
+ * Sanitise a 64-bit bounded index wrt speculation, returning zero if out
+ * of bounds.
+ */
+ .macro mask_nospec64, idx, limit, tmp
+ sub \tmp, \idx, \limit
+ bic \tmp, \tmp, \idx
+ and \idx, \idx, \tmp, asr #63
+ csdb
+ .endm
+
+/*
* NOP sequence
*/
.macro nops, num
@@ -492,4 +510,8 @@
.Ldone\@:
.endm
+ .macro pte_to_phys, phys, pte
+ and \phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT)
+ .endm
+
#endif /* __ASM_ASSEMBLER_H */
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 0fe7e43..0b0755c 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -31,6 +31,8 @@
#define dmb(opt) asm volatile("dmb " #opt : : : "memory")
#define dsb(opt) asm volatile("dsb " #opt : : : "memory")
+#define csdb() asm volatile("hint #20" : : : "memory")
+
#define mb() dsb(sy)
#define rmb() dsb(ld)
#define wmb() dsb(st)
@@ -38,6 +40,27 @@
#define dma_rmb() dmb(oshld)
#define dma_wmb() dmb(oshst)
+/*
+ * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz
+ * and 0 otherwise.
+ */
+#define array_index_mask_nospec array_index_mask_nospec
+static inline unsigned long array_index_mask_nospec(unsigned long idx,
+ unsigned long sz)
+{
+ unsigned long mask;
+
+ asm volatile(
+ " cmp %1, %2\n"
+ " sbc %0, xzr, xzr\n"
+ : "=r" (mask)
+ : "r" (idx), "Ir" (sz)
+ : "cc");
+
+ csdb();
+ return mask;
+}
+
#define __smp_mb() dmb(ish)
#define __smp_rmb() dmb(ishld)
#define __smp_wmb() dmb(ishst)
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 847bfe6..9a6b81a 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -92,6 +92,7 @@
#define CAVIUM_CPU_PART_THUNDERX 0x0A1
#define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2
+#define CAVIUM_CPU_PART_THUNDERX2 0x0AF
#define BRCM_CPU_PART_VULCAN 0x516
@@ -107,6 +108,8 @@
#define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
#define MIDR_KRYO2XX_GOLD \
MIDR_CPU_MODEL(ARM_CPU_IMP_QCOM, ARM_CPU_PART_KRYO2XX_GOLD)
+#define MIDR_CAVIUM_THUNDERX2 MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2)
+#define MIDR_BRCM_VULCAN MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN)
#ifndef __ASSEMBLY__
diff --git a/arch/arm64/include/asm/dma-contiguous.h b/arch/arm64/include/asm/dma-contiguous.h
index f7e2c32..50f70a8 100644
--- a/arch/arm64/include/asm/dma-contiguous.h
+++ b/arch/arm64/include/asm/dma-contiguous.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013,2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013,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
@@ -15,7 +15,6 @@
#define _ASM_DMA_CONTIGUOUS_H
#ifdef __KERNEL__
-#ifdef CONFIG_DMA_CMA
#include <linux/types.h>
@@ -23,5 +22,3 @@
#endif
#endif
-
-#endif
diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h
index 85c4a89..c5bc52e 100644
--- a/arch/arm64/include/asm/futex.h
+++ b/arch/arm64/include/asm/futex.h
@@ -48,16 +48,17 @@
} while (0)
static inline int
-futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
+futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr)
{
int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15;
- int oparg = (encoded_op << 8) >> 20;
- int cmparg = (encoded_op << 20) >> 20;
+ int oparg = (int)(encoded_op << 8) >> 20;
+ int cmparg = (int)(encoded_op << 20) >> 20;
int oldval = 0, ret, tmp;
+ u32 __user *uaddr = __uaccess_mask_ptr(_uaddr);
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
- oparg = 1 << oparg;
+ oparg = 1U << (oparg & 0x1f);
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
@@ -106,15 +107,17 @@
}
static inline int
-futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr,
u32 oldval, u32 newval)
{
int ret = 0;
u32 val, tmp;
+ u32 __user *uaddr;
- if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
+ if (!access_ok(VERIFY_WRITE, _uaddr, sizeof(u32)))
return -EFAULT;
+ uaddr = __uaccess_mask_ptr(_uaddr);
uaccess_enable();
asm volatile("// futex_atomic_cmpxchg_inatomic\n"
" prfm pstl1strm, %2\n"
diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h
index 77a27af..7803343 100644
--- a/arch/arm64/include/asm/kernel-pgtable.h
+++ b/arch/arm64/include/asm/kernel-pgtable.h
@@ -78,16 +78,8 @@
/*
* Initial memory map attributes.
*/
-#define _SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
-#define _SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
-
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-#define SWAPPER_PTE_FLAGS (_SWAPPER_PTE_FLAGS | PTE_NG)
-#define SWAPPER_PMD_FLAGS (_SWAPPER_PMD_FLAGS | PMD_SECT_NG)
-#else
-#define SWAPPER_PTE_FLAGS _SWAPPER_PTE_FLAGS
-#define SWAPPER_PMD_FLAGS _SWAPPER_PMD_FLAGS
-#endif
+#define SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
+#define SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
#if ARM64_SWAPPER_USES_SECTION_MAPS
#define SWAPPER_MM_MMUFLAGS (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS)
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index e505038..37d56e8 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -393,4 +393,9 @@
"PARange is %d bits, unsupported configuration!", parange);
}
+static inline bool kvm_arm_harden_branch_predictor(void)
+{
+ return cpus_have_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 35ea9c1..36d2aba 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -325,7 +325,7 @@
vect = __bp_harden_hyp_vecs_start +
data->hyp_vectors_slot * SZ_2K;
- if (!has_vhe())
+ if (!cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN))
vect = lm_alias(vect);
}
diff --git a/arch/arm64/include/asm/kvm_psci.h b/arch/arm64/include/asm/kvm_psci.h
deleted file mode 100644
index bc39e55..0000000
--- a/arch/arm64/include/asm/kvm_psci.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __ARM64_KVM_PSCI_H__
-#define __ARM64_KVM_PSCI_H__
-
-#define KVM_ARM_PSCI_0_1 1
-#define KVM_ARM_PSCI_0_2 2
-
-int kvm_psci_version(struct kvm_vcpu *vcpu);
-int kvm_psci_call(struct kvm_vcpu *vcpu);
-
-#endif /* __ARM64_KVM_PSCI_H__ */
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index 8fe5ffc..708028e 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -61,12 +61,12 @@
* KIMAGE_VADDR - the virtual address of the start of the kernel image
* VA_BITS - the maximum number of bits for virtual addresses.
* VA_START - the first kernel virtual address.
- * TASK_SIZE - the maximum size of a user space task.
- * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
*/
#define VA_BITS (CONFIG_ARM64_VA_BITS)
-#define VA_START (UL(0xffffffffffffffff) << VA_BITS)
-#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
+#define VA_START (UL(0xffffffffffffffff) - \
+ (UL(1) << VA_BITS) + 1)
+#define PAGE_OFFSET (UL(0xffffffffffffffff) - \
+ (UL(1) << (VA_BITS - 1)) + 1)
#define KIMAGE_VADDR (MODULES_END)
#define MODULES_END (MODULES_VADDR + MODULES_VSIZE)
#define MODULES_VADDR (VA_START + KASAN_SHADOW_SIZE)
@@ -75,19 +75,6 @@
#define PCI_IO_END (VMEMMAP_START - SZ_2M)
#define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE)
#define FIXADDR_TOP (PCI_IO_START - SZ_2M)
-#define TASK_SIZE_64 (UL(1) << VA_BITS)
-
-#ifdef CONFIG_COMPAT
-#define TASK_SIZE_32 UL(0x100000000)
-#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
- TASK_SIZE_32 : TASK_SIZE_64)
-#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
- TASK_SIZE_32 : TASK_SIZE_64)
-#else
-#define TASK_SIZE TASK_SIZE_64
-#endif /* CONFIG_COMPAT */
-
-#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
#define KERNEL_START _text
#define KERNEL_END _end
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index f543df3..24c780d 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -21,7 +21,7 @@
#ifndef __ASSEMBLY__
-#include <asm/percpu.h>
+#include <linux/percpu.h>
typedef struct {
atomic64_t id;
@@ -55,7 +55,7 @@
static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void)
{
- return raw_cpu_ptr(&bp_hardening_data);
+ return this_cpu_ptr(&bp_hardening_data);
}
static inline void arm64_apply_bp_hardening(void)
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 84b5283..f705d96 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -37,13 +37,11 @@
#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED)
#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S)
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-#define PROT_DEFAULT (_PROT_DEFAULT | PTE_NG)
-#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_SECT_NG)
-#else
-#define PROT_DEFAULT _PROT_DEFAULT
-#define PROT_SECT_DEFAULT _PROT_SECT_DEFAULT
-#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
+#define PTE_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PTE_NG : 0)
+#define PMD_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0)
+
+#define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG)
+#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG)
#define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE))
#define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE))
@@ -55,22 +53,22 @@
#define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
#define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL))
-#define _PAGE_DEFAULT (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
-#define _HYP_PAGE_DEFAULT (_PAGE_DEFAULT & ~PTE_NG)
+#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
+#define _HYP_PAGE_DEFAULT _PAGE_DEFAULT
-#define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
-#define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
-#define PAGE_KERNEL_ROX __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
-#define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
-#define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
+#define PAGE_KERNEL __pgprot(PROT_NORMAL)
+#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
+#define PAGE_KERNEL_ROX __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
+#define PAGE_KERNEL_EXEC __pgprot(PROT_NORMAL & ~PTE_PXN)
+#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
#define PAGE_HYP __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN)
#define PAGE_HYP_EXEC __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY)
#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN)
#define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
-#define PAGE_S2 __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
-#define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
+#define PAGE_S2 __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
+#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN)
#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_NG | PTE_PXN | PTE_UXN)
#define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index a4af9f0..d8039a1 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -19,6 +19,13 @@
#ifndef __ASM_PROCESSOR_H
#define __ASM_PROCESSOR_H
+#define TASK_SIZE_64 (UL(1) << VA_BITS)
+
+#define KERNEL_DS UL(-1)
+#define USER_DS (TASK_SIZE_64 - 1)
+
+#ifndef __ASSEMBLY__
+
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
@@ -37,6 +44,22 @@
#include <asm/ptrace.h>
#include <asm/types.h>
+/*
+ * TASK_SIZE - the maximum size of a user space task.
+ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area.
+ */
+#ifdef CONFIG_COMPAT
+#define TASK_SIZE_32 UL(0x100000000)
+#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \
+ TASK_SIZE_32 : TASK_SIZE_64)
+#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \
+ TASK_SIZE_32 : TASK_SIZE_64)
+#else
+#define TASK_SIZE TASK_SIZE_64
+#endif /* CONFIG_COMPAT */
+
+#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4))
+
#define STACK_TOP_MAX TASK_SIZE_64
#ifdef CONFIG_COMPAT
#define AARCH32_VECTORS_BASE 0xffff0000
@@ -195,4 +218,5 @@
int cpu_enable_uao(void *__unused);
int cpu_enable_cache_maint_trap(void *__unused);
+#endif /* __ASSEMBLY__ */
#endif /* __ASM_PROCESSOR_H */
diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 9311547..6c35d21 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -35,6 +35,7 @@
#include <asm/cpufeature.h>
#include <asm/kernel-pgtable.h>
+#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/errno.h>
#include <asm/memory.h>
@@ -65,10 +66,7 @@
extern int fixup_exception(struct pt_regs *regs);
-#define KERNEL_DS (-1UL)
#define get_ds() (KERNEL_DS)
-
-#define USER_DS TASK_SIZE_64
#define get_fs() (current_thread_info()->addr_limit)
static inline void set_fs(mm_segment_t fs)
@@ -76,6 +74,13 @@
current_thread_info()->addr_limit = fs;
/*
+ * Prevent a mispredicted conditional call to set_fs from forwarding
+ * the wrong address limit to access_ok under speculation.
+ */
+ dsb(nsh);
+ isb();
+
+ /*
* Enable/disable UAO so that copy_to_user() etc can access
* kernel memory with the unprivileged instructions.
*/
@@ -93,22 +98,32 @@
* Returns 1 if the range is valid, 0 otherwise.
*
* This is equivalent to the following test:
- * (u65)addr + (u65)size <= current->addr_limit
- *
- * This needs 65-bit arithmetic.
+ * (u65)addr + (u65)size <= (u65)current->addr_limit + 1
*/
-#define __range_ok(addr, size) \
-({ \
- unsigned long __addr = (unsigned long __force)(addr); \
- unsigned long flag, roksum; \
- __chk_user_ptr(addr); \
- asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \
- : "=&r" (flag), "=&r" (roksum) \
- : "1" (__addr), "Ir" (size), \
- "r" (current_thread_info()->addr_limit) \
- : "cc"); \
- flag; \
-})
+static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
+{
+ unsigned long limit = current_thread_info()->addr_limit;
+
+ __chk_user_ptr(addr);
+ asm volatile(
+ // A + B <= C + 1 for all A,B,C, in four easy steps:
+ // 1: X = A + B; X' = X % 2^64
+ " adds %0, %0, %2\n"
+ // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4
+ " csel %1, xzr, %1, hi\n"
+ // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X'
+ // to compensate for the carry flag being set in step 4. For
+ // X > 2^64, X' merely has to remain nonzero, which it does.
+ " csinv %0, %0, xzr, cc\n"
+ // 4: For X < 2^64, this gives us X' - C - 1 <= 0, where the -1
+ // comes from the carry in being clear. Otherwise, we are
+ // testing X' - C == 0, subject to the previous adjustments.
+ " sbcs xzr, %0, %1\n"
+ " cset %0, ls\n"
+ : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc");
+
+ return addr;
+}
/*
* When dealing with data aborts, watchpoints, or instruction traps we may end
@@ -117,7 +132,7 @@
*/
#define untagged_addr(addr) sign_extend64(addr, 55)
-#define access_ok(type, addr, size) __range_ok(addr, size)
+#define access_ok(type, addr, size) __range_ok((unsigned long)(addr), size)
#define user_addr_max get_fs
#define _ASM_EXTABLE(from, to) \
@@ -236,6 +251,26 @@
}
/*
+ * Sanitise a uaccess pointer such that it becomes NULL if above the
+ * current addr_limit.
+ */
+#define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr)
+static inline void __user *__uaccess_mask_ptr(const void __user *ptr)
+{
+ void __user *safe_ptr;
+
+ asm volatile(
+ " bics xzr, %1, %2\n"
+ " csel %0, %1, xzr, eq\n"
+ : "=&r" (safe_ptr)
+ : "r" (ptr), "r" (current_thread_info()->addr_limit)
+ : "cc");
+
+ csdb();
+ return safe_ptr;
+}
+
+/*
* The "__xxx" versions of the user access functions do not verify the address
* space - it must have been done previously with a separate "access_ok()"
* call.
@@ -287,29 +322,34 @@
(x) = (__force __typeof__(*(ptr)))__gu_val; \
} while (0)
-#define __get_user(x, ptr) \
+#define __get_user_check(x, ptr, err) \
({ \
- int __gu_err = 0; \
- __get_user_err((x), (ptr), __gu_err); \
- __gu_err; \
+ __typeof__(*(ptr)) __user *__p = (ptr); \
+ might_fault(); \
+ if (access_ok(VERIFY_READ, __p, sizeof(*__p))) { \
+ __p = uaccess_mask_ptr(__p); \
+ __get_user_err((x), __p, (err)); \
+ } else { \
+ (x) = 0; (err) = -EFAULT; \
+ } \
})
#define __get_user_error(x, ptr, err) \
({ \
- __get_user_err((x), (ptr), (err)); \
+ __get_user_check((x), (ptr), (err)); \
(void)0; \
})
+#define __get_user(x, ptr) \
+({ \
+ int __gu_err = 0; \
+ __get_user_check((x), (ptr), __gu_err); \
+ __gu_err; \
+})
+
#define __get_user_unaligned __get_user
-#define get_user(x, ptr) \
-({ \
- __typeof__(*(ptr)) __user *__p = (ptr); \
- might_fault(); \
- access_ok(VERIFY_READ, __p, sizeof(*__p)) ? \
- __get_user((x), __p) : \
- ((x) = 0, -EFAULT); \
-})
+#define get_user __get_user
#define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature) \
asm volatile( \
@@ -353,47 +393,51 @@
uaccess_disable_not_uao(); \
} while (0)
-#define __put_user(x, ptr) \
+#define __put_user_check(x, ptr, err) \
({ \
- int __pu_err = 0; \
- __put_user_err((x), (ptr), __pu_err); \
- __pu_err; \
+ __typeof__(*(ptr)) __user *__p = (ptr); \
+ might_fault(); \
+ if (access_ok(VERIFY_WRITE, __p, sizeof(*__p))) { \
+ __p = uaccess_mask_ptr(__p); \
+ __put_user_err((x), __p, (err)); \
+ } else { \
+ (err) = -EFAULT; \
+ } \
})
#define __put_user_error(x, ptr, err) \
({ \
- __put_user_err((x), (ptr), (err)); \
+ __put_user_check((x), (ptr), (err)); \
(void)0; \
})
+#define __put_user(x, ptr) \
+({ \
+ int __pu_err = 0; \
+ __put_user_check((x), (ptr), __pu_err); \
+ __pu_err; \
+})
+
#define __put_user_unaligned __put_user
-#define put_user(x, ptr) \
-({ \
- __typeof__(*(ptr)) __user *__p = (ptr); \
- might_fault(); \
- access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ? \
- __put_user((x), __p) : \
- -EFAULT; \
-})
+#define put_user __put_user
extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n);
extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n);
-extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n);
-extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n);
+extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n);
static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n)
{
kasan_check_write(to, n);
check_object_size(to, n, false);
- return __arch_copy_from_user(to, from, n);
+ return __arch_copy_from_user(to, __uaccess_mask_ptr(from), n);
}
static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n)
{
kasan_check_read(from, n);
check_object_size(from, n, true);
- return __arch_copy_to_user(to, from, n);
+ return __arch_copy_to_user(__uaccess_mask_ptr(to), from, n);
}
static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)
@@ -421,22 +465,25 @@
return n;
}
-static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n)
+static inline unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n))
- n = __copy_in_user(to, from, n);
+ n = __arch_copy_in_user(__uaccess_mask_ptr(to), __uaccess_mask_ptr(from), n);
return n;
}
+#define copy_in_user __copy_in_user
#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user
-static inline unsigned long __must_check clear_user(void __user *to, unsigned long n)
+extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n);
+static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n)
{
if (access_ok(VERIFY_WRITE, to, n))
- n = __clear_user(to, n);
+ n = __arch_clear_user(__uaccess_mask_ptr(to), n);
return n;
}
+#define clear_user __clear_user
extern long strncpy_from_user(char *dest, const char __user *src, long count);
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index dd918d0..ca1cf2d 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -38,8 +38,8 @@
/* user mem (segment) */
EXPORT_SYMBOL(__arch_copy_from_user);
EXPORT_SYMBOL(__arch_copy_to_user);
-EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(__copy_in_user);
+EXPORT_SYMBOL(__arch_clear_user);
+EXPORT_SYMBOL(__arch_copy_in_user);
/* physical memory */
EXPORT_SYMBOL(memstart_addr);
diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S
index dec95bd..746a203 100644
--- a/arch/arm64/kernel/bpi.S
+++ b/arch/arm64/kernel/bpi.S
@@ -17,6 +17,7 @@
*/
#include <linux/linkage.h>
+#include <linux/arm-smccc.h>
.macro ventry target
.rept 31
@@ -53,6 +54,7 @@
vectors __kvm_hyp_vector
.endr
ENTRY(__bp_harden_hyp_vecs_end)
+
ENTRY(__psci_hyp_bp_inval_start)
sub sp, sp, #(8 * 18)
stp x16, x17, [sp, #(16 * 0)]
@@ -77,3 +79,23 @@
ldp x0, x1, [sp, #(16 * 8)]
add sp, sp, #(8 * 18)
ENTRY(__psci_hyp_bp_inval_end)
+
+.macro smccc_workaround_1 inst
+ sub sp, sp, #(8 * 4)
+ stp x2, x3, [sp, #(8 * 0)]
+ stp x0, x1, [sp, #(8 * 2)]
+ mov w0, #ARM_SMCCC_ARCH_WORKAROUND_1
+ \inst #0
+ ldp x2, x3, [sp, #(8 * 0)]
+ ldp x0, x1, [sp, #(8 * 2)]
+ add sp, sp, #(8 * 4)
+.endm
+
+ENTRY(__smccc_workaround_1_smc_start)
+ smccc_workaround_1 smc
+ENTRY(__smccc_workaround_1_smc_end)
+
+ENTRY(__smccc_workaround_1_hvc_start)
+ smccc_workaround_1 hvc
+ENTRY(__smccc_workaround_1_hvc_end)
+.#endif
diff --git a/arch/arm64/kernel/cpu-reset.S b/arch/arm64/kernel/cpu-reset.S
index 65f42d2..f736a6f 100644
--- a/arch/arm64/kernel/cpu-reset.S
+++ b/arch/arm64/kernel/cpu-reset.S
@@ -16,7 +16,7 @@
#include <asm/virt.h>
.text
-.pushsection .idmap.text, "ax"
+.pushsection .idmap.text, "awx"
/*
* __cpu_soft_restart(el2_switch, entry, arg0, arg1, arg2) - Helper for
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 7c8e185..49e548f 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -54,11 +54,15 @@
#ifdef CONFIG_KVM
extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[];
+extern char __smccc_workaround_1_smc_start[];
+extern char __smccc_workaround_1_smc_end[];
+extern char __smccc_workaround_1_hvc_start[];
+extern char __smccc_workaround_1_hvc_end[];
static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start,
const char *hyp_vecs_end)
{
- void *dst = lm_alias(__bp_harden_hyp_vecs_start + slot * SZ_2K);
+ void *dst = __bp_harden_hyp_vecs_start + slot * SZ_2K;
int i;
for (i = 0; i < SZ_2K; i += 0x80)
@@ -98,6 +102,10 @@
#else
#define __psci_hyp_bp_inval_start NULL
#define __psci_hyp_bp_inval_end NULL
+#define __smccc_workaround_1_smc_start NULL
+#define __smccc_workaround_1_smc_end NULL
+#define __smccc_workaround_1_hvc_start NULL
+#define __smccc_workaround_1_hvc_end NULL
static void __install_bp_hardening_cb(bp_hardening_cb_t fn,
const char *hyp_vecs_start,
@@ -124,8 +132,11 @@
__install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end);
}
+#include <uapi/linux/psci.h>
+#include <linux/arm-smccc.h>
#include <linux/psci.h>
+#ifdef CONFIG_PSCI_BP_HARDENING
static int enable_psci_bp_hardening(void *data)
{
const struct arm64_cpu_capabilities *entry = data;
@@ -135,6 +146,59 @@
(bp_hardening_cb_t)psci_ops.get_version,
__psci_hyp_bp_inval_start,
__psci_hyp_bp_inval_end);
+ return 0;
+}
+#endif
+
+static void call_smc_arch_workaround_1(void)
+{
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static void call_hvc_arch_workaround_1(void)
+{
+ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
+}
+
+static int enable_smccc_arch_workaround_1(void *data)
+{
+ const struct arm64_cpu_capabilities *entry = data;
+ bp_hardening_cb_t cb;
+ void *smccc_start, *smccc_end;
+ struct arm_smccc_res res;
+
+ if (!entry->matches(entry, SCOPE_LOCAL_CPU))
+ return 0;
+
+ if (psci_ops.smccc_version == SMCCC_VERSION_1_0)
+ return 0;
+
+ switch (psci_ops.conduit) {
+ case PSCI_CONDUIT_HVC:
+ arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+ if (res.a0)
+ return 0;
+ cb = call_hvc_arch_workaround_1;
+ smccc_start = __smccc_workaround_1_hvc_start;
+ smccc_end = __smccc_workaround_1_hvc_end;
+ break;
+
+ case PSCI_CONDUIT_SMC:
+ arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+ ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+ if (res.a0)
+ return 0;
+ cb = call_smc_arch_workaround_1;
+ smccc_start = __smccc_workaround_1_smc_start;
+ smccc_end = __smccc_workaround_1_smc_end;
+ break;
+
+ default:
+ return 0;
+ }
+
+ install_bp_hardening_cb(entry, cb, smccc_start, smccc_end);
return 0;
}
@@ -238,32 +302,50 @@
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
- .enable = enable_psci_bp_hardening,
+ .enable = enable_smccc_arch_workaround_1,
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
- .enable = enable_psci_bp_hardening,
+ .enable = enable_smccc_arch_workaround_1,
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
- .enable = enable_psci_bp_hardening,
+ .enable = enable_smccc_arch_workaround_1,
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
- .enable = enable_psci_bp_hardening,
+ .enable = enable_smccc_arch_workaround_1,
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_KRYO3G),
+#ifdef CONFIG_PSCI_BP_HARDENING
.enable = enable_psci_bp_hardening,
+#else
+ .enable = enable_smccc_arch_workaround_1,
+#endif
},
{
.capability = ARM64_HARDEN_BRANCH_PREDICTOR,
MIDR_ALL_VERSIONS(MIDR_KRYO2XX_GOLD),
+#ifdef CONFIG_PSCI_BP_HARDENING
.enable = enable_psci_bp_hardening,
+#else
+ .enable = enable_smccc_arch_workaround_1,
+#endif
+ },
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
+ .enable = enable_smccc_arch_workaround_1,
+ },
+ {
+ .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+ MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2),
+ .enable = enable_smccc_arch_workaround_1,
},
#endif
{
@@ -279,15 +361,18 @@
{
const struct arm64_cpu_capabilities *caps = arm64_errata;
- for (; caps->matches; caps++)
- if (!cpus_have_cap(caps->capability) &&
- caps->matches(caps, SCOPE_LOCAL_CPU)) {
+ for (; caps->matches; caps++) {
+ if (cpus_have_cap(caps->capability)) {
+ if (caps->enable)
+ caps->enable((void *)caps);
+ } else if (caps->matches(caps, SCOPE_LOCAL_CPU)) {
pr_crit("CPU%d: Requires work around for %s, not detected"
" at boot time\n",
smp_processor_id(),
caps->desc ? : "an erratum");
cpu_die_early();
}
+ }
}
void update_cpu_errata_workarounds(void)
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 5cf4c64..675bf45 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -95,12 +95,13 @@
};
static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = {
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
+ ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0),
+ ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 24, 0),
ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0),
ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0),
S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI),
S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_FP_SHIFT, 4, ID_AA64PFR0_FP_NI),
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0),
/* Linux doesn't care about the EL3 */
ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, ID_AA64PFR0_EL3_SHIFT, 4, 0),
ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_EL2_SHIFT, 4, 0),
@@ -753,12 +754,23 @@
static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry,
int __unused)
{
+ char const *str = "command line option";
u64 pfr0 = read_system_reg(SYS_ID_AA64PFR0_EL1);
- /* Forced on command line? */
+ /*
+ * For reasons that aren't entirely clear, enabling KPTI on Cavium
+ * 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)) {
+ str = "ARM64_WORKAROUND_CAVIUM_27456";
+ __kpti_forced = -1;
+ }
+
+ /* Forced? */
if (__kpti_forced) {
- pr_info_once("kernel page table isolation forced %s by command line option\n",
- __kpti_forced > 0 ? "ON" : "OFF");
+ pr_info_once("kernel page table isolation forced %s by %s\n",
+ __kpti_forced > 0 ? "ON" : "OFF", str);
return __kpti_forced > 0;
}
@@ -766,11 +778,42 @@
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE))
return true;
+ /* Don't force KPTI for CPUs that are not vulnerable */
+ switch (read_cpuid_id() & MIDR_CPU_MODEL_MASK) {
+ case MIDR_CAVIUM_THUNDERX2:
+ case MIDR_BRCM_VULCAN:
+ return false;
+ }
+
/* Defer to CPU feature registers */
return !cpuid_feature_extract_unsigned_field(pfr0,
ID_AA64PFR0_CSV3_SHIFT);
}
+static int __nocfi kpti_install_ng_mappings(void *__unused)
+{
+ typedef void (kpti_remap_fn)(int, int, phys_addr_t);
+ extern kpti_remap_fn idmap_kpti_install_ng_mappings;
+ kpti_remap_fn *remap_fn;
+
+ static bool kpti_applied = false;
+ int cpu = smp_processor_id();
+
+ if (kpti_applied)
+ return 0;
+
+ remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
+
+ cpu_install_idmap();
+ remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir));
+ cpu_uninstall_idmap();
+
+ if (!cpu)
+ kpti_applied = true;
+
+ return 0;
+}
+
static int __init parse_kpti(char *str)
{
bool enabled;
@@ -874,6 +917,7 @@
.capability = ARM64_UNMAP_KERNEL_AT_EL0,
.def_scope = SCOPE_SYSTEM,
.matches = unmap_kernel_at_el0,
+ .enable = kpti_install_ng_mappings,
},
#endif
{},
@@ -969,6 +1013,25 @@
cap_set_elf_hwcap(hwcaps);
}
+/*
+ * Check if the current CPU has a given feature capability.
+ * Should be called from non-preemptible context.
+ */
+static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array,
+ unsigned int cap)
+{
+ const struct arm64_cpu_capabilities *caps;
+
+ if (WARN_ON(preemptible()))
+ return false;
+
+ for (caps = cap_array; caps->matches; caps++)
+ if (caps->capability == cap &&
+ caps->matches(caps, SCOPE_LOCAL_CPU))
+ return true;
+ return false;
+}
+
void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
const char *info)
{
@@ -1037,8 +1100,9 @@
}
static void
-verify_local_cpu_features(const struct arm64_cpu_capabilities *caps)
+verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list)
{
+ const struct arm64_cpu_capabilities *caps = caps_list;
for (; caps->matches; caps++) {
if (!cpus_have_cap(caps->capability))
continue;
@@ -1046,7 +1110,7 @@
* If the new CPU misses an advertised feature, we cannot proceed
* further, park the cpu.
*/
- if (!caps->matches(caps, SCOPE_LOCAL_CPU)) {
+ if (!__this_cpu_has_cap(caps_list, caps->capability)) {
pr_crit("CPU%d: missing feature: %s\n",
smp_processor_id(), caps->desc);
cpu_die_early();
@@ -1099,22 +1163,12 @@
enable_cpu_capabilities(arm64_features);
}
-/*
- * Check if the current CPU has a given feature capability.
- * Should be called from non-preemptible context.
- */
+extern const struct arm64_cpu_capabilities arm64_errata[];
+
bool this_cpu_has_cap(unsigned int cap)
{
- const struct arm64_cpu_capabilities *caps;
-
- if (WARN_ON(preemptible()))
- return false;
-
- for (caps = arm64_features; caps->desc; caps++)
- if (caps->capability == cap && caps->matches)
- return caps->matches(caps, SCOPE_LOCAL_CPU);
-
- return false;
+ return (__this_cpu_has_cap(arm64_features, cap) ||
+ __this_cpu_has_cap(arm64_errata, cap));
}
void __init setup_cpu_features(void)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index f8ba35d..7613ed1 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -30,11 +30,13 @@
#include <asm/irq.h>
#include <asm/memory.h>
#include <asm/mmu.h>
+#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
#include <asm/uaccess.h>
#include <asm/asm-uaccess.h>
#include <asm/unistd.h>
+#include <asm/kernel-pgtable.h>
/*
* Context tracking subsystem. Used to instrument transitions
@@ -125,10 +127,10 @@
.else
add x21, sp, #S_FRAME_SIZE
get_thread_info tsk
- /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */
+ /* Save the task's original addr_limit and set USER_DS */
ldr x20, [tsk, #TSK_TI_ADDR_LIMIT]
str x20, [sp, #S_ORIG_ADDR_LIMIT]
- mov x20, #TASK_SIZE_64
+ mov x20, #USER_DS
str x20, [tsk, #TSK_TI_ADDR_LIMIT]
/* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */
.endif /* \el == 0 */
@@ -668,8 +670,7 @@
* Instruction abort handling
*/
mrs x26, far_el1
- // enable interrupts before calling the main handler
- enable_dbg_and_irq
+ msr daifclr, #(8 | 4 | 1)
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
@@ -704,8 +705,10 @@
* Stack or PC alignment exception handling
*/
mrs x26, far_el1
- // enable interrupts before calling the main handler
- enable_dbg_and_irq
+ enable_dbg
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl trace_hardirqs_off
+#endif
ct_user_exit
mov x0, x26
mov x1, x25
@@ -764,6 +767,11 @@
#endif
ct_user_exit
+#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
+ tbz x22, #55, 1f
+ bl do_el0_irq_bp_hardening
+1:
+#endif
irq_handler
#ifdef CONFIG_TRACE_IRQFLAGS
@@ -876,6 +884,7 @@
b.ne __sys_trace
cmp scno, sc_nr // check upper syscall limit
b.hs ni_sys
+ mask_nospec64 scno, sc_nr, x19 // enforce bounds for syscall number
ldr x16, [stbl, scno, lsl #3] // address in the syscall table
blr x16 // call sys_* routine
b ret_fast_syscall
@@ -953,16 +962,9 @@
orr \tmp, \tmp, #USER_ASID_FLAG
msr ttbr1_el1, \tmp
/*
- * We avoid running the post_ttbr_update_workaround here because the
- * user and kernel ASIDs don't have conflicting mappings, so any
- * "blessing" as described in:
- *
- * http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com
- *
- * will not hurt correctness. Whilst this may partially defeat the
- * point of using split ASIDs in the first place, it avoids
- * the hit of invalidating the entire I-cache on every return to
- * userspace.
+ * We avoid running the post_ttbr_update_workaround here because
+ * it's only needed by Cavium ThunderX, which requires KPTI to be
+ * disabled.
*/
.endm
@@ -972,6 +974,11 @@
.if \regsize == 64
msr tpidrro_el0, x30 // Restored in kernel_ventry
.endif
+ /*
+ * Defend against branch aliasing attacks by pushing a dummy
+ * entry onto the return stack and using a RET instruction to
+ * enter the full-fat kernel vectors.
+ */
bl 2f
b .
2:
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index c186586..d479185 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -474,7 +474,7 @@
* end early head section, begin head code that is also used for
* hotplug and needs to have the same protections as the text region
*/
- .section ".idmap.text","ax"
+ .section ".idmap.text","awx"
ENTRY(kimage_vaddr)
.quad _text - TEXT_OFFSET
diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c
index 409abc4..1b3eb67 100644
--- a/arch/arm64/kernel/pci.c
+++ b/arch/arm64/kernel/pci.c
@@ -175,8 +175,10 @@
return NULL;
root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node);
- if (!root_ops)
+ if (!root_ops) {
+ kfree(ri);
return NULL;
+ }
ri->cfg = pci_acpi_setup_ecam_mapping(root);
if (!ri->cfg) {
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 52710f1..e0b731e 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -869,15 +869,23 @@
{
unsigned long config_base = 0;
- if (is_kernel_in_hyp_mode() &&
- attr->exclude_kernel != attr->exclude_hv)
- return -EINVAL;
+ /*
+ * If we're running in hyp mode, then we *are* the hypervisor.
+ * Therefore we ignore exclude_hv in this configuration, since
+ * there's no hypervisor to sample anyway. This is consistent
+ * with other architectures (x86 and Power).
+ */
+ if (is_kernel_in_hyp_mode()) {
+ if (!attr->exclude_kernel)
+ config_base |= ARMV8_PMU_INCLUDE_EL2;
+ } else {
+ if (attr->exclude_kernel)
+ config_base |= ARMV8_PMU_EXCLUDE_EL1;
+ if (!attr->exclude_hv)
+ config_base |= ARMV8_PMU_INCLUDE_EL2;
+ }
if (attr->exclude_user)
config_base |= ARMV8_PMU_EXCLUDE_EL0;
- if (!is_kernel_in_hyp_mode() && attr->exclude_kernel)
- config_base |= ARMV8_PMU_EXCLUDE_EL1;
- if (!attr->exclude_hv)
- config_base |= ARMV8_PMU_INCLUDE_EL2;
/*
* Install the filter into config_base as this is used to
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index ee0ea17..08ca9dc 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -213,7 +213,7 @@
for (j = 0; j < 8; j++) {
u32 data;
if (probe_kernel_address(p, data)) {
- printk(" ********");
+ pr_cont(" ********");
} else {
pr_cont(" %08x", data);
}
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index df67652..5a4fbcc 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -95,7 +95,7 @@
ret
ENDPROC(__cpu_suspend_enter)
- .pushsection ".idmap.text", "ax"
+ .pushsection ".idmap.text", "awx"
ENTRY(cpu_resume)
bl el2_setup // if in EL2 drop to EL1 cleanly
bl __cpu_setup
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 2e6e9e9..efe43c5 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -22,12 +22,15 @@
#include <linux/kvm.h>
#include <linux/kvm_host.h>
+#include <kvm/arm_psci.h>
+
#include <asm/esr.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_coproc.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
-#include <asm/kvm_psci.h>
+#include <asm/debug-monitors.h>
+#include <asm/traps.h>
#define CREATE_TRACE_POINTS
#include "trace.h"
@@ -42,7 +45,7 @@
kvm_vcpu_hvc_get_imm(vcpu));
vcpu->stat.hvc_exit_stat++;
- ret = kvm_psci_call(vcpu);
+ ret = kvm_hvc_call_handler(vcpu);
if (ret < 0) {
vcpu_set_reg(vcpu, 0, ~0UL);
return 1;
@@ -53,7 +56,16 @@
static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
+ /*
+ * "If an SMC instruction executed at Non-secure EL1 is
+ * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a
+ * Trap exception, not a Secure Monitor Call exception [...]"
+ *
+ * We need to advance the PC after the trap, as it would
+ * otherwise return to the same address...
+ */
vcpu_set_reg(vcpu, 0, ~0UL);
+ kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu));
return 1;
}
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 4e92399..4e9d50c 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -15,6 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/arm-smccc.h>
#include <linux/linkage.h>
#include <asm/alternative.h>
@@ -79,10 +80,11 @@
lsr x0, x1, #ESR_ELx_EC_SHIFT
cmp x0, #ESR_ELx_EC_HVC64
+ ccmp x0, #ESR_ELx_EC_HVC32, #4, ne
b.ne el1_trap
- mrs x1, vttbr_el2 // If vttbr is valid, the 64bit guest
- cbnz x1, el1_trap // called HVC
+ mrs x1, vttbr_el2 // If vttbr is valid, the guest
+ cbnz x1, el1_hvc_guest // called HVC
/* Here, we're pretty sure the host called HVC. */
ldp x0, x1, [sp], #16
@@ -101,6 +103,20 @@
2: eret
+el1_hvc_guest:
+ /*
+ * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1.
+ * The workaround has already been applied on the host,
+ * so let's quickly get back to the guest. We don't bother
+ * restoring x1, as it can be clobbered anyway.
+ */
+ ldr x1, [sp] // Guest's x0
+ eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1
+ cbnz w1, el1_trap
+ mov x0, x1
+ add sp, sp, #16
+ eret
+
el1_trap:
/*
* x0: ESR_EC
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 3eab6ac..849ee8a 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -19,6 +19,8 @@
#include <linux/jump_label.h>
#include <uapi/linux/psci.h>
+#include <kvm/arm_psci.h>
+
#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>
@@ -311,14 +313,16 @@
if (exit_code == ARM_EXCEPTION_TRAP &&
(kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 ||
- kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) &&
- vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) {
- u64 val = PSCI_RET_NOT_SUPPORTED;
- if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
- val = 2;
+ kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32)) {
+ u32 val = vcpu_get_reg(vcpu, 0);
- vcpu_set_reg(vcpu, 0, val);
- goto again;
+ if (val == PSCI_0_2_FN_PSCI_VERSION) {
+ val = kvm_psci_version(vcpu, kern_hyp_va(vcpu->kvm));
+ if (unlikely(val == KVM_ARM_PSCI_0_1))
+ val = PSCI_RET_NOT_SUPPORTED;
+ vcpu_set_reg(vcpu, 0, val);
+ goto again;
+ }
}
if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
@@ -417,6 +421,7 @@
vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+ __timer_save_state(vcpu);
__deactivate_traps(vcpu);
__deactivate_vm(vcpu);
__sysreg_restore_host_state(host_ctxt);
diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S
index 07c7ad9..b581e16 100644
--- a/arch/arm64/lib/clear_user.S
+++ b/arch/arm64/lib/clear_user.S
@@ -21,7 +21,7 @@
.text
-/* Prototype: int __clear_user(void *addr, size_t sz)
+/* Prototype: int __arch_clear_user(void *addr, size_t sz)
* Purpose : clear some user memory
* Params : addr - user memory address to clear
* : sz - number of bytes to clear
@@ -29,7 +29,7 @@
*
* Alignment fixed up by hardware.
*/
-ENTRY(__clear_user)
+ENTRY(__arch_clear_user)
uaccess_enable_not_uao x2, x3, x4
mov x2, x1 // save the size for fixup return
subs x1, x1, #8
@@ -52,7 +52,7 @@
5: mov x0, #0
uaccess_disable_not_uao x2, x3
ret
-ENDPROC(__clear_user)
+ENDPROC(__arch_clear_user)
.section .fixup,"ax"
.align 2
diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S
index e8bfaf1..800779e 100644
--- a/arch/arm64/lib/copy_in_user.S
+++ b/arch/arm64/lib/copy_in_user.S
@@ -64,14 +64,14 @@
.endm
end .req x5
-ENTRY(__copy_in_user)
+ENTRY(__arch_copy_in_user)
uaccess_enable_not_uao x3, x4, x5
add end, x0, x2
#include "copy_template.S"
uaccess_disable_not_uao x3, x4
mov x0, #0
ret
-ENDPROC(__copy_in_user)
+ENDPROC(__arch_copy_in_user)
.section .fixup,"ax"
.align 2
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 2b8950e..6befc9c 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -343,7 +343,7 @@
mm_flags |= FAULT_FLAG_WRITE;
}
- if (addr < USER_DS && is_permission_fault(esr, regs)) {
+ if (addr < TASK_SIZE && is_permission_fault(esr, regs)) {
/* regs->orig_addr_limit may be 0 if we entered from EL0 */
if (regs->orig_addr_limit == KERNEL_DS)
die("Accessing user space memory with fs=KERNEL_DS", regs, esr);
@@ -618,6 +618,12 @@
arm64_notify_die("", regs, &info, esr);
}
+asmlinkage void __exception do_el0_irq_bp_hardening(void)
+{
+ /* PC has already been checked in entry.S */
+ arm64_apply_bp_hardening();
+}
+
asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr,
unsigned int esr,
struct pt_regs *regs)
@@ -644,6 +650,12 @@
struct siginfo info;
struct task_struct *tsk = current;
+ if (user_mode(regs)) {
+ if (instruction_pointer(regs) > TASK_SIZE)
+ arm64_apply_bp_hardening();
+ local_irq_enable();
+ }
+
if (show_unhandled_signals && unhandled_signal(tsk, SIGBUS))
pr_info_ratelimited("%s[%d]: %s exception: pc=%p sp=%p\n",
tsk->comm, task_pid_nr(tsk),
@@ -703,6 +715,9 @@
if (interrupts_enabled(regs))
trace_hardirqs_off();
+ if (user_mode(regs) && instruction_pointer(regs) > TASK_SIZE)
+ arm64_apply_bp_hardening();
+
if (!inf->fn(addr, esr, regs)) {
rv = 1;
} else {
diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c
index 01c1717..caf75ab 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -18,6 +18,7 @@
#include <linux/elf.h>
#include <linux/fs.h>
+#include <linux/memblock.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/export.h>
@@ -102,12 +103,18 @@
*/
int valid_phys_addr_range(phys_addr_t addr, size_t size)
{
- if (addr < PHYS_OFFSET)
- return 0;
- if (addr + size > __pa(high_memory - 1) + 1)
- return 0;
-
- return 1;
+ /*
+ * Check whether addr is covered by a memory region without the
+ * MEMBLOCK_NOMAP attribute, and whether that region covers the
+ * entire range. In theory, this could lead to false negatives
+ * if the range is covered by distinct but adjacent memory regions
+ * that only differ in other attributes. However, few of such
+ * attributes have been defined, and it is debatable whether it
+ * follows that /dev/mem read() calls should be able traverse
+ * such boundaries.
+ */
+ return memblock_is_region_memory(addr, size) &&
+ memblock_is_map_memory(addr);
}
/*
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index e7bf3c3..6e989eb 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -466,7 +466,7 @@
{
extern char __entry_tramp_text_start[];
- pgprot_t prot = PAGE_KERNEL_EXEC;
+ pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
/* The trampoline is always mapped and can therefore be global */
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 2e69a14..3a9af60 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -132,7 +132,7 @@
*
* x0: Address of context pointer
*/
- .pushsection ".idmap.text", "ax"
+ .pushsection ".idmap.text", "awx"
ENTRY(cpu_do_resume)
ldp x2, x3, [x0]
ldp x4, x5, [x0, #16]
@@ -197,7 +197,17 @@
b post_ttbr_update_workaround // Back to C code...
ENDPROC(cpu_do_switch_mm)
- .pushsection ".idmap.text", "ax"
+ .pushsection ".idmap.text", "awx"
+
+.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2
+ adrp \tmp1, empty_zero_page
+ msr ttbr1_el1, \tmp1
+ isb
+ tlbi vmalle1
+ dsb nsh
+ isb
+.endm
+
/*
* void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd)
*
@@ -208,13 +218,7 @@
mrs x2, daif
msr daifset, #0xf
- adrp x1, empty_zero_page
- msr ttbr1_el1, x1
- isb
-
- tlbi vmalle1
- dsb nsh
- isb
+ __idmap_cpu_set_reserved_ttbr1 x1, x3
msr ttbr1_el1, x0
isb
@@ -225,13 +229,196 @@
ENDPROC(idmap_cpu_replace_ttbr1)
.popsection
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+ .pushsection ".idmap.text", "awx"
+
+ .macro __idmap_kpti_get_pgtable_ent, type
+ dc cvac, cur_\()\type\()p // Ensure any existing dirty
+ dmb sy // lines are written back before
+ ldr \type, [cur_\()\type\()p] // loading the entry
+ tbz \type, #0, next_\()\type // Skip invalid entries
+ .endm
+
+ .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.
+ .endm
+
+/*
+ * void __kpti_install_ng_mappings(int cpu, int num_cpus, phys_addr_t swapper)
+ *
+ * Called exactly once from stop_machine context by each CPU found during boot.
+ */
+__idmap_kpti_flag:
+ .long 1
+ENTRY(idmap_kpti_install_ng_mappings)
+ cpu .req w0
+ num_cpus .req w1
+ swapper_pa .req x2
+ swapper_ttb .req x3
+ flag_ptr .req x4
+ cur_pgdp .req x5
+ end_pgdp .req x6
+ pgd .req x7
+ cur_pudp .req x8
+ end_pudp .req x9
+ pud .req x10
+ cur_pmdp .req x11
+ end_pmdp .req x12
+ pmd .req x13
+ cur_ptep .req x14
+ end_ptep .req x15
+ pte .req x16
+
+ mrs swapper_ttb, ttbr1_el1
+ adr flag_ptr, __idmap_kpti_flag
+
+ cbnz cpu, __idmap_kpti_secondary
+
+ /* We're the boot CPU. Wait for the others to catch up */
+ sevl
+1: wfe
+ ldaxr w18, [flag_ptr]
+ eor w18, w18, num_cpus
+ cbnz w18, 1b
+
+ /* We need to walk swapper, so turn off the MMU. */
+ mrs x18, sctlr_el1
+ bic x18, x18, #SCTLR_ELx_M
+ msr sctlr_el1, x18
+ isb
+
+ /* Everybody is enjoying the idmap, so we can rewrite swapper. */
+ /* PGD */
+ mov cur_pgdp, swapper_pa
+ add end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8)
+do_pgd: __idmap_kpti_get_pgtable_ent pgd
+ tbnz pgd, #1, walk_puds
+ __idmap_kpti_put_pgtable_ent_ng pgd
+next_pgd:
+ add cur_pgdp, cur_pgdp, #8
+ cmp cur_pgdp, end_pgdp
+ b.ne do_pgd
+
+ /* Publish the updated tables and nuke all the TLBs */
+ dsb sy
+ tlbi vmalle1is
+ dsb ish
+ isb
+
+ /* We're done: fire up the MMU again */
+ mrs x18, sctlr_el1
+ orr x18, x18, #SCTLR_ELx_M
+ msr sctlr_el1, x18
+ isb
+
+ /* Set the flag to zero to indicate that we're all done */
+ str wzr, [flag_ptr]
+ ret
+
+ /* PUD */
+walk_puds:
+ .if CONFIG_PGTABLE_LEVELS > 3
+ pte_to_phys cur_pudp, pgd
+ add end_pudp, cur_pudp, #(PTRS_PER_PUD * 8)
+do_pud: __idmap_kpti_get_pgtable_ent pud
+ tbnz pud, #1, walk_pmds
+ __idmap_kpti_put_pgtable_ent_ng pud
+next_pud:
+ add cur_pudp, cur_pudp, 8
+ cmp cur_pudp, end_pudp
+ b.ne do_pud
+ b next_pgd
+ .else /* CONFIG_PGTABLE_LEVELS <= 3 */
+ mov pud, pgd
+ b walk_pmds
+next_pud:
+ b next_pgd
+ .endif
+
+ /* PMD */
+walk_pmds:
+ .if CONFIG_PGTABLE_LEVELS > 2
+ pte_to_phys cur_pmdp, pud
+ add end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8)
+do_pmd: __idmap_kpti_get_pgtable_ent pmd
+ tbnz pmd, #1, walk_ptes
+ __idmap_kpti_put_pgtable_ent_ng pmd
+next_pmd:
+ add cur_pmdp, cur_pmdp, #8
+ cmp cur_pmdp, end_pmdp
+ b.ne do_pmd
+ b next_pud
+ .else /* CONFIG_PGTABLE_LEVELS <= 2 */
+ mov pmd, pud
+ b walk_ptes
+next_pmd:
+ b next_pud
+ .endif
+
+ /* PTE */
+walk_ptes:
+ pte_to_phys cur_ptep, pmd
+ add end_ptep, cur_ptep, #(PTRS_PER_PTE * 8)
+do_pte: __idmap_kpti_get_pgtable_ent pte
+ __idmap_kpti_put_pgtable_ent_ng pte
+next_pte:
+ add cur_ptep, cur_ptep, #8
+ cmp cur_ptep, end_ptep
+ b.ne do_pte
+ b next_pmd
+
+ /* Secondary CPUs end up here */
+__idmap_kpti_secondary:
+ /* Uninstall swapper before surgery begins */
+ __idmap_cpu_set_reserved_ttbr1 x18, x17
+
+ /* Increment the flag to let the boot CPU we're ready */
+1: ldxr w18, [flag_ptr]
+ add w18, w18, #1
+ stxr w17, w18, [flag_ptr]
+ cbnz w17, 1b
+
+ /* Wait for the boot CPU to finish messing around with swapper */
+ sevl
+1: wfe
+ ldxr w18, [flag_ptr]
+ cbnz w18, 1b
+
+ /* All done, act like nothing happened */
+ msr ttbr1_el1, swapper_ttb
+ isb
+ ret
+
+ .unreq cpu
+ .unreq num_cpus
+ .unreq swapper_pa
+ .unreq swapper_ttb
+ .unreq flag_ptr
+ .unreq cur_pgdp
+ .unreq end_pgdp
+ .unreq pgd
+ .unreq cur_pudp
+ .unreq end_pudp
+ .unreq pud
+ .unreq cur_pmdp
+ .unreq end_pmdp
+ .unreq pmd
+ .unreq cur_ptep
+ .unreq end_ptep
+ .unreq pte
+ENDPROC(idmap_kpti_install_ng_mappings)
+ .popsection
+#endif
+
/*
* __cpu_setup
*
* Initialise the processor for turning the MMU on. Return in x0 the
* value of the SCTLR_EL1 register.
*/
- .pushsection ".idmap.text", "ax"
+ .pushsection ".idmap.text", "awx"
ENTRY(__cpu_setup)
tlbi vmalle1 // Invalidate local TLB
dsb nsh
diff --git a/arch/frv/include/asm/timex.h b/arch/frv/include/asm/timex.h
index a89bdde..139093f 100644
--- a/arch/frv/include/asm/timex.h
+++ b/arch/frv/include/asm/timex.h
@@ -16,5 +16,11 @@
#define vxtime_lock() do {} while (0)
#define vxtime_unlock() do {} while (0)
+/* This attribute is used in include/linux/jiffies.h alongside with
+ * __cacheline_aligned_in_smp. It is assumed that __cacheline_aligned_in_smp
+ * for frv does not contain another section specification.
+ */
+#define __jiffy_arch_data __attribute__((__section__(".data")))
+
#endif
diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h
index daba1f9..174aedc 100644
--- a/arch/mips/include/asm/kprobes.h
+++ b/arch/mips/include/asm/kprobes.h
@@ -40,7 +40,8 @@
#define flush_insn_slot(p) \
do { \
- flush_icache_range((unsigned long)p->addr, \
+ if (p->addr) \
+ flush_icache_range((unsigned long)p->addr, \
(unsigned long)p->addr + \
(MAX_INSN_SIZE * sizeof(kprobe_opcode_t))); \
} while (0)
diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h
index d21f3da..c0be540 100644
--- a/arch/mips/include/asm/pgtable-32.h
+++ b/arch/mips/include/asm/pgtable-32.h
@@ -18,6 +18,10 @@
#include <asm-generic/pgtable-nopmd.h>
+#ifdef CONFIG_HIGHMEM
+#include <asm/highmem.h>
+#endif
+
extern int temp_tlb_entry;
/*
@@ -61,7 +65,8 @@
#define VMALLOC_START MAP_BASE
-#define PKMAP_BASE (0xfe000000UL)
+#define PKMAP_END ((FIXADDR_START) & ~((LAST_PKMAP << PAGE_SHIFT)-1))
+#define PKMAP_BASE (PKMAP_END - PAGE_SIZE * LAST_PKMAP)
#ifdef CONFIG_HIGHMEM
# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE)
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index 89fa5c0b..c92f4c2 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -1257,6 +1257,13 @@
{
__kernel_size_t res;
+#ifdef CONFIG_CPU_MICROMIPS
+/* micromips memset / bzero also clobbers t7 & t8 */
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31"
+#else
+#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"
+#endif /* CONFIG_CPU_MICROMIPS */
+
if (eva_kernel_access()) {
__asm__ __volatile__(
"move\t$4, %1\n\t"
@@ -1266,7 +1273,7 @@
"move\t%0, $6"
: "=r" (res)
: "r" (addr), "r" (size)
- : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ : bzero_clobbers);
} else {
might_fault();
__asm__ __volatile__(
@@ -1277,7 +1284,7 @@
"move\t%0, $6"
: "=r" (res)
: "r" (addr), "r" (size)
- : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ : bzero_clobbers);
}
return res;
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index 18a1ccd..2b1bf93 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -218,7 +218,7 @@
1: PTR_ADDIU a0, 1 /* fill bytewise */
R10KCBARRIER(0(ra))
bne t1, a0, 1b
- sb a1, -1(a0)
+ EX(sb, a1, -1(a0), .Lsmall_fixup\@)
2: jr ra /* done */
move a2, zero
@@ -251,13 +251,18 @@
PTR_L t0, TI_TASK($28)
andi a2, STORMASK
LONG_L t0, THREAD_BUADDR(t0)
- LONG_ADDU a2, t1
+ LONG_ADDU a2, a0
jr ra
LONG_SUBU a2, t0
.Llast_fixup\@:
jr ra
- andi v1, a2, STORMASK
+ nop
+
+.Lsmall_fixup\@:
+ PTR_SUBU a2, t1, a0
+ jr ra
+ PTR_ADDIU a2, 1
.endm
diff --git a/arch/mips/mm/pgtable-32.c b/arch/mips/mm/pgtable-32.c
index adc6911..b19a3c5 100644
--- a/arch/mips/mm/pgtable-32.c
+++ b/arch/mips/mm/pgtable-32.c
@@ -51,15 +51,15 @@
/*
* Fixed mappings:
*/
- vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
- fixrange_init(vaddr, vaddr + FIXADDR_SIZE, pgd_base);
+ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1);
+ fixrange_init(vaddr & PMD_MASK, vaddr + FIXADDR_SIZE, pgd_base);
#ifdef CONFIG_HIGHMEM
/*
* Permanent kmaps:
*/
vaddr = PKMAP_BASE;
- fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+ fixrange_init(vaddr & PMD_MASK, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
pgd = swapper_pg_dir + __pgd_offset(vaddr);
pud = pud_offset(pgd, vaddr);
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 700e2d2..2e68ca1 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -648,6 +648,10 @@
(modpath->mod == PCI_FUNC(devfn)));
}
+ /* index might be out of bounds for bc[] */
+ if (index >= 6)
+ return 0;
+
id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
return (modpath->bc[index] == id);
}
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
index c0deafc..798ab37 100644
--- a/arch/powerpc/include/asm/barrier.h
+++ b/arch/powerpc/include/asm/barrier.h
@@ -34,7 +34,8 @@
#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
-#ifdef __SUBARCH_HAS_LWSYNC
+/* The sub-arch has lwsync */
+#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
# define SMPWMB LWSYNC
#else
# define SMPWMB eieio
diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h
index cd4ffd8..bb9073a 100644
--- a/arch/powerpc/include/asm/module.h
+++ b/arch/powerpc/include/asm/module.h
@@ -14,6 +14,10 @@
#include <asm-generic/module.h>
+#ifdef CC_USING_MPROFILE_KERNEL
+#define MODULE_ARCH_VERMAGIC "mprofile-kernel"
+#endif
+
#ifndef __powerpc64__
/*
* Thanks to Paul M for explaining this.
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index e958b70..9e5e0d9 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -21,6 +21,9 @@
/* We calculate number of sg entries based on PAGE_SIZE */
#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry))
+/* Default time to sleep or delay between OPAL_BUSY/OPAL_BUSY_EVENT loops */
+#define OPAL_BUSY_DELAY_MS 10
+
/* /sys/firmware/opal */
extern struct kobject *opal_kobj;
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index 56398e7..71c6988 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -132,7 +132,19 @@
#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT)
#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
+
+#ifdef CONFIG_PPC_BOOK3S_64
+/*
+ * On hash the vmalloc and other regions alias to the kernel region when passed
+ * through __pa(), which virt_to_pfn() uses. That means virt_addr_valid() can
+ * return true for some vmalloc addresses, which is incorrect. So explicitly
+ * check that the address is in the kernel region.
+ */
+#define virt_addr_valid(kaddr) (REGION_ID(kaddr) == KERNEL_REGION_ID && \
+ pfn_valid(virt_to_pfn(kaddr)))
+#else
#define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr))
+#endif
/*
* On Book-E parts we need __va to parse the device tree and we can't
diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h
index 78efe8d..30f2d6d 100644
--- a/arch/powerpc/include/asm/synch.h
+++ b/arch/powerpc/include/asm/synch.h
@@ -5,10 +5,6 @@
#include <linux/stringify.h>
#include <asm/feature-fixups.h>
-#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC)
-#define __SUBARCH_HAS_LWSYNC
-#endif
-
#ifndef __ASSEMBLY__
extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup;
extern void do_lwsync_fixups(unsigned long value, void *fixup_start,
diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c
index de7d091..1abd8dd 100644
--- a/arch/powerpc/kernel/eeh_pe.c
+++ b/arch/powerpc/kernel/eeh_pe.c
@@ -795,7 +795,8 @@
eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]);
/* PCI Command: 0x4 */
- eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1]);
+ eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1] |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
/* Check the PCIe link is ready */
eeh_bridge_check_link(edev);
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 7614d1d..94b5dfb 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -723,7 +723,7 @@
ld r3, PACA_EXSLB+EX_DAR(r13)
std r3, _DAR(r1)
beq cr6, 2f
- li r10, 0x480 /* fix trap number for I-SLB miss */
+ li r10, 0x481 /* fix trap number for I-SLB miss */
std r10, _TRAP(r1)
2: bl save_nvgprs
addi r3, r1, STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index 028a22b..ad713f7 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -372,6 +372,14 @@
*/
WARN_ON(!arch_irqs_disabled());
+ /*
+ * Interrupts must always be hard disabled before irq_happened is
+ * modified (to prevent lost update in case of interrupt between
+ * load and store).
+ */
+ __hard_irq_disable();
+ local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+
/* Indicate in the PACA that we have an interrupt to replay */
local_paca->irq_happened |= PACA_IRQ_EE;
}
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index f1d7e99..ab7b661 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -719,12 +719,20 @@
static void start_cpu_decrementer(void)
{
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
+ unsigned int tcr;
+
/* Clear any pending timer interrupts */
mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
- /* Enable decrementer interrupt */
- mtspr(SPRN_TCR, TCR_DIE);
-#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */
+ tcr = mfspr(SPRN_TCR);
+ /*
+ * The watchdog may have already been enabled by u-boot. So leave
+ * TRC[WP] (Watchdog Period) alone.
+ */
+ tcr &= TCR_WP_MASK; /* Clear all bits except for TCR[WP] */
+ tcr |= TCR_DIE; /* Enable decrementer */
+ mtspr(SPRN_TCR, tcr);
+#endif
}
void __init generic_calibrate_decr(void)
diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c
index 02176fd..286a3b0 100644
--- a/arch/powerpc/kvm/book3s_pr_papr.c
+++ b/arch/powerpc/kvm/book3s_pr_papr.c
@@ -50,7 +50,9 @@
pteg_addr = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
- copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
+ ret = H_FUNCTION;
+ if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)))
+ goto done;
hpte = pteg;
ret = H_PTEG_FULL;
@@ -71,7 +73,9 @@
hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6));
hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7));
pteg_addr += i * HPTE_SIZE;
- copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
+ ret = H_FUNCTION;
+ if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE))
+ goto done;
kvmppc_set_gpr(vcpu, 4, pte_index | i);
ret = H_SUCCESS;
@@ -93,7 +97,9 @@
pteg = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
- copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+ ret = H_FUNCTION;
+ if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+ goto done;
pte[0] = be64_to_cpu((__force __be64)pte[0]);
pte[1] = be64_to_cpu((__force __be64)pte[1]);
@@ -103,7 +109,9 @@
((flags & H_ANDCOND) && (pte[0] & avpn) != 0))
goto done;
- copy_to_user((void __user *)pteg, &v, sizeof(v));
+ ret = H_FUNCTION;
+ if (copy_to_user((void __user *)pteg, &v, sizeof(v)))
+ goto done;
rb = compute_tlbie_rb(pte[0], pte[1], pte_index);
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
@@ -171,7 +179,10 @@
}
pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
- copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+ if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) {
+ ret = H_FUNCTION;
+ break;
+ }
pte[0] = be64_to_cpu((__force __be64)pte[0]);
pte[1] = be64_to_cpu((__force __be64)pte[1]);
@@ -184,7 +195,10 @@
tsh |= H_BULK_REMOVE_NOT_FOUND;
} else {
/* Splat the pteg in (userland) hpt */
- copy_to_user((void __user *)pteg, &v, sizeof(v));
+ if (copy_to_user((void __user *)pteg, &v, sizeof(v))) {
+ ret = H_FUNCTION;
+ break;
+ }
rb = compute_tlbie_rb(pte[0], pte[1],
tsh & H_BULK_REMOVE_PTEX);
@@ -211,7 +225,9 @@
pteg = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
- copy_from_user(pte, (void __user *)pteg, sizeof(pte));
+ ret = H_FUNCTION;
+ if (copy_from_user(pte, (void __user *)pteg, sizeof(pte)))
+ goto done;
pte[0] = be64_to_cpu((__force __be64)pte[0]);
pte[1] = be64_to_cpu((__force __be64)pte[1]);
@@ -234,7 +250,9 @@
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
pte[0] = (__force u64)cpu_to_be64(pte[0]);
pte[1] = (__force u64)cpu_to_be64(pte[1]);
- copy_to_user((void __user *)pteg, pte, sizeof(pte));
+ ret = H_FUNCTION;
+ if (copy_to_user((void __user *)pteg, pte, sizeof(pte)))
+ goto done;
ret = H_SUCCESS;
done:
diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c
index e86bfa1..46c8338 100644
--- a/arch/powerpc/lib/feature-fixups.c
+++ b/arch/powerpc/lib/feature-fixups.c
@@ -55,7 +55,7 @@
unsigned int *target = (unsigned int *)branch_target(src);
/* Branch within the section doesn't need translating */
- if (target < alt_start || target >= alt_end) {
+ if (target < alt_start || target > alt_end) {
instr = translate_branch(dest, src);
if (!instr)
return 1;
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index 85c85eb..b4abf9d 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -175,6 +175,8 @@
skip = roundup(cprm->pos - total + sz, 4) - cprm->pos;
if (!dump_skip(cprm, skip))
goto Eio;
+
+ rc = 0;
out:
free_page((unsigned long)buf);
return rc;
diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c
index 9db4398..1bceb95 100644
--- a/arch/powerpc/platforms/powernv/opal-nvram.c
+++ b/arch/powerpc/platforms/powernv/opal-nvram.c
@@ -11,6 +11,7 @@
#define DEBUG
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
@@ -56,9 +57,17 @@
while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
rc = opal_write_nvram(__pa(buf), count, off);
- if (rc == OPAL_BUSY_EVENT)
+ if (rc == OPAL_BUSY_EVENT) {
+ msleep(OPAL_BUSY_DELAY_MS);
opal_poll_events(NULL);
+ } else if (rc == OPAL_BUSY) {
+ msleep(OPAL_BUSY_DELAY_MS);
+ }
}
+
+ if (rc)
+ return -EIO;
+
*index += count;
return count;
}
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c
index 3e828b2..2842f9d 100644
--- a/arch/powerpc/sysdev/mpc8xx_pic.c
+++ b/arch/powerpc/sysdev/mpc8xx_pic.c
@@ -79,7 +79,7 @@
irq = in_be32(&siu_reg->sc_sivec) >> 26;
if (irq == PIC_VEC_SPURRIOUS)
- irq = 0;
+ return 0;
return irq_linear_revmap(mpc8xx_pic_host, irq);
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index 09bccb2..2a17123 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -318,7 +318,7 @@
if (sb->s_root)
hypfs_delete_tree(sb->s_root);
- if (sb_info->update_file)
+ if (sb_info && sb_info->update_file)
hypfs_remove(sb_info->update_file);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 295bfb7..39127b6 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -798,6 +798,7 @@
/* copy and convert to ebcdic */
memcpy(ipb->hdr.loadparm, buf, lp_len);
ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN);
+ ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID;
return len;
}
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 3667d20..115bda2 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -31,8 +31,14 @@
{
. = 0x00000000;
.text : {
- _text = .; /* Text and read-only data */
+ /* Text and read-only data */
HEAD_TEXT
+ /*
+ * E.g. perf doesn't like symbols starting at address zero,
+ * therefore skip the initial PSW and channel program located
+ * at address zero and let _text start at 0x200.
+ */
+ _text = 0x200;
TEXT_TEXT
SCHED_TEXT
CPUIDLE_TEXT
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index 59d5038..9cc600b 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -1733,9 +1733,14 @@
lp->rcv_nxt = p->seqid;
+ /*
+ * If this is a control-only packet, there is nothing
+ * else to do but advance the rx queue since the packet
+ * was already processed above.
+ */
if (!(p->type & LDC_DATA)) {
new = rx_advance(lp, new);
- goto no_data;
+ break;
}
if (p->stype & (LDC_ACK | LDC_NACK)) {
err = data_ack_nack(lp, p);
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 2db18cb..c019709 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -12,6 +12,7 @@
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/un.h>
#include <sys/types.h>
#include <os.h>
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index a86d7cc..bf0acb8 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -16,6 +16,7 @@
#include <os.h>
#include <sysdep/mcontext.h>
#include <um_malloc.h>
+#include <sys/ucontext.h>
void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
[SIGTRAP] = relay_signal,
@@ -159,7 +160,7 @@
static void hard_handler(int sig, siginfo_t *si, void *p)
{
- struct ucontext *uc = p;
+ ucontext_t *uc = p;
mcontext_t *mc = &uc->uc_mcontext;
unsigned long pending = 1UL << sig;
diff --git a/arch/x86/boot/compressed/error.h b/arch/x86/boot/compressed/error.h
index 2e59dac..d732e60 100644
--- a/arch/x86/boot/compressed/error.h
+++ b/arch/x86/boot/compressed/error.h
@@ -1,7 +1,9 @@
#ifndef BOOT_COMPRESSED_ERROR_H
#define BOOT_COMPRESSED_ERROR_H
+#include <linux/compiler.h>
+
void warn(char *m);
-void error(char *m);
+void error(char *m) __noreturn;
#endif /* BOOT_COMPRESSED_ERROR_H */
diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig
new file mode 100644
index 0000000..43c9575
--- /dev/null
+++ b/arch/x86/configs/x86_64_cuttlefish_defconfig
@@ -0,0 +1,454 @@
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_FHANDLE is not set
+# CONFIG_USELIB is not set
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_MEMCG=y
+CONFIG_MEMCG_SWAP=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NAMESPACES=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_LZ4 is not set
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_PCSPKR_PLATFORM is not set
+CONFIG_BPF_SYSCALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
+CONFIG_CC_STACKPROTECTOR_STRONG=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_SMP=y
+CONFIG_HYPERVISOR_GUEST=y
+CONFIG_PARAVIRT=y
+CONFIG_PARAVIRT_SPINLOCKS=y
+CONFIG_MCORE2=y
+CONFIG_PROCESSOR_SELECT=y
+# CONFIG_CPU_SUP_CENTAUR is not set
+CONFIG_NR_CPUS=8
+CONFIG_PREEMPT=y
+# CONFIG_MICROCODE is not set
+CONFIG_X86_MSR=y
+CONFIG_X86_CPUID=y
+CONFIG_KSM=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
+CONFIG_TRANSPARENT_HUGEPAGE=y
+# CONFIG_MTRR is not set
+CONFIG_HZ_100=y
+CONFIG_KEXEC=y
+CONFIG_CRASH_DUMP=y
+CONFIG_PHYSICAL_START=0x200000
+CONFIG_RANDOMIZE_BASE=y
+CONFIG_PHYSICAL_ALIGN=0x1000000
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0 reboot=p"
+CONFIG_PM_WAKELOCKS=y
+CONFIG_PM_WAKELOCKS_LIMIT=0
+# CONFIG_PM_WAKELOCKS_GC is not set
+CONFIG_PM_DEBUG=y
+CONFIG_ACPI_PROCFS_POWER=y
+# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_THERMAL is not set
+# CONFIG_X86_PM_TIMER is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_X86_ACPI_CPUFREQ=y
+# CONFIG_X86_ACPI_CPUFREQ_CPB is not set
+CONFIG_PCI_MMCONFIG=y
+CONFIG_PCI_MSI=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_IA32_EMULATION=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=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_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_ESP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+CONFIG_INET_DIAG_DESTROY=y
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+CONFIG_TCP_MD5SIG=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_NETLABEL=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_MARK=y
+CONFIG_NETFILTER_XT_TARGET_NFLOG=y
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=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_HASHLIMIT=y
+CONFIG_NETFILTER_XT_MATCH_HELPER=y
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+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_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_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_IPV6HEADER=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_NET_SCHED=y
+CONFIG_NET_SCH_HTB=y
+CONFIG_NET_CLS_U32=y
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_U32=y
+CONFIG_NET_CLS_ACT=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
+CONFIG_RFKILL=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEBUG_DEVRES=y
+CONFIG_OF=y
+CONFIG_OF_UNITTEST=y
+# CONFIG_PNP_DEBUG_MESSAGES is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_VIRTIO_BLK=y
+CONFIG_UID_SYS_STATS=y
+CONFIG_MEMORY_STATE_TIME=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=y
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_VIRTIO=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_CRYPT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_UEVENT=y
+CONFIG_DM_VERITY=y
+CONFIG_DM_VERITY_FEC=y
+CONFIG_NETDEVICES=y
+CONFIG_NETCONSOLE=y
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_TUN=y
+CONFIG_VIRTIO_NET=y
+# CONFIG_ETHERNET is not set
+CONFIG_PPP=y
+CONFIG_PPP_BSDCOMP=y
+CONFIG_PPP_DEFLATE=y
+CONFIG_PPP_MPPE=y
+CONFIG_PPPOLAC=y
+CONFIG_PPPOPNS=y
+CONFIG_USB_USBNET=y
+# CONFIG_USB_NET_AX8817X is not set
+# CONFIG_USB_NET_AX88179_178A is not set
+# CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_NCM is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_CDC_SUBSET is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_WLAN_VENDOR_ADMTEK is not set
+# CONFIG_WLAN_VENDOR_ATH is not set
+# CONFIG_WLAN_VENDOR_ATMEL is not set
+# CONFIG_WLAN_VENDOR_BROADCOM is not set
+# CONFIG_WLAN_VENDOR_CISCO is not set
+# CONFIG_WLAN_VENDOR_INTEL is not set
+# CONFIG_WLAN_VENDOR_INTERSIL is not set
+# CONFIG_WLAN_VENDOR_MARVELL is not set
+# CONFIG_WLAN_VENDOR_MEDIATEK is not set
+# CONFIG_WLAN_VENDOR_RALINK is not set
+# CONFIG_WLAN_VENDOR_REALTEK is not set
+# CONFIG_WLAN_VENDOR_RSI is not set
+# CONFIG_WLAN_VENDOR_ST is not set
+# CONFIG_WLAN_VENDOR_TI is not set
+# CONFIG_WLAN_VENDOR_ZYDAS is not set
+CONFIG_MAC80211_HWSIM=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_KEYRESET=y
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_JOYSTICK=y
+CONFIG_JOYSTICK_XPAD=y
+CONFIG_JOYSTICK_XPAD_FF=y
+CONFIG_JOYSTICK_XPAD_LEDS=y
+CONFIG_INPUT_TABLET=y
+CONFIG_TABLET_USB_ACECAD=y
+CONFIG_TABLET_USB_AIPTEK=y
+CONFIG_TABLET_USB_GTCO=y
+CONFIG_TABLET_USB_HANWANG=y
+CONFIG_TABLET_USB_KBTAB=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_KEYCHORD=y
+CONFIG_INPUT_UINPUT=y
+CONFIG_INPUT_GPIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=48
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_HW_RANDOM=y
+# CONFIG_HW_RANDOM_INTEL is not set
+# CONFIG_HW_RANDOM_AMD is not set
+# CONFIG_HW_RANDOM_VIA is not set
+CONFIG_HW_RANDOM_VIRTIO=y
+CONFIG_HPET=y
+# CONFIG_HPET_MMAP_DEFAULT is not set
+# CONFIG_DEVPORT is not set
+# CONFIG_ACPI_I2C_OPREGION is not set
+# CONFIG_I2C_COMPAT is not set
+# CONFIG_I2C_HELPER_AUTO is not set
+CONFIG_PTP_1588_CLOCK=y
+# CONFIG_HWMON is not set
+# CONFIG_X86_PKG_TEMP_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=y
+CONFIG_MEDIA_SUPPORT=y
+# CONFIG_DVB_TUNER_DIB0070 is not set
+# CONFIG_DVB_TUNER_DIB0090 is not set
+# CONFIG_VGA_ARB is not set
+CONFIG_DRM=y
+# CONFIG_DRM_FBDEV_EMULATION is not set
+CONFIG_DRM_VIRTIO_GPU=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_HIDRAW=y
+CONFIG_UHID=y
+# CONFIG_HID_GENERIC is not set
+CONFIG_HID_A4TECH=y
+CONFIG_HID_ACRUX=y
+CONFIG_HID_ACRUX_FF=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_PRODIKEYS=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_DRAGONRISE_FF=y
+CONFIG_HID_EMS_FF=y
+CONFIG_HID_ELECOM=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_HOLTEK=y
+CONFIG_HID_KEYTOUCH=y
+CONFIG_HID_KYE=y
+CONFIG_HID_UCLOGIC=y
+CONFIG_HID_WALTOP=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LCPOWER=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=y
+CONFIG_LOGITECH_FF=y
+CONFIG_LOGIRUMBLEPAD2_FF=y
+CONFIG_LOGIG940_FF=y
+CONFIG_HID_MAGICMOUSE=y
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_MULTITOUCH=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_PANTHERLORD_FF=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_PICOLCD=y
+CONFIG_HID_PRIMAX=y
+CONFIG_HID_ROCCAT=y
+CONFIG_HID_SAITEK=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SPEEDLINK=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_GREENASIA_FF=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_SMARTJOYPLUS_FF=y
+CONFIG_HID_TIVO=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_WACOM=y
+CONFIG_HID_WIIMOTE=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_HID_ZYDACRON=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_DUMMY_HCD=y
+CONFIG_USB_CONFIGFS=y
+CONFIG_USB_CONFIGFS_F_FS=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_RTC_CLASS=y
+# CONFIG_RTC_HCTOSYS is not set
+CONFIG_SW_SYNC=y
+CONFIG_VIRTIO_PCI=y
+CONFIG_VIRTIO_BALLOON=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_STAGING=y
+CONFIG_ASHMEM=y
+CONFIG_ANDROID_VSOC=y
+CONFIG_ION=y
+# CONFIG_X86_PLATFORM_DEVICES is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_ANDROID=y
+CONFIG_ANDROID_BINDER_IPC=y
+# CONFIG_FIRMWARE_MEMMAP is not set
+CONFIG_EXT4_FS=y
+CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_EXT4_FS_SECURITY=y
+CONFIG_EXT4_ENCRYPTION=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+# CONFIG_PRINT_QUOTA_WARNING is not set
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
+CONFIG_SDCARD_FS=y
+CONFIG_PSTORE=y
+CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_STACK_USAGE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_LOCKUP_DETECTOR=y
+CONFIG_PANIC_TIMEOUT=5
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+CONFIG_TIMER_STATS=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
+CONFIG_ENABLE_DEFAULT_TRACERS=y
+CONFIG_IO_DELAY_NONE=y
+CONFIG_DEBUG_BOOT_PARAMS=y
+CONFIG_OPTIMIZE_INLINING=y
+CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+CONFIG_SECURITY_PATH=y
+CONFIG_HARDENED_USERCOPY=y
+CONFIG_SECURITY_SELINUX=y
+CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1
+# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
index 8648158..f8fe11d 100644
--- a/arch/x86/crypto/cast5_avx_glue.c
+++ b/arch/x86/crypto/cast5_avx_glue.c
@@ -66,8 +66,6 @@
void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src);
int err;
- fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
-
err = blkcipher_walk_virt(desc, walk);
desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
@@ -79,6 +77,7 @@
/* Process multi-block batch */
if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+ fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way;
do {
fn(ctx, wdst, wsrc);
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index b8d3f1b..91c48cd 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -51,6 +51,7 @@
#include <linux/ftrace.h>
#include <linux/frame.h>
#include <linux/kasan.h>
+#include <linux/moduleloader.h>
#include <asm/text-patching.h>
#include <asm/cacheflush.h>
@@ -405,6 +406,14 @@
return length;
}
+/* Recover page to RW mode before releasing it */
+void free_insn_page(void *page)
+{
+ set_memory_nx((unsigned long)page & PAGE_MASK, 1);
+ set_memory_rw((unsigned long)page & PAGE_MASK, 1);
+ module_memfree(page);
+}
+
static int arch_copy_kprobe(struct kprobe *p)
{
int ret;
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index d07a9390..bbfb03ec 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -366,6 +366,8 @@
tsc_clocksource_reliable = 1;
if (!strncmp(str, "noirqtime", 9))
no_sched_irq_time = 1;
+ if (!strcmp(str, "unstable"))
+ mark_tsc_unstable("boot parameter");
return 1;
}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index b24b3c6..5c3d416f 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1363,8 +1363,10 @@
static void cancel_hv_tscdeadline(struct kvm_lapic *apic)
{
+ preempt_disable();
kvm_x86_ops->cancel_hv_timer(apic->vcpu);
apic->lapic_timer.hv_timer_in_use = false;
+ preempt_enable();
}
void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu)
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 8c99f2f..aaa93b4 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1879,6 +1879,7 @@
*/
if (var->unusable)
var->db = 0;
+ /* This is symmetric with svm_set_segment() */
var->dpl = to_svm(vcpu)->vmcb->save.cpl;
break;
}
@@ -2024,18 +2025,14 @@
s->base = var->base;
s->limit = var->limit;
s->selector = var->selector;
- if (var->unusable)
- s->attrib = 0;
- else {
- s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
- s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
- s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
- s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT;
- s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
- s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
- s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
- s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
- }
+ s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK);
+ s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT;
+ s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT;
+ s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT;
+ s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT;
+ s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT;
+ s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT;
+ s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT;
/*
* This is always accurate, except if SYSRET returned to a segment
@@ -2044,7 +2041,8 @@
* would entail passing the CPL to userspace and back.
*/
if (seg == VCPU_SREG_SS)
- svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3;
+ /* This is symmetric with svm_get_segment() */
+ svm->vmcb->save.cpl = (var->dpl & 3);
mark_dirty(svm->vmcb, VMCB_SEG);
}
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 9c51710..ff2030f 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -7924,11 +7924,13 @@
{
unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
int cr = exit_qualification & 15;
- int reg = (exit_qualification >> 8) & 15;
- unsigned long val = kvm_register_readl(vcpu, reg);
+ int reg;
+ unsigned long val;
switch ((exit_qualification >> 4) & 3) {
case 0: /* mov to cr */
+ reg = (exit_qualification >> 8) & 15;
+ val = kvm_register_readl(vcpu, reg);
switch (cr) {
case 0:
if (vmcs12->cr0_guest_host_mask &
@@ -7983,6 +7985,7 @@
* lmsw can change bits 1..3 of cr0, and only set bit 0 of
* cr0. Other attempted changes are ignored, with no exit.
*/
+ val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f;
if (vmcs12->cr0_guest_host_mask & 0xe &
(val ^ vmcs12->cr0_read_shadow))
return true;
@@ -10660,8 +10663,7 @@
vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3);
}
- if (nested_cpu_has_ept(vmcs12))
- vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
+ vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS);
if (nested_cpu_has_vid(vmcs12))
vmcs12->guest_intr_status = vmcs_read16(GUEST_INTR_STATUS);
diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S
index 7e48807..45a53df 100644
--- a/arch/x86/lib/csum-copy_64.S
+++ b/arch/x86/lib/csum-copy_64.S
@@ -55,7 +55,7 @@
movq %r12, 3*8(%rsp)
movq %r14, 4*8(%rsp)
movq %r13, 5*8(%rsp)
- movq %rbp, 6*8(%rsp)
+ movq %r15, 6*8(%rsp)
movq %r8, (%rsp)
movq %r9, 1*8(%rsp)
@@ -74,7 +74,7 @@
/* main loop. clear in 64 byte blocks */
/* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */
/* r11: temp3, rdx: temp4, r12 loopcnt */
- /* r10: temp5, rbp: temp6, r14 temp7, r13 temp8 */
+ /* r10: temp5, r15: temp6, r14 temp7, r13 temp8 */
.p2align 4
.Lloop:
source
@@ -89,7 +89,7 @@
source
movq 32(%rdi), %r10
source
- movq 40(%rdi), %rbp
+ movq 40(%rdi), %r15
source
movq 48(%rdi), %r14
source
@@ -103,7 +103,7 @@
adcq %r11, %rax
adcq %rdx, %rax
adcq %r10, %rax
- adcq %rbp, %rax
+ adcq %r15, %rax
adcq %r14, %rax
adcq %r13, %rax
@@ -121,7 +121,7 @@
dest
movq %r10, 32(%rsi)
dest
- movq %rbp, 40(%rsi)
+ movq %r15, 40(%rsi)
dest
movq %r14, 48(%rsi)
dest
@@ -203,7 +203,7 @@
movq 3*8(%rsp), %r12
movq 4*8(%rsp), %r14
movq 5*8(%rsp), %r13
- movq 6*8(%rsp), %rbp
+ movq 6*8(%rsp), %r15
addq $7*8, %rsp
ret
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 274dfc4..a0e85f2 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -832,9 +832,11 @@
/*
* We don't do virtual mode, since we don't do runtime services, on
- * non-native EFI
+ * non-native EFI. With efi=old_map, we don't do runtime services in
+ * kexec kernel because in the initial boot something else might
+ * have been mapped at these virtual addresses.
*/
- if (!efi_is_native()) {
+ if (!efi_is_native() || efi_enabled(EFI_OLD_MEMMAP)) {
efi_memmap_unmap();
clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
return;
diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c
index 1518d28..27361cb 100644
--- a/arch/x86/um/stub_segv.c
+++ b/arch/x86/um/stub_segv.c
@@ -6,11 +6,12 @@
#include <sysdep/stub.h>
#include <sysdep/faultinfo.h>
#include <sysdep/mcontext.h>
+#include <sys/ucontext.h>
void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig, siginfo_t *info, void *p)
{
- struct ucontext *uc = p;
+ ucontext_t *uc = p;
GET_FAULTINFO_FROM_MC(*((struct faultinfo *) STUB_DATA),
&uc->uc_mcontext);
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index 63f72f0..80dedde 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -175,6 +175,9 @@
if (!bio_is_rw(bio))
return false;
+ if (!bio_sectors(bio))
+ return false;
+
/* Already protected? */
if (bio_integrity(bio))
return false;
diff --git a/block/bio.c b/block/bio.c
index 07f287b..4f93345 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -42,9 +42,9 @@
* break badly! cannot be bigger than what you can fit into an
* unsigned short
*/
-#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
+#define BV(x, n) { .nr_vecs = x, .name = "biovec-"#n }
static struct biovec_slab bvec_slabs[BVEC_POOL_NR] __read_mostly = {
- BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
+ BV(1, 1), BV(4, 4), BV(16, 16), BV(64, 64), BV(128, 128), BV(BIO_MAX_PAGES, max),
};
#undef BV
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 8c74712..0668b66 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1265,13 +1265,13 @@
blk_queue_bounce(q, &bio);
+ blk_queue_split(q, &bio, q->bio_split);
+
if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
bio_io_error(bio);
return BLK_QC_T_NONE;
}
- blk_queue_split(q, &bio, q->bio_split);
-
if (!is_flush_fua && !blk_queue_nomerges(q) &&
blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
return BLK_QC_T_NONE;
@@ -1592,7 +1592,8 @@
{
unsigned flush_start_tag = set->queue_depth;
- blk_mq_tag_idle(hctx);
+ if (blk_mq_hw_queue_mapped(hctx))
+ blk_mq_tag_idle(hctx);
if (set->ops->exit_request)
set->ops->exit_request(set->driver_data,
@@ -1907,6 +1908,9 @@
struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx;
blk_mq_sysfs_unregister(q);
+
+ /* protect against switching io scheduler */
+ mutex_lock(&q->sysfs_lock);
for (i = 0; i < set->nr_hw_queues; i++) {
int node;
@@ -1956,6 +1960,7 @@
}
}
q->nr_hw_queues = i;
+ mutex_unlock(&q->sysfs_lock);
blk_mq_sysfs_register(q);
}
@@ -2014,15 +2019,15 @@
blk_mq_init_cpu_queues(q, set->nr_hw_queues);
- mutex_lock(&all_q_mutex);
get_online_cpus();
+ mutex_lock(&all_q_mutex);
list_add_tail(&q->all_q_node, &all_q_list);
blk_mq_add_queue_tag_set(set, q);
blk_mq_map_swqueue(q, cpu_online_mask);
- put_online_cpus();
mutex_unlock(&all_q_mutex);
+ put_online_cpus();
return q;
diff --git a/block/partition-generic.c b/block/partition-generic.c
index a2437c0..298c05f 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -321,8 +321,10 @@
if (info) {
struct partition_meta_info *pinfo = alloc_part_info(disk);
- if (!pinfo)
+ if (!pinfo) {
+ err = -ENOMEM;
goto out_free_stats;
+ }
memcpy(pinfo, info, sizeof(*info));
p->info = pinfo;
}
diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c
index 5610cd5..7d8d50c 100644
--- a/block/partitions/msdos.c
+++ b/block/partitions/msdos.c
@@ -300,7 +300,9 @@
continue;
bsd_start = le32_to_cpu(p->p_offset);
bsd_size = le32_to_cpu(p->p_size);
- if (memcmp(flavour, "bsd\0", 4) == 0)
+ /* FreeBSD has relative offset if C partition offset is zero */
+ if (memcmp(flavour, "bsd\0", 4) == 0 &&
+ le32_to_cpu(l->d_partitions[2].p_offset) == 0)
bsd_start += offset;
if (offset == bsd_start && size == bsd_size)
/* full parent partition, we have it already */
diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64
new file mode 100644
index 0000000..5a96563
--- /dev/null
+++ b/build.config.cuttlefish.x86_64
@@ -0,0 +1,15 @@
+ARCH=x86_64
+BRANCH=android-4.9
+CLANG_TRIPLE=x86_64-linux-gnu-
+CROSS_COMPILE=x86_64-linux-androidkernel-
+DEFCONFIG=x86_64_cuttlefish_defconfig
+EXTRA_CMDS=''
+KERNEL_DIR=common
+POST_DEFCONFIG_CMDS="check_defconfig"
+CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-4630689/bin
+LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin
+FILES="
+arch/x86/boot/bzImage
+vmlinux
+System.map
+"
diff --git a/crypto/ahash.c b/crypto/ahash.c
index 14402ef..90d73a2 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -91,13 +91,14 @@
if (nbytes && walk->offset & alignmask && !err) {
walk->offset = ALIGN(walk->offset, alignmask + 1);
- walk->data += walk->offset;
-
nbytes = min(nbytes,
((unsigned int)(PAGE_SIZE)) - walk->offset);
walk->entrylen -= nbytes;
- return nbytes;
+ if (nbytes) {
+ walk->data += walk->offset;
+ return nbytes;
+ }
}
if (walk->flags & CRYPTO_ALG_ASYNC)
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 029f705..ce2df8c 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -102,6 +102,7 @@
}
}
+ ret = -ENOMEM;
cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
if (!cert->pub->key)
goto error_decode;
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index f83de99..56bd612 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -62,9 +62,6 @@
dma_addr_t dma_dest[2];
int src_off = 0;
- if (submit->flags & ASYNC_TX_FENCE)
- dma_flags |= DMA_PREP_FENCE;
-
while (src_cnt > 0) {
submit->flags = flags_orig;
pq_src_cnt = min(src_cnt, dma_maxpq(dma, dma_flags));
@@ -83,6 +80,8 @@
if (cb_fn_orig)
dma_flags |= DMA_PREP_INTERRUPT;
}
+ if (submit->flags & ASYNC_TX_FENCE)
+ dma_flags |= DMA_PREP_FENCE;
/* Drivers force forward progress in case they can not provide
* a descriptor
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index c5557d0..94e04c9 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -87,8 +87,8 @@
static bool device_id_scheme = false;
module_param(device_id_scheme, bool, 0444);
-static bool only_lcd = false;
-module_param(only_lcd, bool, 0444);
+static int only_lcd = -1;
+module_param(only_lcd, int, 0444);
static int register_count;
static DEFINE_MUTEX(register_count_mutex);
@@ -2082,6 +2082,16 @@
goto leave;
}
+ /*
+ * We're seeing a lot of bogus backlight interfaces on newer machines
+ * without a LCD such as desktops, servers and HDMI sticks. Checking
+ * the lcd flag fixes this, so enable this on any machines which are
+ * win8 ready (where we also prefer the native backlight driver, so
+ * normally the acpi_video code should not register there anyways).
+ */
+ if (only_lcd == -1)
+ only_lcd = acpi_osi_is_win8();
+
dmi_check_system(video_dmi_table);
ret = acpi_bus_register_driver(&acpi_video_bus);
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index 9179e9a..35a2d9e 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -180,6 +180,12 @@
ACPI_FUNCTION_TRACE(acpi_enable_event);
+ /* If Hardware Reduced flag is set, there are no fixed events */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
/* Decode the Fixed Event */
if (event > ACPI_EVENT_MAX) {
@@ -237,6 +243,12 @@
ACPI_FUNCTION_TRACE(acpi_disable_event);
+ /* If Hardware Reduced flag is set, there are no fixed events */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
/* Decode the Fixed Event */
if (event > ACPI_EVENT_MAX) {
@@ -290,6 +302,12 @@
ACPI_FUNCTION_TRACE(acpi_clear_event);
+ /* If Hardware Reduced flag is set, there are no fixed events */
+
+ if (acpi_gbl_reduced_hardware) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
/* Decode the Fixed Event */
if (event > ACPI_EVENT_MAX) {
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
index db0e903..ac2e8df 100644
--- a/drivers/acpi/acpica/psobject.c
+++ b/drivers/acpi/acpica/psobject.c
@@ -121,6 +121,9 @@
(u32)(aml_offset +
sizeof(struct acpi_table_header)));
+ ACPI_ERROR((AE_INFO,
+ "Aborting disassembly, AML byte code is corrupt"));
+
/* Dump the context surrounding the invalid opcode */
acpi_ut_dump_buffer(((u8 *)walk_state->parser_state.
@@ -129,6 +132,14 @@
sizeof(struct acpi_table_header) -
16));
acpi_os_printf(" */\n");
+
+ /*
+ * Just abort the disassembly, cannot continue because the
+ * parser is essentially lost. The disassembler can then
+ * randomly fail because an ill-constructed parse tree
+ * can result.
+ */
+ return_ACPI_STATUS(AE_AML_BAD_OPCODE);
#endif
}
@@ -293,6 +304,9 @@
if (status == AE_CTRL_PARSE_CONTINUE) {
return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
}
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
/* Create Op structure and append to parent's argument list */
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index b4a2c31..7b665aa 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1518,7 +1518,7 @@
}
acpi_handle_info(ec->handle,
- "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
+ "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
return ret;
}
diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c
index 6c7dd7a..dd70d6c 100644
--- a/drivers/acpi/ec_sys.c
+++ b/drivers/acpi/ec_sys.c
@@ -128,7 +128,7 @@
return -ENOMEM;
}
- if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe))
+ if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe))
goto error;
if (!debugfs_create_bool("use_global_lock", 0444, dev_dir,
&first_ec->global_lock))
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 08b3ca0..b012e94 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -158,7 +158,7 @@
-------------------------------------------------------------------------- */
struct acpi_ec {
acpi_handle handle;
- unsigned long gpe;
+ u32 gpe;
unsigned long command_addr;
unsigned long data_addr;
bool global_lock;
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c
index b1815b2..3874eec 100644
--- a/drivers/acpi/nfit/core.c
+++ b/drivers/acpi/nfit/core.c
@@ -967,8 +967,11 @@
if (nd_desc) {
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
+ mutex_lock(&acpi_desc->init_mutex);
rc = sprintf(buf, "%d%s", acpi_desc->scrub_count,
- (work_busy(&acpi_desc->work)) ? "+\n" : "\n");
+ work_busy(&acpi_desc->work)
+ && !acpi_desc->cancel ? "+\n" : "\n");
+ mutex_unlock(&acpi_desc->init_mutex);
}
device_unlock(dev);
return rc;
@@ -2547,15 +2550,21 @@
static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
{
struct nfit_spa *nfit_spa;
- int rc;
- list_for_each_entry(nfit_spa, &acpi_desc->spas, list)
- if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) {
- /* BLK regions don't need to wait for ars results */
- rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
- if (rc)
- return rc;
- }
+ list_for_each_entry(nfit_spa, &acpi_desc->spas, list) {
+ int rc, type = nfit_spa_type(nfit_spa->spa);
+
+ /* PMEM and VMEM will be registered by the ARS workqueue */
+ if (type == NFIT_SPA_PM || type == NFIT_SPA_VOLATILE)
+ continue;
+ /* BLK apertures belong to BLK region registration below */
+ if (type == NFIT_SPA_BDW)
+ continue;
+ /* BLK regions don't need to wait for ARS results */
+ rc = acpi_nfit_register_region(acpi_desc, nfit_spa);
+ if (rc)
+ return rc;
+ }
queue_work(nfit_wq, &acpi_desc->work);
return 0;
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 02ded25..cdc4737 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -214,6 +214,15 @@
},
},
{
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */
+ .callback = video_detect_force_video,
+ .ident = "SAMSUNG 670Z5E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"),
+ },
+ },
+ {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
.callback = video_detect_force_video,
.ident = "SAMSUNG 730U3E/740U3E",
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index aaa761b..cd2eab6 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -514,8 +514,9 @@
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
- dev_err(dev, "no irq\n");
- return -EINVAL;
+ if (irq != -EPROBE_DEFER)
+ dev_err(dev, "no irq\n");
+ return irq;
}
hpriv->irq = irq;
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 3331ed8..f74f3ca 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -1736,7 +1736,7 @@
return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
- if (map->max_raw_write && map->max_raw_write > val_len)
+ if (map->max_raw_write && map->max_raw_write < val_len)
return -E2BIG;
map->lock(map->lock_arg);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 68bfcef..ff1c4d7 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -612,6 +612,9 @@
*/
static int loop_flush(struct loop_device *lo)
{
+ /* loop not yet configured, no running thread, nothing to flush */
+ if (lo->lo_state != Lo_bound)
+ return 0;
return loop_switch(lo, NULL);
}
@@ -1107,11 +1110,15 @@
if (info->lo_encrypt_type) {
unsigned int type = info->lo_encrypt_type;
- if (type >= MAX_LO_CRYPT)
- return -EINVAL;
+ if (type >= MAX_LO_CRYPT) {
+ err = -EINVAL;
+ goto exit;
+ }
xfer = xfer_funcs[type];
- if (xfer == NULL)
- return -EINVAL;
+ if (xfer == NULL) {
+ err = -EINVAL;
+ goto exit;
+ }
} else
xfer = NULL;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index b86273f..3cfd879 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -169,25 +169,6 @@
return false; /* device present */
}
-/* we have to use runtime tag to setup command header */
-static void mtip_init_cmd_header(struct request *rq)
-{
- struct driver_data *dd = rq->q->queuedata;
- struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
- u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
-
- /* Point the command headers at the command tables. */
- cmd->command_header = dd->port->command_list +
- (sizeof(struct mtip_cmd_hdr) * rq->tag);
- cmd->command_header_dma = dd->port->command_list_dma +
- (sizeof(struct mtip_cmd_hdr) * rq->tag);
-
- if (host_cap_64)
- cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16);
-
- cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF);
-}
-
static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd)
{
struct request *rq;
@@ -199,9 +180,6 @@
if (IS_ERR(rq))
return NULL;
- /* Internal cmd isn't submitted via .queue_rq */
- mtip_init_cmd_header(rq);
-
return blk_mq_rq_to_pdu(rq);
}
@@ -3833,8 +3811,6 @@
struct request *rq = bd->rq;
int ret;
- mtip_init_cmd_header(rq);
-
if (unlikely(mtip_check_unal_depth(hctx, rq)))
return BLK_MQ_RQ_QUEUE_BUSY;
@@ -3866,6 +3842,7 @@
{
struct driver_data *dd = data;
struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq);
+ u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
/*
* For flush requests, request_idx starts at the end of the
@@ -3882,6 +3859,17 @@
memset(cmd->command, 0, CMD_DMA_ALLOC_SZ);
+ /* Point the command headers at the command tables. */
+ cmd->command_header = dd->port->command_list +
+ (sizeof(struct mtip_cmd_hdr) * request_idx);
+ cmd->command_header_dma = dd->port->command_list_dma +
+ (sizeof(struct mtip_cmd_hdr) * request_idx);
+
+ if (host_cap_64)
+ cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16);
+
+ cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF);
+
sg_init_table(cmd->sg, MTIP_MAX_SG);
return 0;
}
diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c
index f927756..7f7c942 100644
--- a/drivers/bluetooth/bluetooth-power.c
+++ b/drivers/bluetooth/bluetooth-power.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009-2010, 2013-2017 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2009-2010, 2013-2018 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -43,6 +43,7 @@
static const struct of_device_id bt_power_match_table[] = {
{ .compatible = "qca,ar3002" },
{ .compatible = "qca,qca6174" },
+ { .compatible = "qca,qca9379" },
{ .compatible = "qca,wcn3990" },
{}
};
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 72fe0a5..017c37b 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Broadcom Corporation
+ * Copyright (C) 2014-2017 Broadcom
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -37,8 +37,6 @@
#define ARB_ERR_CAP_CLEAR (1 << 0)
#define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12)
#define ARB_ERR_CAP_STATUS_TEA (1 << 11)
-#define ARB_ERR_CAP_STATUS_BS_SHIFT (1 << 2)
-#define ARB_ERR_CAP_STATUS_BS_MASK 0x3c
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
@@ -47,7 +45,6 @@
ARB_ERR_CAP_CLR,
ARB_ERR_CAP_HI_ADDR,
ARB_ERR_CAP_ADDR,
- ARB_ERR_CAP_DATA,
ARB_ERR_CAP_STATUS,
ARB_ERR_CAP_MASTER,
};
@@ -57,7 +54,6 @@
[ARB_ERR_CAP_CLR] = 0x0c4,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0c8,
- [ARB_ERR_CAP_DATA] = 0x0cc,
[ARB_ERR_CAP_STATUS] = 0x0d0,
[ARB_ERR_CAP_MASTER] = -1,
};
@@ -67,7 +63,6 @@
[ARB_ERR_CAP_CLR] = 0x0c8,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x0cc,
- [ARB_ERR_CAP_DATA] = 0x0d0,
[ARB_ERR_CAP_STATUS] = 0x0d4,
[ARB_ERR_CAP_MASTER] = 0x0d8,
};
@@ -77,7 +72,6 @@
[ARB_ERR_CAP_CLR] = 0x168,
[ARB_ERR_CAP_HI_ADDR] = -1,
[ARB_ERR_CAP_ADDR] = 0x16c,
- [ARB_ERR_CAP_DATA] = 0x170,
[ARB_ERR_CAP_STATUS] = 0x174,
[ARB_ERR_CAP_MASTER] = 0x178,
};
@@ -87,7 +81,6 @@
[ARB_ERR_CAP_CLR] = 0x7e4,
[ARB_ERR_CAP_HI_ADDR] = 0x7e8,
[ARB_ERR_CAP_ADDR] = 0x7ec,
- [ARB_ERR_CAP_DATA] = 0x7f0,
[ARB_ERR_CAP_STATUS] = 0x7f4,
[ARB_ERR_CAP_MASTER] = 0x7f8,
};
@@ -109,9 +102,13 @@
{
int offset = gdev->gisb_offsets[reg];
- /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
- if (offset == -1)
- return 1;
+ if (offset < 0) {
+ /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
+ if (reg == ARB_ERR_CAP_MASTER)
+ return 1;
+ else
+ return 0;
+ }
if (gdev->big_endian)
return ioread32be(gdev->base + offset);
@@ -119,6 +116,16 @@
return ioread32(gdev->base + offset);
}
+static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev)
+{
+ u64 value;
+
+ value = gisb_read(gdev, ARB_ERR_CAP_ADDR);
+ value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
+
+ return value;
+}
+
static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
{
int offset = gdev->gisb_offsets[reg];
@@ -127,9 +134,9 @@
return;
if (gdev->big_endian)
- iowrite32be(val, gdev->base + reg);
+ iowrite32be(val, gdev->base + offset);
else
- iowrite32(val, gdev->base + reg);
+ iowrite32(val, gdev->base + offset);
}
static ssize_t gisb_arb_get_timeout(struct device *dev,
@@ -185,7 +192,7 @@
const char *reason)
{
u32 cap_status;
- unsigned long arb_addr;
+ u64 arb_addr;
u32 master;
const char *m_name;
char m_fmt[11];
@@ -197,10 +204,7 @@
return 1;
/* Read the address and master */
- arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
-#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
- arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
-#endif
+ arb_addr = gisb_read_address(gdev);
master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
m_name = brcmstb_gisb_master_to_str(gdev, master);
@@ -209,7 +213,7 @@
m_name = m_fmt;
}
- pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n",
+ pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n",
__func__, reason, arb_addr,
cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R',
cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "",
diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c
index 286418f..a089e7c 100644
--- a/drivers/char/diag/diag_dci.c
+++ b/drivers/char/diag/diag_dci.c
@@ -2713,7 +2713,7 @@
}
}
-static int diag_dci_init_remote(void)
+int diag_dci_init_remote(void)
{
int i;
struct dci_ops_tbl_t *temp = NULL;
@@ -2740,11 +2740,6 @@
return 0;
}
-#else
-static int diag_dci_init_remote(void)
-{
- return 0;
-}
#endif
static int diag_dci_init_ops_tbl(void)
@@ -2754,10 +2749,6 @@
err = diag_dci_init_local();
if (err)
goto err;
- err = diag_dci_init_remote();
- if (err)
- goto err;
-
return 0;
err:
diff --git a/drivers/char/diag/diag_dci.h b/drivers/char/diag/diag_dci.h
index 61eb3f5..2fb0e3f 100644
--- a/drivers/char/diag/diag_dci.h
+++ b/drivers/char/diag/diag_dci.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-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
@@ -323,6 +323,7 @@
int diag_dci_write_bridge(int token, unsigned char *buf, int len);
int diag_dci_write_done_bridge(int index, unsigned char *buf, int len);
int diag_dci_send_handshake_pkt(int index);
+int diag_dci_init_remote(void);
#endif
#endif
diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c
index b7d56a9..c20dd2e 100644
--- a/drivers/char/diag/diag_masks.c
+++ b/drivers/char/diag/diag_masks.c
@@ -2189,9 +2189,12 @@
if (driver->time_sync_enabled)
diag_send_time_sync_update(peripheral);
mutex_lock(&driver->md_session_lock);
- diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID);
- diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
- diag_send_event_mask_update(peripheral);
+ if (driver->set_mask_cmd) {
+ diag_send_msg_mask_update(peripheral,
+ ALL_SSID, ALL_SSID);
+ diag_send_log_mask_update(peripheral, ALL_EQUIP_ID);
+ diag_send_event_mask_update(peripheral);
+ }
mutex_unlock(&driver->md_session_lock);
diag_send_real_time_update(peripheral,
driver->real_time_mode[DIAG_LOCAL_PROC]);
@@ -2228,6 +2231,7 @@
break;
case DIAG_CMD_OP_SET_LOG_MASK:
hdlr = diag_cmd_set_log_mask;
+ driver->set_mask_cmd = 1;
break;
case DIAG_CMD_OP_GET_LOG_MASK:
hdlr = diag_cmd_get_log_mask;
@@ -2247,17 +2251,21 @@
break;
case DIAG_CMD_OP_SET_MSG_MASK:
hdlr = diag_cmd_set_msg_mask;
+ driver->set_mask_cmd = 1;
break;
case DIAG_CMD_OP_SET_ALL_MSG_MASK:
hdlr = diag_cmd_set_all_msg_mask;
+ driver->set_mask_cmd = 1;
break;
}
} else if (*buf == DIAG_CMD_GET_EVENT_MASK) {
hdlr = diag_cmd_get_event_mask;
} else if (*buf == DIAG_CMD_SET_EVENT_MASK) {
hdlr = diag_cmd_update_event_mask;
+ driver->set_mask_cmd = 1;
} else if (*buf == DIAG_CMD_EVENT_TOGGLE) {
hdlr = diag_cmd_toggle_events;
+ driver->set_mask_cmd = 1;
}
if (hdlr)
diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c
index ce0c7bb..55b1b49 100644
--- a/drivers/char/diag/diag_memorydevice.c
+++ b/drivers/char/diag/diag_memorydevice.c
@@ -384,7 +384,7 @@
int i, j;
struct diag_md_info *ch = NULL;
- for (i = 0; i < NUM_DIAG_MD_DEV; i++) {
+ for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) {
ch = &diag_md[i];
ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize;
ch->tbl = kzalloc(ch->num_tbl_entries *
@@ -408,12 +408,53 @@
return -ENOMEM;
}
+int diag_md_mdm_init(void)
+{
+ int i, j;
+ struct diag_md_info *ch = NULL;
+
+ for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) {
+ ch = &diag_md[i];
+ ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize;
+ ch->tbl = kcalloc(ch->num_tbl_entries, sizeof(*ch->tbl),
+ GFP_KERNEL);
+ if (!ch->tbl)
+ goto fail;
+
+ for (j = 0; j < ch->num_tbl_entries; j++) {
+ ch->tbl[j].buf = NULL;
+ ch->tbl[j].len = 0;
+ ch->tbl[j].ctx = 0;
+ }
+ spin_lock_init(&(ch->lock));
+ }
+
+ return 0;
+
+fail:
+ diag_md_mdm_exit();
+ return -ENOMEM;
+}
+
void diag_md_exit(void)
{
int i;
struct diag_md_info *ch = NULL;
- for (i = 0; i < NUM_DIAG_MD_DEV; i++) {
+ for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) {
+ ch = &diag_md[i];
+ kfree(ch->tbl);
+ ch->num_tbl_entries = 0;
+ ch->ops = NULL;
+ }
+}
+
+void diag_md_mdm_exit(void)
+{
+ int i;
+ struct diag_md_info *ch = NULL;
+
+ for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) {
ch = &diag_md[i];
kfree(ch->tbl);
ch->num_tbl_entries = 0;
diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h
index 35a1ee3..9b4aa39 100644
--- a/drivers/char/diag/diag_memorydevice.h
+++ b/drivers/char/diag/diag_memorydevice.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -46,7 +46,9 @@
extern struct diag_md_info diag_md[NUM_DIAG_MD_DEV];
int diag_md_init(void);
+int diag_md_mdm_init(void);
void diag_md_exit(void);
+void diag_md_mdm_exit(void);
void diag_md_open_all(void);
void diag_md_close_all(void);
int diag_md_register(int id, int ctx, struct diag_mux_ops *ops);
diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h
index fc18776..9bbfb82 100644
--- a/drivers/char/diag/diagchar.h
+++ b/drivers/char/diag/diagchar.h
@@ -673,6 +673,7 @@
struct diag_mask_info *log_mask;
struct diag_mask_info *event_mask;
struct diag_mask_info *build_time_mask;
+ uint8_t set_mask_cmd;
uint8_t msg_mask_tbl_count;
uint8_t bt_msg_mask_tbl_count;
uint16_t event_mask_size;
diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c
index 0d3389a..a169230 100644
--- a/drivers/char/diag/diagchar_core.c
+++ b/drivers/char/diag/diagchar_core.c
@@ -969,6 +969,9 @@
poolsize_mdm_dci_write);
diagmem_setsize(POOL_TYPE_QSC_MUX, itemsize_qsc_usb,
poolsize_qsc_usb);
+ diag_md_mdm_init();
+ if (diag_dci_init_remote())
+ return -ENOMEM;
driver->hdlc_encode_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL);
if (!driver->hdlc_encode_buf)
return -ENOMEM;
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 510fc10..f11c1c7 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -409,6 +409,7 @@
msg = ipmi_alloc_smi_msg();
if (!msg) {
ssif_info->ssif_state = SSIF_NORMAL;
+ ipmi_ssif_unlock_cond(ssif_info, flags);
return;
}
@@ -431,6 +432,7 @@
msg = ipmi_alloc_smi_msg();
if (!msg) {
ssif_info->ssif_state = SSIF_NORMAL;
+ ipmi_ssif_unlock_cond(ssif_info, flags);
return;
}
diff --git a/drivers/char/random.c b/drivers/char/random.c
index ee737ef..8a167a6 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -434,8 +434,9 @@
* its value (from 0->1->2).
*/
static int crng_init = 0;
-#define crng_ready() (likely(crng_init > 0))
+#define crng_ready() (likely(crng_init > 1))
static int crng_init_cnt = 0;
+static unsigned long crng_global_init_time = 0;
#define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)
static void _extract_crng(struct crng_state *crng,
__u8 out[CHACHA20_BLOCK_SIZE]);
@@ -741,7 +742,7 @@
static int credit_entropy_bits_safe(struct entropy_store *r, int nbits)
{
- const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1));
+ const int nbits_max = r->poolinfo->poolwords * 32;
if (nbits < 0)
return -EINVAL;
@@ -800,7 +801,7 @@
if (!spin_trylock_irqsave(&primary_crng.lock, flags))
return 0;
- if (crng_ready()) {
+ if (crng_init != 0) {
spin_unlock_irqrestore(&primary_crng.lock, flags);
return 0;
}
@@ -836,7 +837,7 @@
_crng_backtrack_protect(&primary_crng, buf.block,
CHACHA20_KEY_SIZE);
}
- spin_lock_irqsave(&primary_crng.lock, flags);
+ spin_lock_irqsave(&crng->lock, flags);
for (i = 0; i < 8; i++) {
unsigned long rv;
if (!arch_get_random_seed_long(&rv) &&
@@ -852,7 +853,7 @@
wake_up_interruptible(&crng_init_wait);
pr_notice("random: crng init done\n");
}
- spin_unlock_irqrestore(&primary_crng.lock, flags);
+ spin_unlock_irqrestore(&crng->lock, flags);
}
static inline void maybe_reseed_primary_crng(void)
@@ -872,8 +873,9 @@
{
unsigned long v, flags;
- if (crng_init > 1 &&
- time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))
+ if (crng_ready() &&
+ (time_after(crng_global_init_time, crng->init_time) ||
+ time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)))
crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL);
spin_lock_irqsave(&crng->lock, flags);
if (arch_get_random_long(&v))
@@ -1115,12 +1117,16 @@
static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs)
{
__u32 *ptr = (__u32 *) regs;
+ unsigned int idx;
if (regs == NULL)
return 0;
- if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32))
- f->reg_idx = 0;
- return *(ptr + f->reg_idx++);
+ idx = READ_ONCE(f->reg_idx);
+ if (idx >= sizeof(struct pt_regs) / sizeof(__u32))
+ idx = 0;
+ ptr += idx++;
+ WRITE_ONCE(f->reg_idx, idx);
+ return *ptr;
}
void add_interrupt_randomness(int irq, int irq_flags)
@@ -1149,7 +1155,7 @@
fast_mix(fast_pool);
add_interrupt_bench(cycles);
- if (!crng_ready()) {
+ if (unlikely(crng_init == 0)) {
if ((fast_pool->count >= 64) &&
crng_fast_load((char *) fast_pool->pool,
sizeof(fast_pool->pool))) {
@@ -1664,6 +1670,7 @@
init_std_data(&input_pool);
init_std_data(&blocking_pool);
crng_initialize(&primary_crng);
+ crng_global_init_time = jiffies;
#ifdef CONFIG_NUMA
pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL);
@@ -1850,6 +1857,14 @@
input_pool.entropy_count = 0;
blocking_pool.entropy_count = 0;
return 0;
+ case RNDRESEEDCRNG:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (crng_init < 2)
+ return -ENODATA;
+ crng_reseed(&primary_crng, NULL);
+ crng_global_init_time = jiffies - 1;
+ return 0;
default:
return -EINVAL;
}
@@ -2143,7 +2158,7 @@
{
struct entropy_store *poolp = &input_pool;
- if (!crng_ready()) {
+ if (unlikely(crng_init == 0)) {
crng_fast_load(buffer, count);
return;
}
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
index 4e1cd5a..07c8f70 100644
--- a/drivers/clk/at91/clk-generated.c
+++ b/drivers/clk/at91/clk-generated.c
@@ -260,13 +260,13 @@
gck->lock = lock;
gck->range = *range;
+ clk_generated_startup(gck);
hw = &gck->hw;
ret = clk_hw_register(NULL, &gck->hw);
if (ret) {
kfree(gck);
hw = ERR_PTR(ret);
- } else
- clk_generated_startup(gck);
+ }
return hw;
}
diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c
index abdc149..73aab6e 100644
--- a/drivers/clk/bcm/clk-bcm2835.c
+++ b/drivers/clk/bcm/clk-bcm2835.c
@@ -545,9 +545,7 @@
const struct bcm2835_pll_data *data = pll->data;
spin_lock(&cprman->regs_lock);
- cprman_write(cprman, data->cm_ctrl_reg,
- cprman_read(cprman, data->cm_ctrl_reg) |
- CM_PLL_ANARST);
+ cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST);
cprman_write(cprman, data->a2w_ctrl_reg,
cprman_read(cprman, data->a2w_ctrl_reg) |
A2W_PLL_CTRL_PWRDN);
@@ -583,6 +581,10 @@
cpu_relax();
}
+ cprman_write(cprman, data->a2w_ctrl_reg,
+ cprman_read(cprman, data->a2w_ctrl_reg) |
+ A2W_PLL_CTRL_PRST_DISABLE);
+
return 0;
}
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
index 674785d..f0290092 100644
--- a/drivers/clk/clk-conf.c
+++ b/drivers/clk/clk-conf.c
@@ -106,7 +106,7 @@
rc = clk_set_rate(clk, rate);
if (rc < 0)
- pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
+ pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n",
__clk_get_name(clk), rate, rc,
clk_get_rate(clk));
clk_put(clk);
diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
index 96d37175..8ad458b 100644
--- a/drivers/clk/clk-scpi.c
+++ b/drivers/clk/clk-scpi.c
@@ -71,15 +71,15 @@
};
/* find closest match to given frequency in OPP table */
-static int __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
+static long __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
{
int idx;
- u32 fmin = 0, fmax = ~0, ftmp;
+ unsigned long fmin = 0, fmax = ~0, ftmp;
const struct scpi_opp *opp = clk->info->opps;
for (idx = 0; idx < clk->info->count; idx++, opp++) {
ftmp = opp->freq;
- if (ftmp >= (u32)rate) {
+ if (ftmp >= rate) {
if (ftmp <= fmax)
fmax = ftmp;
break;
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 2f29ee1..5588f75 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -7,9 +7,9 @@
bool
depends on COMMON_CLK_AMLOGIC
help
- Support for the clock controller on AmLogic S805 devices, aka
- meson8b. Say Y if you want peripherals and CPU frequency scaling to
- work.
+ Support for the clock controller on AmLogic S802 (Meson8),
+ S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you
+ want peripherals and CPU frequency scaling to work.
config COMMON_CLK_GXBB
bool
diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c
index 3f1be46..70567958 100644
--- a/drivers/clk/meson/meson8b.c
+++ b/drivers/clk/meson/meson8b.c
@@ -1,5 +1,6 @@
/*
- * AmLogic S805 / Meson8b Clock Controller Driver
+ * AmLogic S802 (Meson8) / S805 (Meson8b) / S812 (Meson8m2) Clock Controller
+ * Driver
*
* Copyright (c) 2015 Endless Mobile, Inc.
* Author: Carlo Caione <carlo@endlessm.com>
@@ -661,7 +662,9 @@
}
static const struct of_device_id meson8b_clkc_match_table[] = {
+ { .compatible = "amlogic,meson8-clkc" },
{ .compatible = "amlogic,meson8b-clkc" },
+ { .compatible = "amlogic,meson8m2-clkc" },
{ }
};
diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c
index 57adebf..0e8665c 100644
--- a/drivers/clk/msm/clock-gcc-8953.c
+++ b/drivers/clk/msm/clock-gcc-8953.c
@@ -411,6 +411,27 @@
F_END
};
+static struct clk_freq_tbl ftbl_gfx3d_clk_src_sdm632[] = {
+ F_MM( 19200000, FIXED_CLK_SRC, xo, 1, 0, 0),
+ F_MM( 50000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 8, 0, 0),
+ F_MM( 80000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 5, 0, 0),
+ F_MM( 100000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 4, 0, 0),
+ F_MM( 133330000, FIXED_CLK_SRC, gpll0_main_div2_mm, 3, 0, 0),
+ F_MM( 160000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2.5, 0, 0),
+ F_MM( 200000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2, 0, 0),
+ F_MM( 216000000, FIXED_CLK_SRC, gpll6_main_div2_gfx, 2.5, 0, 0),
+ F_MM( 266670000, FIXED_CLK_SRC, gpll0, 3, 0, 0),
+ F_MM( 320000000, FIXED_CLK_SRC, gpll0, 2.5, 0, 0),
+ F_MM( 400000000, FIXED_CLK_SRC, gpll0, 2, 0, 0),
+ F_MM( 460800000, FIXED_CLK_SRC, gpll4_out_aux, 2.5, 0, 0),
+ F_MM( 510000000, 1020000000, gpll3, 1, 0, 0),
+ F_MM( 560000000, 1120000000, gpll3, 1, 0, 0),
+ F_MM( 650000000, 1300000000, gpll3, 1, 0, 0),
+ F_MM( 700000000, 1400000000, gpll3, 1, 0, 0),
+ F_MM( 725000000, 1450000000, gpll3, 1, 0, 0),
+
+ F_END
+};
static struct rcg_clk gfx3d_clk_src = {
.cmd_rcgr_reg = GFX3D_CMD_RCGR,
.set_rate = set_rate_hid,
@@ -4104,6 +4125,11 @@
if (compat_bin)
gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm450;
+ compat_bin = of_device_is_compatible(pdev->dev.of_node,
+ "qcom,gcc-gfx-sdm632");
+ if (compat_bin)
+ gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm632;
+
ret = of_get_fmax_vdd_class(pdev, &gcc_oxili_gfx3d_clk.c,
"qcom,gfxfreq-corner");
if (ret) {
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c
index f2ed36c..0bdfeeb 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c
@@ -165,7 +165,8 @@
return sel;
}
-static bool pll_is_pll_locked_12nm(struct mdss_pll_resources *pll)
+static bool pll_is_pll_locked_12nm(struct mdss_pll_resources *pll,
+ bool is_handoff)
{
u32 status;
bool pll_locked;
@@ -177,8 +178,9 @@
((status & BIT(1)) > 0),
DSI_PLL_POLL_MAX_READS,
DSI_PLL_POLL_TIMEOUT_US)) {
- pr_err("DSI PLL ndx=%d status=%x failed to Lock\n",
- pll->index, status);
+ if (!is_handoff)
+ pr_err("DSI PLL ndx=%d status=%x failed to Lock\n",
+ pll->index, status);
pll_locked = false;
} else {
pll_locked = true;
@@ -213,7 +215,7 @@
wmb(); /* make sure register committed before enabling branch clocks */
udelay(50); /* h/w recommended delay */
- if (!pll_is_pll_locked_12nm(pll)) {
+ if (!pll_is_pll_locked_12nm(pll, false)) {
pr_err("DSI PLL ndx=%d lock failed!\n",
pll->index);
rc = -EINVAL;
@@ -261,7 +263,7 @@
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_POWERUP_CTRL, data);
ndelay(500); /* h/w recommended delay */
- if (!pll_is_pll_locked_12nm(pll)) {
+ if (!pll_is_pll_locked_12nm(pll, false)) {
pr_err("DSI PLL ndx=%d lock failed!\n",
pll->index);
rc = -EINVAL;
@@ -556,6 +558,142 @@
param->gmp_cntrl = 0x1;
}
+static u32 __mdss_dsi_get_multi_intX100(u64 vco_rate, u32 *rem)
+{
+ u32 reminder = 0;
+ u64 temp = 0;
+ const u32 ref_clk_rate = 19200000, quarterX100 = 25;
+
+ temp = div_u64_rem(vco_rate, ref_clk_rate, &reminder);
+ temp *= 100;
+
+ /*
+ * Multiplication integer needs to be floored in steps of 0.25
+ * Hence multi_intX100 needs to be rounded off in steps of 25
+ */
+ if (reminder < (ref_clk_rate / 4)) {
+ *rem = reminder;
+ return temp;
+ } else if ((reminder >= (ref_clk_rate / 4)) &&
+ reminder < (ref_clk_rate / 2)) {
+ *rem = (reminder - (ref_clk_rate / 4));
+ return (temp + quarterX100);
+ } else if ((reminder >= (ref_clk_rate / 2)) &&
+ (reminder < ((3 * ref_clk_rate) / 4))) {
+ *rem = (reminder - (ref_clk_rate / 2));
+ return (temp + (quarterX100 * 2));
+ }
+
+ *rem = (reminder - ((3 * ref_clk_rate) / 4));
+ return (temp + (quarterX100 * 3));
+}
+
+static u32 __calc_gcd(u32 num1, u32 num2)
+{
+ if (num2 != 0)
+ return __calc_gcd(num2, (num1 % num2));
+ else
+ return num1;
+}
+
+static void mdss_dsi_pll_12nm_calc_ssc(struct mdss_pll_resources *pll,
+ struct dsi_pll_db *pdb)
+{
+ struct dsi_pll_param *param = &pdb->param;
+ u64 multi_intX100 = 0, temp = 0;
+ u32 temp_rem1 = 0, temp_rem2 = 0;
+ const u64 power_2_17 = 131072, power_2_10 = 1024;
+ const u32 ref_clk_rate = 19200000;
+
+ multi_intX100 = __mdss_dsi_get_multi_intX100(pll->vco_current_rate,
+ &temp_rem1);
+
+ /* Calculation for mpll_ssc_peak_i */
+ temp = (multi_intX100 * pll->ssc_ppm * power_2_17);
+ temp = div_u64(temp, 100); /* 100 div for multi_intX100 */
+ param->mpll_ssc_peak_i =
+ (u32) div_u64(temp, 1000000); /*10^6 for SSC PPM */
+
+ /* Calculation for mpll_stepsize_i */
+ param->mpll_stepsize_i = (u32) div_u64((param->mpll_ssc_peak_i *
+ pll->ssc_freq * power_2_10), ref_clk_rate);
+
+ /* Calculation for mpll_mint_i */
+ param->mpll_mint_i = (u32) (div_u64((multi_intX100 * 4), 100) - 32);
+
+ /* Calculation for mpll_frac_den */
+ param->mpll_frac_den = (u32) div_u64(ref_clk_rate,
+ __calc_gcd((u32)pll->vco_current_rate, ref_clk_rate));
+
+ /* Calculation for mpll_frac_quot_i */
+ temp = (temp_rem1 * power_2_17);
+ param->mpll_frac_quot_i =
+ (u32) div_u64_rem(temp, ref_clk_rate, &temp_rem2);
+
+ /* Calculation for mpll_frac_rem */
+ param->mpll_frac_rem = (u32) div_u64(((u64)temp_rem2 *
+ param->mpll_frac_den), ref_clk_rate);
+
+ pr_debug("mpll_ssc_peak_i=%d mpll_stepsize_i=%d mpll_mint_i=%d\n",
+ param->mpll_ssc_peak_i, param->mpll_stepsize_i,
+ param->mpll_mint_i);
+ pr_debug("mpll_frac_den=%d mpll_frac_quot_i=%d mpll_frac_rem=%d",
+ param->mpll_frac_den, param->mpll_frac_quot_i,
+ param->mpll_frac_rem);
+}
+
+static void pll_db_commit_12nm_ssc(struct mdss_pll_resources *pll,
+ struct dsi_pll_db *pdb)
+{
+ void __iomem *pll_base = pll->pll_base;
+ struct dsi_pll_param *param = &pdb->param;
+ char data = 0;
+
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC0, 0x27);
+
+ data = (param->mpll_mint_i & 0xff);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC7, data);
+
+ data = ((param->mpll_mint_i & 0xff00) >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC8, data);
+
+ data = (param->mpll_ssc_peak_i & 0xff);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC1, data);
+
+ data = ((param->mpll_ssc_peak_i & 0xff00) >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC2, data);
+
+ data = ((param->mpll_ssc_peak_i & 0xf0000) >> 16);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC3, data);
+
+ data = (param->mpll_stepsize_i & 0xff);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC4, data);
+
+ data = ((param->mpll_stepsize_i & 0xff00) >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC5, data);
+
+ data = ((param->mpll_stepsize_i & 0x1f0000) >> 16);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC6, data);
+
+ data = (param->mpll_frac_quot_i & 0xff);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC10, data);
+
+ data = ((param->mpll_frac_quot_i & 0xff00) >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC11, data);
+
+ data = (param->mpll_frac_rem & 0xff);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC12, data);
+
+ data = ((param->mpll_frac_rem & 0xff00) >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC13, data);
+
+ data = (param->mpll_frac_den & 0xff);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC14, data);
+
+ data = ((param->mpll_frac_den & 0xff00) >> 8);
+ MDSS_PLL_REG_W(pll_base, DSIPHY_SSC15, data);
+}
+
static void pll_db_commit_12nm(struct mdss_pll_resources *pll,
struct dsi_pll_db *pdb)
{
@@ -616,6 +754,9 @@
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PRO_DLY_RELOCK, 0x0c);
MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOCK_DET_MODE_SEL, 0x02);
+ if (pll->ssc_en)
+ pll_db_commit_12nm_ssc(pll, pdb);
+
pr_debug("pll:%d\n", pll->index);
wmb(); /* make sure register committed before preparing the clocks */
}
@@ -710,7 +851,7 @@
return ret;
}
- if (pll_is_pll_locked_12nm(pll)) {
+ if (pll_is_pll_locked_12nm(pll, true)) {
pll->handoff_resources = true;
pll->pll_on = true;
c->rate = pll_vco_get_rate_12nm(c);
@@ -756,18 +897,27 @@
rc, pll->index);
goto error;
}
+ }
- data = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SYS_CTRL);
- if (data & BIT(7)) { /* DSI PHY in LP-11 or ULPS */
- rc = dsi_pll_relock(pll);
- if (rc)
- goto error;
- else
- goto end;
- }
+ /*
+ * For cases where DSI PHY is already enabled like:
+ * 1.) LP-11 during static screen
+ * 2.) ULPS during static screen
+ * 3.) Boot up with cont splash enabled where PHY is programmed in LK
+ * Execute the Re-lock sequence to enable the DSI PLL.
+ */
+ data = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SYS_CTRL);
+ if (data & BIT(7)) {
+ rc = dsi_pll_relock(pll);
+ if (rc)
+ goto error;
+ else
+ goto end;
}
mdss_dsi_pll_12nm_calc_reg(pll, pdb);
+ if (pll->ssc_en)
+ mdss_dsi_pll_12nm_calc_ssc(pll, pdb);
/* commit DSI vco */
pll_db_commit_12nm(pll, pdb);
@@ -802,6 +952,7 @@
{
struct dsi_pll_vco_clk *vco = to_vco_clk(c);
struct mdss_pll_resources *pll = vco->priv;
+ u32 data = 0;
if (!pll) {
pr_err("Dsi pll resources are not available\n");
@@ -813,7 +964,9 @@
return -EINVAL;
}
- MDSS_PLL_REG_W(pll->pll_base, DSIPHY_SSC0, 0x40);
+ data = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC0);
+ data |= BIT(6); /* enable GP_CLK_EN */
+ MDSS_PLL_REG_W(pll->pll_base, DSIPHY_SSC0, data);
wmb(); /* make sure register committed before enabling branch clocks */
return 0;
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c
index 210742b..5d2fa9a 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c
@@ -636,11 +636,13 @@
};
static struct clk_lookup mdss_dsi_pllcc_12nm[] = {
+ CLK_LIST(dsi0pll_vco_clk),
CLK_LIST(dsi0pll_byte_clk_src),
CLK_LIST(dsi0pll_pixel_clk_src),
};
static struct clk_lookup mdss_dsi_pllcc_12nm_1[] = {
+ CLK_LIST(dsi1pll_vco_clk),
CLK_LIST(dsi1pll_byte_clk_src),
CLK_LIST(dsi1pll_pixel_clk_src),
};
@@ -650,6 +652,9 @@
{
int rc = 0, ndx;
struct dsi_pll_db *pdb;
+ int const ssc_freq_min = 30000; /* min. recommended freq. value */
+ int const ssc_freq_max = 33000; /* max. recommended freq. value */
+ int const ssc_ppm_max = 5000; /* max. recommended ppm */
if (!pdev || !pdev->dev.of_node) {
pr_err("Invalid input parameters\n");
@@ -680,6 +685,21 @@
pixel_div_clk_src_ops = clk_ops_div;
pixel_div_clk_src_ops.prepare = dsi_pll_div_prepare;
+ if (pll_res->ssc_en) {
+ if (!pll_res->ssc_freq || (pll_res->ssc_freq < ssc_freq_min) ||
+ (pll_res->ssc_freq > ssc_freq_max)) {
+ pll_res->ssc_freq = ssc_freq_min;
+ pr_debug("SSC frequency out of recommended range. Set to default=%d\n",
+ pll_res->ssc_freq);
+ }
+
+ if (!pll_res->ssc_ppm || (pll_res->ssc_ppm > ssc_ppm_max)) {
+ pll_res->ssc_ppm = ssc_ppm_max;
+ pr_debug("SSC PPM out of recommended range. Set to default=%d\n",
+ pll_res->ssc_ppm);
+ }
+ }
+
/* Set client data to mux, div and vco clocks. */
if (pll_res->index == DSI_PLL_1) {
dsi1pll_byte_clk_src.priv = pll_res;
diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h
index 6912ff4..0974717 100644
--- a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h
+++ b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h
@@ -37,6 +37,22 @@
#define DSIPHY_PLL_LOOP_DIV_RATIO_1 0x2e8
#define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1 0x328
#define DSIPHY_SSC0 0x394
+#define DSIPHY_SSC7 0x3b0
+#define DSIPHY_SSC8 0x3b4
+#define DSIPHY_SSC1 0x398
+#define DSIPHY_SSC2 0x39c
+#define DSIPHY_SSC3 0x3a0
+#define DSIPHY_SSC4 0x3a4
+#define DSIPHY_SSC5 0x3a8
+#define DSIPHY_SSC6 0x3ac
+#define DSIPHY_SSC10 0x360
+#define DSIPHY_SSC11 0x364
+#define DSIPHY_SSC12 0x368
+#define DSIPHY_SSC13 0x36c
+#define DSIPHY_SSC14 0x370
+#define DSIPHY_SSC15 0x374
+#define DSIPHY_SSC7 0x3b0
+#define DSIPHY_SSC8 0x3b4
#define DSIPHY_SSC9 0x3b8
#define DSIPHY_STAT0 0x3e0
#define DSIPHY_CTRL0 0x3e8
@@ -58,6 +74,14 @@
u32 post_div_mux;
u32 pixel_divhf;
u32 fsm_ovr_ctrl;
+
+ /* ssc_params */
+ u32 mpll_ssc_peak_i;
+ u32 mpll_stepsize_i;
+ u32 mpll_mint_i;
+ u32 mpll_frac_den;
+ u32 mpll_frac_quot_i;
+ u32 mpll_frac_rem;
};
enum {
diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c
index 8bccf4e..9ff4ea6 100644
--- a/drivers/clk/mvebu/armada-38x.c
+++ b/drivers/clk/mvebu/armada-38x.c
@@ -46,10 +46,11 @@
}
static const u32 armada_38x_cpu_frequencies[] __initconst = {
- 0, 0, 0, 0,
- 1066 * 1000 * 1000, 0, 0, 0,
+ 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0,
+ 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0,
1332 * 1000 * 1000, 0, 0, 0,
- 1600 * 1000 * 1000,
+ 1600 * 1000 * 1000, 0, 0, 0,
+ 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000,
};
static u32 __init armada_38x_get_cpu_freq(void __iomem *sar)
@@ -75,11 +76,11 @@
};
static const int armada_38x_cpu_l2_ratios[32][2] __initconst = {
- {0, 1}, {0, 1}, {0, 1}, {0, 1},
+ {1, 2}, {0, 1}, {1, 2}, {0, 1},
+ {1, 2}, {0, 1}, {1, 2}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
- {1, 2}, {0, 1}, {0, 1}, {0, 1},
- {0, 1}, {0, 1}, {0, 1}, {0, 1},
+ {1, 2}, {0, 1}, {0, 1}, {1, 2},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
@@ -90,7 +91,7 @@
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
{1, 2}, {0, 1}, {0, 1}, {0, 1},
- {0, 1}, {0, 1}, {0, 1}, {0, 1},
+ {1, 2}, {0, 1}, {0, 1}, {7, 15},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
{0, 1}, {0, 1}, {0, 1}, {0, 1},
diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h
index aaf2324..f759978 100644
--- a/drivers/clk/qcom/clk-rcg.h
+++ b/drivers/clk/qcom/clk-rcg.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -185,6 +185,7 @@
extern const struct clk_ops clk_pixel_ops;
extern const struct clk_ops clk_gfx3d_ops;
extern const struct clk_ops clk_dp_ops;
+extern const struct clk_ops clk_esc_ops;
extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk,
struct device *dev, u8 rcg_flags);
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 00989a8..057f0e1 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -1191,6 +1191,76 @@
};
EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
+static int clk_esc_determine_rate(struct clk_hw *hw,
+ struct clk_rate_request *req)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ unsigned long parent_rate, div;
+ u32 mask = BIT(rcg->hid_width) - 1;
+ struct clk_hw *p;
+ unsigned long rate = req->rate;
+
+ if (rate == 0)
+ return -EINVAL;
+
+ p = req->best_parent_hw;
+ req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate);
+
+ div = ((2 * parent_rate) / rate) - 1;
+ div = min_t(u32, div, mask);
+
+ req->rate = clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div);
+
+ return 0;
+}
+
+static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_rcg2 *rcg = to_clk_rcg2(hw);
+ struct freq_tbl f = { 0 };
+ unsigned long div;
+ int i, num_parents = clk_hw_get_num_parents(hw);
+ u32 mask = BIT(rcg->hid_width) - 1;
+ u32 cfg;
+
+ div = ((2 * parent_rate) / rate) - 1;
+ div = min_t(u32, div, mask);
+
+ f.pre_div = div;
+
+ regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
+ cfg &= CFG_SRC_SEL_MASK;
+ cfg >>= CFG_SRC_SEL_SHIFT;
+
+ for (i = 0; i < num_parents; i++) {
+ if (cfg == rcg->parent_map[i].cfg) {
+ f.src = rcg->parent_map[i].src;
+ return clk_rcg2_configure(rcg, &f);
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int clk_esc_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate, unsigned long parent_rate, u8 index)
+{
+ return clk_esc_set_rate(hw, rate, parent_rate);
+}
+
+const struct clk_ops clk_esc_ops = {
+ .is_enabled = clk_rcg2_is_enabled,
+ .get_parent = clk_rcg2_get_parent,
+ .set_parent = clk_rcg2_set_parent,
+ .recalc_rate = clk_rcg2_recalc_rate,
+ .determine_rate = clk_esc_determine_rate,
+ .set_rate = clk_esc_set_rate,
+ .set_rate_and_parent = clk_esc_set_rate_and_parent,
+ .list_registers = clk_rcg2_list_registers,
+};
+EXPORT_SYMBOL(clk_esc_ops);
+
/* Common APIs to be used for DFS based RCGR */
static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset,
u32 *mode, u32 *pre_div)
diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c
index d4f27d7..0c49fa4 100644
--- a/drivers/clk/qcom/dispcc-sdm845.c
+++ b/drivers/clk/qcom/dispcc-sdm845.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -328,13 +328,12 @@
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_0,
- .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_esc0_clk_src",
.parent_names = disp_cc_parent_names_0,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_esc_ops,
VDD_CX_FMAX_MAP1(
MIN, 19200000),
},
@@ -345,13 +344,12 @@
.mnd_width = 0,
.hid_width = 5,
.parent_map = disp_cc_parent_map_0,
- .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src,
.clkr.hw.init = &(struct clk_init_data){
.name = "disp_cc_mdss_esc1_clk_src",
.parent_names = disp_cc_parent_names_0,
.num_parents = 4,
.flags = CLK_SET_RATE_PARENT,
- .ops = &clk_rcg2_ops,
+ .ops = &clk_esc_ops,
VDD_CX_FMAX_MAP1(
MIN, 19200000),
},
diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c
index 00e6aba..c55d5fe 100644
--- a/drivers/clk/renesas/clk-rcar-gen2.c
+++ b/drivers/clk/renesas/clk-rcar-gen2.c
@@ -271,11 +271,14 @@
unsigned int extal_div;
unsigned int pll1_mult;
unsigned int pll3_mult;
+ unsigned int pll0_mult; /* For R-Car V2H and E2 only */
};
static const struct cpg_pll_config cpg_pll_configs[8] __initconst = {
- { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 },
- { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 },
+ { 1, 208, 106, 200 }, { 1, 208, 88, 200 },
+ { 1, 156, 80, 150 }, { 1, 156, 66, 150 },
+ { 2, 240, 122, 230 }, { 2, 240, 102, 230 },
+ { 2, 208, 106, 200 }, { 2, 208, 88, 200 },
};
/* SDHI divisors */
@@ -297,6 +300,12 @@
static u32 cpg_mode __initdata;
+static const char * const pll0_mult_match[] = {
+ "renesas,r8a7792-cpg-clocks",
+ "renesas,r8a7794-cpg-clocks",
+ NULL
+};
+
static struct clk * __init
rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
const struct cpg_pll_config *config,
@@ -317,9 +326,15 @@
* clock implementation and we currently have no need to change
* the multiplier value.
*/
- u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+ if (of_device_compatible_match(np, pll0_mult_match)) {
+ /* R-Car V2H and E2 do not have PLL0CR */
+ mult = config->pll0_mult;
+ div = 3;
+ } else {
+ u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+ mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
+ }
parent_name = "main";
- mult = ((value >> 24) & ((1 << 7) - 1)) + 1;
} else if (!strcmp(name, "pll1")) {
parent_name = "main";
mult = config->pll1_mult / 2;
diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c
index eea38f6..3892346 100644
--- a/drivers/clk/renesas/clk-sh73a0.c
+++ b/drivers/clk/renesas/clk-sh73a0.c
@@ -46,7 +46,7 @@
unsigned int shift;
};
-static struct div4_clk div4_clks[] = {
+static const struct div4_clk div4_clks[] = {
{ "zg", "pll0", CPG_FRQCRA, 16 },
{ "m3", "pll1", CPG_FRQCRA, 12 },
{ "b", "pll1", CPG_FRQCRA, 8 },
@@ -79,7 +79,7 @@
{
const struct clk_div_table *table = NULL;
unsigned int shift, reg, width;
- const char *parent_name;
+ const char *parent_name = NULL;
unsigned int mult = 1;
unsigned int div = 1;
@@ -135,7 +135,7 @@
shift = 24;
width = 5;
} else {
- struct div4_clk *c;
+ const struct div4_clk *c;
for (c = div4_clks; c->name; c++) {
if (!strcmp(name, c->name)) {
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 597aa57..379080c 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -45,6 +45,15 @@
If in doubt, say N.
+config CPU_FREQ_TIMES
+ bool "CPU frequency time-in-state statistics"
+ default y
+ help
+ This driver exports CPU time-in-state information through procfs file
+ system.
+
+ If in doubt, say N.
+
choice
prompt "Default CPUFreq governor"
default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index bf98b28..ba9f9405 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -4,7 +4,10 @@
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
-# CPUfreq governors
+# CPUfreq times
+obj-$(CONFIG_CPU_FREQ_TIMES) += cpufreq_times.o
+
+# CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 8059ef9..d82ce73 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -19,6 +19,7 @@
#include <linux/cpu.h>
#include <linux/cpufreq.h>
+#include <linux/cpufreq_times.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/init.h>
@@ -444,6 +445,7 @@
(unsigned long)freqs->new, (unsigned long)freqs->cpu);
trace_cpu_frequency(freqs->new, freqs->cpu);
cpufreq_stats_record_transition(policy, freqs->new);
+ cpufreq_times_record_transition(freqs);
srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
@@ -1373,6 +1375,7 @@
goto out_exit_policy;
cpufreq_stats_create_table(policy);
+ cpufreq_times_create_policy(policy);
blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
CPUFREQ_CREATE_POLICY, policy);
diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c
new file mode 100644
index 0000000..6254f45
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_times.c
@@ -0,0 +1,461 @@
+/* drivers/cpufreq/cpufreq_times.c
+ *
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/cpufreq_times.h>
+#include <linux/cputime.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/threads.h>
+
+#define UID_HASH_BITS 10
+
+static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS);
+
+static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */
+static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */
+
+struct uid_entry {
+ uid_t uid;
+ unsigned int max_state;
+ struct hlist_node hash;
+ struct rcu_head rcu;
+ u64 time_in_state[0];
+};
+
+/**
+ * struct cpu_freqs - per-cpu frequency information
+ * @offset: start of these freqs' stats in task time_in_state array
+ * @max_state: number of entries in freq_table
+ * @last_index: index in freq_table of last frequency switched to
+ * @freq_table: list of available frequencies
+ */
+struct cpu_freqs {
+ unsigned int offset;
+ unsigned int max_state;
+ unsigned int last_index;
+ unsigned int freq_table[0];
+};
+
+static struct cpu_freqs *all_freqs[NR_CPUS];
+
+static unsigned int next_offset;
+
+
+/* Caller must hold rcu_read_lock() */
+static struct uid_entry *find_uid_entry_rcu(uid_t uid)
+{
+ struct uid_entry *uid_entry;
+
+ hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) {
+ if (uid_entry->uid == uid)
+ return uid_entry;
+ }
+ return NULL;
+}
+
+/* Caller must hold uid lock */
+static struct uid_entry *find_uid_entry_locked(uid_t uid)
+{
+ struct uid_entry *uid_entry;
+
+ hash_for_each_possible(uid_hash_table, uid_entry, hash, uid) {
+ if (uid_entry->uid == uid)
+ return uid_entry;
+ }
+ return NULL;
+}
+
+/* Caller must hold uid lock */
+static struct uid_entry *find_or_register_uid_locked(uid_t uid)
+{
+ struct uid_entry *uid_entry, *temp;
+ unsigned int max_state = READ_ONCE(next_offset);
+ size_t alloc_size = sizeof(*uid_entry) + max_state *
+ sizeof(uid_entry->time_in_state[0]);
+
+ uid_entry = find_uid_entry_locked(uid);
+ if (uid_entry) {
+ if (uid_entry->max_state == max_state)
+ return uid_entry;
+ /* uid_entry->time_in_state is too small to track all freqs, so
+ * expand it.
+ */
+ temp = __krealloc(uid_entry, alloc_size, GFP_ATOMIC);
+ if (!temp)
+ return uid_entry;
+ temp->max_state = max_state;
+ memset(temp->time_in_state + uid_entry->max_state, 0,
+ (max_state - uid_entry->max_state) *
+ sizeof(uid_entry->time_in_state[0]));
+ if (temp != uid_entry) {
+ hlist_replace_rcu(&uid_entry->hash, &temp->hash);
+ kfree_rcu(uid_entry, rcu);
+ }
+ return temp;
+ }
+
+ uid_entry = kzalloc(alloc_size, GFP_ATOMIC);
+ if (!uid_entry)
+ return NULL;
+
+ uid_entry->uid = uid;
+ uid_entry->max_state = max_state;
+
+ hash_add_rcu(uid_hash_table, &uid_entry->hash, uid);
+
+ return uid_entry;
+}
+
+static bool freq_index_invalid(unsigned int index)
+{
+ unsigned int cpu;
+ struct cpu_freqs *freqs;
+
+ for_each_possible_cpu(cpu) {
+ freqs = all_freqs[cpu];
+ if (!freqs || index < freqs->offset ||
+ freqs->offset + freqs->max_state <= index)
+ continue;
+ return freqs->freq_table[index - freqs->offset] ==
+ CPUFREQ_ENTRY_INVALID;
+ }
+ return true;
+}
+
+static int single_uid_time_in_state_show(struct seq_file *m, void *ptr)
+{
+ struct uid_entry *uid_entry;
+ unsigned int i;
+ u64 time;
+ uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private);
+
+ if (uid == overflowuid)
+ return -EINVAL;
+
+ rcu_read_lock();
+
+ uid_entry = find_uid_entry_rcu(uid);
+ if (!uid_entry) {
+ rcu_read_unlock();
+ return 0;
+ }
+
+ for (i = 0; i < uid_entry->max_state; ++i) {
+ if (freq_index_invalid(i))
+ continue;
+ time = cputime_to_clock_t(uid_entry->time_in_state[i]);
+ seq_write(m, &time, sizeof(time));
+ }
+
+ rcu_read_unlock();
+
+ return 0;
+}
+
+static void *uid_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ if (*pos >= HASH_SIZE(uid_hash_table))
+ return NULL;
+
+ return &uid_hash_table[*pos];
+}
+
+static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ (*pos)++;
+
+ if (*pos >= HASH_SIZE(uid_hash_table))
+ return NULL;
+
+ return &uid_hash_table[*pos];
+}
+
+static void uid_seq_stop(struct seq_file *seq, void *v) { }
+
+static int uid_time_in_state_seq_show(struct seq_file *m, void *v)
+{
+ struct uid_entry *uid_entry;
+ struct cpu_freqs *freqs, *last_freqs = NULL;
+ int i, cpu;
+
+ if (v == uid_hash_table) {
+ seq_puts(m, "uid:");
+ for_each_possible_cpu(cpu) {
+ freqs = all_freqs[cpu];
+ if (!freqs || freqs == last_freqs)
+ continue;
+ last_freqs = freqs;
+ for (i = 0; i < freqs->max_state; i++) {
+ if (freqs->freq_table[i] ==
+ CPUFREQ_ENTRY_INVALID)
+ continue;
+ seq_printf(m, " %d", freqs->freq_table[i]);
+ }
+ }
+ seq_putc(m, '\n');
+ }
+
+ rcu_read_lock();
+
+ hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
+ if (uid_entry->max_state)
+ seq_printf(m, "%d:", uid_entry->uid);
+ for (i = 0; i < uid_entry->max_state; ++i) {
+ if (freq_index_invalid(i))
+ continue;
+ seq_printf(m, " %lu", (unsigned long)cputime_to_clock_t(
+ uid_entry->time_in_state[i]));
+ }
+ if (uid_entry->max_state)
+ seq_putc(m, '\n');
+ }
+
+ rcu_read_unlock();
+ return 0;
+}
+
+void cpufreq_task_times_init(struct task_struct *p)
+{
+ void *temp;
+ unsigned long flags;
+ unsigned int max_state;
+
+ spin_lock_irqsave(&task_time_in_state_lock, flags);
+ p->time_in_state = NULL;
+ spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+ p->max_state = 0;
+
+ max_state = READ_ONCE(next_offset);
+
+ /* We use one array to avoid multiple allocs per task */
+ temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC);
+ if (!temp)
+ return;
+
+ spin_lock_irqsave(&task_time_in_state_lock, flags);
+ p->time_in_state = temp;
+ spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+ p->max_state = max_state;
+}
+
+/* Caller must hold task_time_in_state_lock */
+static int cpufreq_task_times_realloc_locked(struct task_struct *p)
+{
+ void *temp;
+ unsigned int max_state = READ_ONCE(next_offset);
+
+ temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC);
+ if (!temp)
+ return -ENOMEM;
+ p->time_in_state = temp;
+ memset(p->time_in_state + p->max_state, 0,
+ (max_state - p->max_state) * sizeof(u64));
+ p->max_state = max_state;
+ return 0;
+}
+
+void cpufreq_task_times_exit(struct task_struct *p)
+{
+ unsigned long flags;
+ void *temp;
+
+ if (!p->time_in_state)
+ return;
+
+ spin_lock_irqsave(&task_time_in_state_lock, flags);
+ temp = p->time_in_state;
+ p->time_in_state = NULL;
+ spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+ kfree(temp);
+}
+
+int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
+ struct pid *pid, struct task_struct *p)
+{
+ unsigned int cpu, i;
+ cputime_t cputime;
+ unsigned long flags;
+ struct cpu_freqs *freqs;
+ struct cpu_freqs *last_freqs = NULL;
+
+ spin_lock_irqsave(&task_time_in_state_lock, flags);
+ for_each_possible_cpu(cpu) {
+ freqs = all_freqs[cpu];
+ if (!freqs || freqs == last_freqs)
+ continue;
+ last_freqs = freqs;
+
+ seq_printf(m, "cpu%u\n", cpu);
+ for (i = 0; i < freqs->max_state; i++) {
+ if (freqs->freq_table[i] == CPUFREQ_ENTRY_INVALID)
+ continue;
+ cputime = 0;
+ if (freqs->offset + i < p->max_state &&
+ p->time_in_state)
+ cputime = p->time_in_state[freqs->offset + i];
+ seq_printf(m, "%u %lu\n", freqs->freq_table[i],
+ (unsigned long)cputime_to_clock_t(cputime));
+ }
+ }
+ spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+ return 0;
+}
+
+void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime)
+{
+ unsigned long flags;
+ unsigned int state;
+ struct uid_entry *uid_entry;
+ struct cpu_freqs *freqs = all_freqs[task_cpu(p)];
+ uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
+
+ if (!freqs || p->flags & PF_EXITING)
+ return;
+
+ state = freqs->offset + READ_ONCE(freqs->last_index);
+
+ spin_lock_irqsave(&task_time_in_state_lock, flags);
+ if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) &&
+ p->time_in_state)
+ p->time_in_state[state] += cputime;
+ spin_unlock_irqrestore(&task_time_in_state_lock, flags);
+
+ spin_lock_irqsave(&uid_lock, flags);
+ uid_entry = find_or_register_uid_locked(uid);
+ if (uid_entry && state < uid_entry->max_state)
+ uid_entry->time_in_state[state] += cputime;
+ spin_unlock_irqrestore(&uid_lock, flags);
+}
+
+void cpufreq_times_create_policy(struct cpufreq_policy *policy)
+{
+ int cpu, index;
+ unsigned int count = 0;
+ struct cpufreq_frequency_table *pos, *table;
+ struct cpu_freqs *freqs;
+ void *tmp;
+
+ if (all_freqs[policy->cpu])
+ return;
+
+ table = policy->freq_table;
+ if (!table)
+ return;
+
+ cpufreq_for_each_entry(pos, table)
+ count++;
+
+ tmp = kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count,
+ GFP_KERNEL);
+ if (!tmp)
+ return;
+
+ freqs = tmp;
+ freqs->max_state = count;
+
+ index = cpufreq_frequency_table_get_index(policy, policy->cur);
+ if (index >= 0)
+ WRITE_ONCE(freqs->last_index, index);
+
+ cpufreq_for_each_entry(pos, table)
+ freqs->freq_table[pos - table] = pos->frequency;
+
+ freqs->offset = next_offset;
+ WRITE_ONCE(next_offset, freqs->offset + count);
+ for_each_cpu(cpu, policy->related_cpus)
+ all_freqs[cpu] = freqs;
+}
+
+void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end)
+{
+ struct uid_entry *uid_entry;
+ struct hlist_node *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&uid_lock, flags);
+
+ for (; uid_start <= uid_end; uid_start++) {
+ hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp,
+ hash, uid_start) {
+ if (uid_start == uid_entry->uid) {
+ hash_del_rcu(&uid_entry->hash);
+ kfree_rcu(uid_entry, rcu);
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&uid_lock, flags);
+}
+
+void cpufreq_times_record_transition(struct cpufreq_freqs *freq)
+{
+ int index;
+ struct cpu_freqs *freqs = all_freqs[freq->cpu];
+ struct cpufreq_policy *policy;
+
+ if (!freqs)
+ return;
+
+ policy = cpufreq_cpu_get(freq->cpu);
+ if (!policy)
+ return;
+
+ index = cpufreq_frequency_table_get_index(policy, freq->new);
+ if (index >= 0)
+ WRITE_ONCE(freqs->last_index, index);
+
+ cpufreq_cpu_put(policy);
+}
+
+static const struct seq_operations uid_time_in_state_seq_ops = {
+ .start = uid_seq_start,
+ .next = uid_seq_next,
+ .stop = uid_seq_stop,
+ .show = uid_time_in_state_seq_show,
+};
+
+static int uid_time_in_state_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &uid_time_in_state_seq_ops);
+}
+
+int single_uid_time_in_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, single_uid_time_in_state_show,
+ &(inode->i_uid));
+}
+
+static const struct file_operations uid_time_in_state_fops = {
+ .open = uid_time_in_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init cpufreq_times_init(void)
+{
+ proc_create_data("uid_time_in_state", 0444, NULL,
+ &uid_time_in_state_fops, NULL);
+
+ return 0;
+}
+
+early_initcall(cpufreq_times_init);
diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
index a5c111b..ea11a33 100644
--- a/drivers/cpuidle/dt_idle_states.c
+++ b/drivers/cpuidle/dt_idle_states.c
@@ -174,8 +174,10 @@
if (!state_node)
break;
- if (!of_device_is_available(state_node))
+ if (!of_device_is_available(state_node)) {
+ of_node_put(state_node);
continue;
+ }
if (!idle_state_valid(state_node, i, cpumask)) {
pr_warn("%s idle state not valid, bailing out\n",
diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c
index fe3ef48..7a653c6 100644
--- a/drivers/cpuidle/lpm-levels-of.c
+++ b/drivers/cpuidle/lpm-levels-of.c
@@ -708,7 +708,7 @@
static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c)
{
- int ret, i;
+ int ret;
char *key;
struct lpm_cpu *cpu;
@@ -724,12 +724,12 @@
key = "qcom,psci-mode-shift";
ret = of_property_read_u32(node, key, &cpu->psci_mode_shift);
if (ret)
- goto failed_parse_params;
+ goto failed;
key = "qcom,psci-mode-mask";
ret = of_property_read_u32(node, key, &cpu->psci_mode_mask);
if (ret)
- goto failed_parse_params;
+ goto failed;
key = "qcom,disable-prediction";
cpu->lpm_prediction = !(of_property_read_bool(node, key));
@@ -757,20 +757,14 @@
key = "parse_cpu";
ret = parse_cpu(node, cpu);
if (ret)
- goto failed_parse_cpu;
+ goto failed;
cpumask_or(&c->child_cpus, &c->child_cpus, &cpu->related_cpus);
list_add(&cpu->list, &c->cpu);
return ret;
-failed_parse_cpu:
- for (i = 0; i < cpu->nlevels; i++) {
- kfree(cpu->levels[i].name);
- cpu->levels[i].name = NULL;
- }
-
-failed_parse_params:
+failed:
pr_err("Failed to read key: %s node: %s\n", key, node->name);
return ret;
}
@@ -785,15 +779,8 @@
free_cluster_node(cl);
};
- list_for_each_entry_safe(cpu, n, &cluster->cpu, list) {
- int i;
-
+ list_for_each_entry_safe(cpu, n, &cluster->cpu, list)
list_del(&cpu->list);
- for (i = 0; i < cpu->nlevels; i++) {
- kfree(cpu->levels[i].name);
- cpu->levels[i].name = NULL;
- }
- }
}
/*
@@ -886,7 +873,6 @@
list_del(&c->list);
free_cluster_node(c);
failed_parse_params:
- c->parent = NULL;
pr_err("Failed parse params\n");
return NULL;
}
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 9ae640d..9694225 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -1783,12 +1783,10 @@
#endif
rc = platform_driver_register(&lpm_driver);
- if (rc) {
- pr_info("Error registering %s\n", lpm_driver.driver.name);
- goto fail;
- }
+ if (rc)
+ pr_info("Error registering %s rc=%d\n", lpm_driver.driver.name,
+ rc);
-fail:
return rc;
}
late_initcall(lpm_levels_module_init);
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index d0b16e5..d8305dd 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -750,7 +750,10 @@
if (final)
new_len = DIV_ROUND_UP(new_len, bs) * bs;
else
- new_len = new_len / bs * bs;
+ new_len = (new_len - 1) / bs * bs;
+
+ if (nbytes != new_len)
+ list_ok = false;
while (nbytes > 0 && sg_tmp) {
n++;
@@ -846,6 +849,8 @@
xmit_len = DIV_ROUND_UP(xmit_len, bs) * bs;
else
xmit_len = xmit_len / bs * bs;
+ } else if (!final) {
+ xmit_len -= bs;
}
hash_later = rctx->total - xmit_len;
@@ -873,14 +878,21 @@
}
if (hash_later) {
- if (req->nbytes) {
- scatterwalk_map_and_copy(rctx->buffer, req->src,
- req->nbytes - hash_later,
- hash_later, 0);
- } else {
+ int offset = 0;
+
+ if (hash_later > req->nbytes) {
memcpy(rctx->buffer, rctx->buffer + xmit_len,
- hash_later);
+ hash_later - req->nbytes);
+ offset = hash_later - req->nbytes;
}
+
+ if (req->nbytes) {
+ scatterwalk_map_and_copy(rctx->buffer + offset,
+ req->src,
+ offset + req->nbytes -
+ hash_later, hash_later, 0);
+ }
+
rctx->bufcnt = hash_later;
} else {
rctx->bufcnt = 0;
@@ -1130,7 +1142,7 @@
ctx = ahash_request_ctx(req);
err = omap_sham_prepare_request(req, ctx->op == OP_UPDATE);
- if (err)
+ if (err || !ctx->total)
goto err1;
dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n",
@@ -1189,11 +1201,10 @@
if (!req->nbytes)
return 0;
- if (ctx->total + req->nbytes < ctx->buflen) {
+ if (ctx->bufcnt + req->nbytes <= ctx->buflen) {
scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src,
0, req->nbytes, 0);
ctx->bufcnt += req->nbytes;
- ctx->total += req->nbytes;
return 0;
}
diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c
index 1dca479..81f7c16 100644
--- a/drivers/devfreq/arm-memlat-mon.c
+++ b/drivers/devfreq/arm-memlat-mon.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -82,7 +82,7 @@
{
ktime_t ts;
unsigned int diff;
- unsigned long freq = 0;
+ uint64_t freq = 0;
ts = ktime_get();
diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts));
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 3357aaf..2298de2 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -969,7 +969,8 @@
if (df->governor == governor) {
ret = 0;
goto out;
- } else if (df->governor->immutable || governor->immutable) {
+ } else if ((df->governor && df->governor->immutable) ||
+ governor->immutable) {
ret = -EINVAL;
goto out;
}
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index b7d7f2d..ee7b48d 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -1473,10 +1473,10 @@
for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) {
check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
rmb();
- initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
- rmb();
cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC);
rmb();
+ initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD);
+ rmb();
cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc;
rmb();
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 21726a2..b9c2972 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1755,19 +1755,26 @@
if (IS_ERR(sdma->clk_ahb))
return PTR_ERR(sdma->clk_ahb);
- clk_prepare(sdma->clk_ipg);
- clk_prepare(sdma->clk_ahb);
+ ret = clk_prepare(sdma->clk_ipg);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare(sdma->clk_ahb);
+ if (ret)
+ goto err_clk;
ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma",
sdma);
if (ret)
- return ret;
+ goto err_irq;
sdma->irq = irq;
sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
- if (!sdma->script_addrs)
- return -ENOMEM;
+ if (!sdma->script_addrs) {
+ ret = -ENOMEM;
+ goto err_irq;
+ }
/* initially no scripts available */
saddr_arr = (s32 *)sdma->script_addrs;
@@ -1882,6 +1889,10 @@
dma_async_device_unregister(&sdma->dma_device);
err_init:
kfree(sdma->script_addrs);
+err_irq:
+ clk_unprepare(sdma->clk_ahb);
+err_clk:
+ clk_unprepare(sdma->clk_ipg);
return ret;
}
@@ -1893,6 +1904,8 @@
devm_free_irq(&pdev->dev, sdma->irq, sdma);
dma_async_device_unregister(&sdma->dma_device);
kfree(sdma->script_addrs);
+ clk_unprepare(sdma->clk_ahb);
+ clk_unprepare(sdma->clk_ipg);
/* Kill the tasklet */
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index cb9b857..61c19b8 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -759,7 +759,7 @@
/* Non-ECC RAM? */
printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__);
res = -ENODEV;
- goto err2;
+ goto err;
}
edac_dbg(3, "init mci\n");
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 3d50bae..1f81e63 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -59,7 +59,10 @@
return cpu == resident_cpu;
}
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+ .conduit = PSCI_CONDUIT_NONE,
+ .smccc_version = SMCCC_VERSION_1_0,
+};
typedef unsigned long (psci_fn)(unsigned long, unsigned long,
unsigned long, unsigned long);
@@ -210,6 +213,22 @@
0, 0, 0);
}
+static void set_conduit(enum psci_conduit conduit)
+{
+ switch (conduit) {
+ case PSCI_CONDUIT_HVC:
+ invoke_psci_fn = __invoke_psci_fn_hvc;
+ break;
+ case PSCI_CONDUIT_SMC:
+ invoke_psci_fn = __invoke_psci_fn_smc;
+ break;
+ default:
+ WARN(1, "Unexpected PSCI conduit %d\n", conduit);
+ }
+
+ psci_ops.conduit = conduit;
+}
+
static int get_set_conduit_method(struct device_node *np)
{
const char *method;
@@ -222,9 +241,9 @@
}
if (!strcmp("hvc", method)) {
- invoke_psci_fn = __invoke_psci_fn_hvc;
+ set_conduit(PSCI_CONDUIT_HVC);
} else if (!strcmp("smc", method)) {
- invoke_psci_fn = __invoke_psci_fn_smc;
+ set_conduit(PSCI_CONDUIT_SMC);
} else {
pr_warn("invalid \"method\" property: %s\n", method);
return -EINVAL;
@@ -495,6 +514,31 @@
pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
}
+static void __init psci_init_smccc(void)
+{
+ u32 ver = ARM_SMCCC_VERSION_1_0;
+ int feature;
+
+ feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+ if (feature != PSCI_RET_NOT_SUPPORTED) {
+ u32 ret;
+ ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+ if (ret == ARM_SMCCC_VERSION_1_1) {
+ psci_ops.smccc_version = SMCCC_VERSION_1_1;
+ ver = ret;
+ }
+ }
+
+ /*
+ * Conveniently, the SMCCC and PSCI versions are encoded the
+ * same way. No, this isn't accidental.
+ */
+ pr_info("SMC Calling Convention v%d.%d\n",
+ PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
+
+}
+
static void __init psci_0_2_set_functions(void)
{
pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -543,6 +587,7 @@
psci_init_migrate();
if (PSCI_VERSION_MAJOR(ver) >= 1) {
+ psci_init_smccc();
psci_init_cpu_suspend();
psci_init_system_suspend();
}
@@ -656,9 +701,9 @@
pr_info("probing for conduit method from ACPI.\n");
if (acpi_psci_use_hvc())
- invoke_psci_fn = __invoke_psci_fn_hvc;
+ set_conduit(PSCI_CONDUIT_HVC);
else
- invoke_psci_fn = __invoke_psci_fn_smc;
+ set_conduit(PSCI_CONDUIT_SMC);
return psci_probe();
}
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index 7c446d1..1d87b07 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -90,8 +90,18 @@
{
int reg;
- if (gpio == 94)
- return GPIOPANELCTL;
+ if (gpio >= CRYSTALCOVE_GPIO_NUM) {
+ /*
+ * Virtual GPIO called from ACPI, for now we only support
+ * the panel ctl.
+ */
+ switch (gpio) {
+ case 0x5e:
+ return GPIOPANELCTL;
+ default:
+ return -EOPNOTSUPP;
+ }
+ }
if (reg_type == CTRL_IN) {
if (gpio < 8)
@@ -130,36 +140,36 @@
static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
+ int reg = to_reg(gpio, CTRL_OUT);
- if (gpio > CRYSTALCOVE_VGPIO_NUM)
+ if (reg < 0)
return 0;
- return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
- CTLO_INPUT_SET);
+ return regmap_write(cg->regmap, reg, CTLO_INPUT_SET);
}
static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio,
int value)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
+ int reg = to_reg(gpio, CTRL_OUT);
- if (gpio > CRYSTALCOVE_VGPIO_NUM)
+ if (reg < 0)
return 0;
- return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT),
- CTLO_OUTPUT_SET | value);
+ return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value);
}
static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
- int ret;
unsigned int val;
+ int ret, reg = to_reg(gpio, CTRL_IN);
- if (gpio > CRYSTALCOVE_VGPIO_NUM)
+ if (reg < 0)
return 0;
- ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val);
+ ret = regmap_read(cg->regmap, reg, &val);
if (ret)
return ret;
@@ -170,14 +180,15 @@
unsigned gpio, int value)
{
struct crystalcove_gpio *cg = gpiochip_get_data(chip);
+ int reg = to_reg(gpio, CTRL_OUT);
- if (gpio > CRYSTALCOVE_VGPIO_NUM)
+ if (reg < 0)
return;
if (value)
- regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1);
+ regmap_update_bits(cg->regmap, reg, 1, 1);
else
- regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 0);
+ regmap_update_bits(cg->regmap, reg, 1, 0);
}
static int crystalcove_irq_type(struct irq_data *data, unsigned type)
@@ -185,6 +196,9 @@
struct crystalcove_gpio *cg =
gpiochip_get_data(irq_data_get_irq_chip_data(data));
+ if (data->hwirq >= CRYSTALCOVE_GPIO_NUM)
+ return 0;
+
switch (type) {
case IRQ_TYPE_NONE:
cg->intcnt_value = CTLI_INTCNT_DIS;
@@ -235,8 +249,10 @@
struct crystalcove_gpio *cg =
gpiochip_get_data(irq_data_get_irq_chip_data(data));
- cg->set_irq_mask = false;
- cg->update |= UPDATE_IRQ_MASK;
+ if (data->hwirq < CRYSTALCOVE_GPIO_NUM) {
+ cg->set_irq_mask = false;
+ cg->update |= UPDATE_IRQ_MASK;
+ }
}
static void crystalcove_irq_mask(struct irq_data *data)
@@ -244,8 +260,10 @@
struct crystalcove_gpio *cg =
gpiochip_get_data(irq_data_get_irq_chip_data(data));
- cg->set_irq_mask = true;
- cg->update |= UPDATE_IRQ_MASK;
+ if (data->hwirq < CRYSTALCOVE_GPIO_NUM) {
+ cg->set_irq_mask = true;
+ cg->update |= UPDATE_IRQ_MASK;
+ }
}
static struct irq_chip crystalcove_irqchip = {
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index f3c3680..4f54ff4 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -3231,7 +3231,8 @@
return desc;
}
- status = gpiod_request(desc, con_id);
+ /* 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 (status < 0)
return ERR_PTR(status);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
index 0e8f897..0217f5d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
@@ -569,6 +569,7 @@
{ 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
+ { 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX },
{ 0, 0, 0, 0, 0 },
};
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
index c02db01f6..fe011c7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c
@@ -201,8 +201,10 @@
for (i = 0; i < list->num_entries; i++) {
unsigned priority = list->array[i].priority;
- list_add_tail(&list->array[i].tv.head,
- &bucket[priority]);
+ if (!list->array[i].robj->parent)
+ list_add_tail(&list->array[i].tv.head,
+ &bucket[priority]);
+
list->array[i].user_pages = NULL;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index cb505f6..c801624 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -519,7 +519,7 @@
INIT_LIST_HEAD(&duplicates);
amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd);
- if (p->uf_entry.robj)
+ if (p->uf_entry.robj && !p->uf_entry.robj->parent)
list_add(&p->uf_entry.tv.head, &p->validated);
if (need_mmap_lock)
diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
index 002862b..3fa8320 100644
--- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c
@@ -6449,9 +6449,9 @@
{
u32 lane_width;
u32 new_lane_width =
- (amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+ ((amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
u32 current_lane_width =
- (amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+ ((amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
if (new_lane_width != current_lane_width) {
amdgpu_set_pcie_lanes(adev, new_lane_width);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index ef7c8de..171480b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -317,7 +317,8 @@
/* init process apertures*/
process->is_32bit_user_mode = in_compat_syscall();
- if (kfd_init_apertures(process) != 0)
+ err = kfd_init_apertures(process);
+ if (err != 0)
goto err_init_apretures;
return process;
diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c
index 5e73dfa..bfe98b5 100644
--- a/drivers/gpu/drm/msm/dp/dp_catalog.c
+++ b/drivers/gpu/drm/msm/dp/dp_catalog.c
@@ -772,8 +772,6 @@
catalog = dp_catalog_get_priv(ctrl);
io_data = catalog->io.dp_link;
- misc_val = dp_read(catalog, io_data, DP_MISC1_MISC0);
- misc_val |= cc;
misc_val |= (tb << 5);
misc_val |= BIT(0); /* Configure clock to synchronous mode */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
index d083e72..a457070 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c
@@ -214,6 +214,7 @@
phy->ops.ulps_ops.is_lanes_in_ulps =
dsi_phy_hw_v3_0_is_lanes_in_ulps;
phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0;
+ phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl;
phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset;
phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo;
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
index 0e2db430..144ccd9 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h
@@ -102,6 +102,7 @@
bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes);
int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
u32 *timing_val, u32 size);
+void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy);
void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
index d89760e..bdc60d2 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h
@@ -43,6 +43,13 @@
DSI_LINK_CLK_MAX,
};
+enum dsi_link_clk_op_type {
+ DSI_LINK_CLK_SET_RATE = BIT(0),
+ DSI_LINK_CLK_PREPARE = BIT(1),
+ DSI_LINK_CLK_ENABLE = BIT(2),
+ DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2),
+};
+
enum dsi_clk_type {
DSI_CORE_CLK = BIT(0),
DSI_LINK_CLK = BIT(1),
@@ -50,6 +57,12 @@
DSI_CLKS_MAX = BIT(2),
};
+enum dsi_lclk_type {
+ DSI_LINK_NONE = 0,
+ DSI_LINK_LP_CLK = BIT(0),
+ DSI_LINK_HS_CLK = BIT(1),
+};
+
struct dsi_clk_ctrl_info {
enum dsi_clk_type clk_type;
enum dsi_clk_state clk_state;
@@ -82,23 +95,29 @@
};
/**
- * struct dsi_link_clk_info - Link clock information for DSI hardware.
- * @byte_clk: Handle to DSI byte clock.
- * @pixel_clk: Handle to DSI pixel clock.
- * @esc_clk: Handle to DSI escape clock.
+ * struct dsi_link_hs_clk_info - Set of high speed link clocks for DSI HW
+ * @byte_clk: Handle to DSI byte_clk.
+ * @pixel_clk: Handle to DSI pixel_clk.
* @byte_intf_clk: Handle to DSI byte intf. clock.
*/
-struct dsi_link_clk_info {
+struct dsi_link_hs_clk_info {
struct clk *byte_clk;
struct clk *pixel_clk;
- struct clk *esc_clk;
struct clk *byte_intf_clk;
};
/**
+ * struct dsi_link_lp_clk_info - Set of low power link clocks for DSI HW.
+ * @esc_clk: Handle to DSI escape clock.
+ */
+struct dsi_link_lp_clk_info {
+ struct clk *esc_clk;
+};
+
+/**
* struct link_clk_freq - Clock frequency information for Link clocks
- * @byte_clk_rate: Frequency of DSI byte clock in KHz.
- * @pixel_clk_rate: Frequency of DSI pixel clock in KHz.
+ * @byte_clk_rate: Frequency of DSI byte_clk in KHz.
+ * @pixel_clk_rate: Frequency of DSI pixel_clk in KHz.
* @esc_clk_rate: Frequency of DSI escape clock in KHz.
*/
struct link_clk_freq {
@@ -111,48 +130,56 @@
* typedef *pre_clockoff_cb() - Callback before clock is turned off
* @priv: private data pointer.
* @clk_type: clock which is being turned off.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @new_state: next state for the clock.
*
* @return: error code.
*/
typedef int (*pre_clockoff_cb)(void *priv,
enum dsi_clk_type clk_type,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state new_state);
/**
* typedef *post_clockoff_cb() - Callback after clock is turned off
* @priv: private data pointer.
* @clk_type: clock which was turned off.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @curr_state: current state for the clock.
*
* @return: error code.
*/
typedef int (*post_clockoff_cb)(void *priv,
enum dsi_clk_type clk_type,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state curr_state);
/**
* typedef *post_clockon_cb() - Callback after clock is turned on
* @priv: private data pointer.
* @clk_type: clock which was turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @curr_state: current state for the clock.
*
* @return: error code.
*/
typedef int (*post_clockon_cb)(void *priv,
enum dsi_clk_type clk_type,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state curr_state);
/**
* typedef *pre_clockon_cb() - Callback before clock is turned on
* @priv: private data pointer.
* @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type.Valid only for link clocks.
* @new_state: next state for the clock.
*
* @return: error code.
*/
typedef int (*pre_clockon_cb)(void *priv,
enum dsi_clk_type clk_type,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state new_state);
@@ -160,7 +187,8 @@
* struct dsi_clk_info - clock information for DSI hardware.
* @name: client name.
* @c_clks[MAX_DSI_CTRL] array of core clock configurations
- * @l_clks[MAX_DSI_CTRL] array of link clock configurations
+ * @l_lp_clks[MAX_DSI_CTRL] array of low power(esc) clock configurations
+ * @l_hs_clks[MAX_DSI_CTRL] array of high speed clock configurations
* @bus_handle[MAX_DSI_CTRL] array of bus handles
* @ctrl_index[MAX_DSI_CTRL] array of DSI controller indexes mapped
* to core and link clock configurations
@@ -175,7 +203,8 @@
struct dsi_clk_info {
char name[MAX_STRING_LEN];
struct dsi_core_clk_info c_clks[MAX_DSI_CTRL];
- struct dsi_link_clk_info l_clks[MAX_DSI_CTRL];
+ struct dsi_link_lp_clk_info l_lp_clks[MAX_DSI_CTRL];
+ struct dsi_link_hs_clk_info l_hs_clks[MAX_DSI_CTRL];
u32 bus_handle[MAX_DSI_CTRL];
u32 ctrl_index[MAX_DSI_CTRL];
pre_clockoff_cb pre_clkoff_cb;
@@ -189,8 +218,8 @@
/**
* struct dsi_clk_link_set - Pair of clock handles to describe link clocks
- * @byte_clk: Handle to DSi byte clock.
- * @pixel_clk: Handle to DSI pixel clock.
+ * @byte_clk: Handle to DSi byte_clk.
+ * @pixel_clk: Handle to DSI pixel_clk.
*/
struct dsi_clk_link_set {
struct clk *byte_clk;
@@ -263,10 +292,10 @@
/**
- * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
+ * dsi_clk_set_pixel_clk_rate() - set frequency for pixel_clk
* @client: DSI clock client pointer.
- * @pixel_clk: Pixel clock rate in Hz.
- * @index: Index of the DSI controller.
+ * @pixel_clk: Pixel_clk rate in Hz.
+ * @index: Index of the DSI controller.
* return: error code in case of failure or 0 for success.
*/
int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
index 434d383..2e3828e 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c
@@ -24,7 +24,8 @@
};
struct dsi_link_clks {
- struct dsi_link_clk_info clks;
+ struct dsi_link_hs_clk_info hs_clks;
+ struct dsi_link_lp_clk_info lp_clks;
struct link_clk_freq freq;
};
@@ -124,7 +125,7 @@
struct dsi_clk_mngr *mngr;
mngr = c->mngr;
- rc = clk_set_rate(mngr->link_clks[index].clks.pixel_clk, pixel_clk);
+ rc = clk_set_rate(mngr->link_clks[index].hs_clks.pixel_clk, pixel_clk);
if (rc)
pr_err("failed to set clk rate for pixel clk, rc=%d\n", rc);
else
@@ -147,7 +148,7 @@
struct dsi_clk_mngr *mngr;
mngr = c->mngr;
- rc = clk_set_rate(mngr->link_clks[index].clks.byte_clk, byte_clk);
+ rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
if (rc)
pr_err("failed to set clk rate for byte clk, rc=%d\n", rc);
else
@@ -285,38 +286,39 @@
return rc;
}
-static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index)
+static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks,
+ int index)
{
int rc = 0;
struct dsi_clk_mngr *mngr;
+ struct dsi_link_clks *l_clks;
if (index >= MAX_DSI_CTRL) {
pr_err("Invalid DSI ctrl index\n");
return -EINVAL;
}
+ l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]);
- if (mngr->is_cont_splash_enabled)
- return 0;
+
/*
* In an ideal world, cont_splash_enabled should not be required inside
* the clock manager. But, in the current driver cont_splash_enabled
* flag is set inside mdp driver and there is no interface event
* associated with this flag setting.
*/
- rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->freq.esc_clk_rate);
- if (rc) {
- pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
- goto error;
- }
+ if (mngr->is_cont_splash_enabled)
+ return 0;
- rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->freq.byte_clk_rate);
+ rc = clk_set_rate(link_hs_clks->byte_clk,
+ l_clks->freq.byte_clk_rate);
if (rc) {
pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
goto error;
}
- rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->freq.pix_clk_rate);
+ rc = clk_set_rate(link_hs_clks->pixel_clk,
+ l_clks->freq.pix_clk_rate);
if (rc) {
pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
goto error;
@@ -327,8 +329,8 @@
* For DPHY: byte_intf_clk_rate = byte_clk_rate / 2
* todo: this needs to be revisited when support for CPHY is added
*/
- if (l_clks->clks.byte_intf_clk) {
- rc = clk_set_rate(l_clks->clks.byte_intf_clk,
+ if (link_hs_clks->byte_intf_clk) {
+ rc = clk_set_rate(link_hs_clks->byte_intf_clk,
(l_clks->freq.byte_clk_rate / 2));
if (rc) {
pr_err("set_rate failed for byte_intf_clk rc = %d\n",
@@ -340,30 +342,24 @@
return rc;
}
-static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_prepare(struct dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
- rc = clk_prepare(l_clks->clks.esc_clk);
- if (rc) {
- pr_err("Failed to prepare dsi esc clk, rc=%d\n", rc);
- goto esc_clk_err;
- }
-
- rc = clk_prepare(l_clks->clks.byte_clk);
+ rc = clk_prepare(link_hs_clks->byte_clk);
if (rc) {
pr_err("Failed to prepare dsi byte clk, rc=%d\n", rc);
goto byte_clk_err;
}
- rc = clk_prepare(l_clks->clks.pixel_clk);
+ rc = clk_prepare(link_hs_clks->pixel_clk);
if (rc) {
pr_err("Failed to prepare dsi pixel clk, rc=%d\n", rc);
goto pixel_clk_err;
}
- if (l_clks->clks.byte_intf_clk) {
- rc = clk_prepare(l_clks->clks.byte_intf_clk);
+ if (link_hs_clks->byte_intf_clk) {
+ rc = clk_prepare(link_hs_clks->byte_intf_clk);
if (rc) {
pr_err("Failed to prepare dsi byte intf clk, rc=%d\n",
rc);
@@ -374,48 +370,39 @@
return rc;
byte_intf_clk_err:
- clk_unprepare(l_clks->clks.pixel_clk);
+ clk_unprepare(link_hs_clks->pixel_clk);
pixel_clk_err:
- clk_unprepare(l_clks->clks.byte_clk);
+ clk_unprepare(link_hs_clks->byte_clk);
byte_clk_err:
- clk_unprepare(l_clks->clks.esc_clk);
-esc_clk_err:
return rc;
}
-static void dsi_link_clk_unprepare(struct dsi_link_clks *l_clks)
+static void dsi_link_hs_clk_unprepare(struct dsi_link_hs_clk_info *link_hs_clks)
{
- if (l_clks->clks.byte_intf_clk)
- clk_unprepare(l_clks->clks.byte_intf_clk);
- clk_unprepare(l_clks->clks.pixel_clk);
- clk_unprepare(l_clks->clks.byte_clk);
- clk_unprepare(l_clks->clks.esc_clk);
+ if (link_hs_clks->byte_intf_clk)
+ clk_unprepare(link_hs_clks->byte_intf_clk);
+ clk_unprepare(link_hs_clks->pixel_clk);
+ clk_unprepare(link_hs_clks->byte_clk);
}
-static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
+static int dsi_link_hs_clk_enable(struct dsi_link_hs_clk_info *link_hs_clks)
{
int rc = 0;
- rc = clk_enable(l_clks->clks.esc_clk);
- if (rc) {
- pr_err("Failed to enable dsi esc clk, rc=%d\n", rc);
- goto esc_clk_err;
- }
-
- rc = clk_enable(l_clks->clks.byte_clk);
+ rc = clk_enable(link_hs_clks->byte_clk);
if (rc) {
pr_err("Failed to enable dsi byte clk, rc=%d\n", rc);
goto byte_clk_err;
}
- rc = clk_enable(l_clks->clks.pixel_clk);
+ rc = clk_enable(link_hs_clks->pixel_clk);
if (rc) {
pr_err("Failed to enable dsi pixel clk, rc=%d\n", rc);
goto pixel_clk_err;
}
- if (l_clks->clks.byte_intf_clk) {
- rc = clk_enable(l_clks->clks.byte_intf_clk);
+ if (link_hs_clks->byte_intf_clk) {
+ rc = clk_enable(link_hs_clks->byte_intf_clk);
if (rc) {
pr_err("Failed to enable dsi byte intf clk, rc=%d\n",
rc);
@@ -426,28 +413,26 @@
return rc;
byte_intf_clk_err:
- clk_disable(l_clks->clks.pixel_clk);
+ clk_disable(link_hs_clks->pixel_clk);
pixel_clk_err:
- clk_disable(l_clks->clks.byte_clk);
+ clk_disable(link_hs_clks->byte_clk);
byte_clk_err:
- clk_disable(l_clks->clks.esc_clk);
-esc_clk_err:
return rc;
}
-static void dsi_link_clk_disable(struct dsi_link_clks *l_clks)
+static void dsi_link_hs_clk_disable(struct dsi_link_hs_clk_info *link_hs_clks)
{
- if (l_clks->clks.byte_intf_clk)
- clk_disable(l_clks->clks.byte_intf_clk);
- clk_disable(l_clks->clks.esc_clk);
- clk_disable(l_clks->clks.pixel_clk);
- clk_disable(l_clks->clks.byte_clk);
+ if (link_hs_clks->byte_intf_clk)
+ clk_disable(link_hs_clks->byte_intf_clk);
+ clk_disable(link_hs_clks->pixel_clk);
+ clk_disable(link_hs_clks->byte_clk);
}
/**
* dsi_link_clk_start() - enable dsi link clocks
*/
-static int dsi_link_clk_start(struct dsi_link_clks *clks, int index)
+static int dsi_link_hs_clk_start(struct dsi_link_hs_clk_info *link_hs_clks,
+ enum dsi_link_clk_op_type op_type, int index)
{
int rc = 0;
@@ -456,28 +441,34 @@
return -EINVAL;
}
- rc = dsi_link_clk_set_rate(clks, index);
- if (rc) {
- pr_err("failed to set clk rates, rc = %d\n", rc);
- goto error;
+ if (op_type & DSI_LINK_CLK_SET_RATE) {
+ rc = dsi_link_hs_clk_set_rate(link_hs_clks, index);
+ if (rc) {
+ pr_err("failed to set HS clk rates, rc = %d\n", rc);
+ goto error;
+ }
}
- rc = dsi_link_clk_prepare(clks);
- if (rc) {
- pr_err("failed to prepare link clks, rc = %d\n", rc);
- goto error;
+ if (op_type & DSI_LINK_CLK_PREPARE) {
+ rc = dsi_link_hs_clk_prepare(link_hs_clks);
+ if (rc) {
+ pr_err("failed to prepare link HS clks, rc = %d\n", rc);
+ goto error;
+ }
}
- rc = dsi_link_clk_enable(clks);
- if (rc) {
- pr_err("failed to enable link clks, rc = %d\n", rc);
- goto error_unprepare;
+ if (op_type & DSI_LINK_CLK_ENABLE) {
+ rc = dsi_link_hs_clk_enable(link_hs_clks);
+ if (rc) {
+ pr_err("failed to enable link HS clks, rc = %d\n", rc);
+ goto error_unprepare;
+ }
}
- pr_debug("Link clocks are enabled\n");
+ pr_debug("HS Link clocks are enabled\n");
return rc;
error_unprepare:
- dsi_link_clk_unprepare(clks);
+ dsi_link_hs_clk_unprepare(link_hs_clks);
error:
return rc;
}
@@ -485,13 +476,69 @@
/**
* dsi_link_clk_stop() - Stop DSI link clocks.
*/
-int dsi_link_clk_stop(struct dsi_link_clks *clks)
+static int dsi_link_hs_clk_stop(struct dsi_link_hs_clk_info *link_hs_clks)
{
- dsi_link_clk_disable(clks);
- dsi_link_clk_unprepare(clks);
+ struct dsi_link_clks *l_clks;
- pr_debug("Link clocks disabled\n");
+ l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks);
+ dsi_link_hs_clk_disable(link_hs_clks);
+ dsi_link_hs_clk_unprepare(link_hs_clks);
+
+ pr_debug("HS Link clocks disabled\n");
+
+ return 0;
+}
+
+static int dsi_link_lp_clk_start(struct dsi_link_lp_clk_info *link_lp_clks)
+{
+ int rc = 0;
+ struct dsi_clk_mngr *mngr;
+ struct dsi_link_clks *l_clks;
+
+ l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);
+
+ mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
+ if (!mngr)
+ return -EINVAL;
+ /*
+ * In an ideal world, cont_splash_enabled should not be required inside
+ * the clock manager. But, in the current driver cont_splash_enabled
+ * flag is set inside mdp driver and there is no interface event
+ * associated with this flag setting. Also, set rate for clock need not
+ * be called for every enable call. It should be done only once when
+ * coming out of suspend.
+ */
+ if (mngr->is_cont_splash_enabled)
+ goto prepare;
+
+ rc = clk_set_rate(link_lp_clks->esc_clk, l_clks->freq.esc_clk_rate);
+ if (rc) {
+ pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
+ goto error;
+ }
+
+prepare:
+ rc = clk_prepare_enable(link_lp_clks->esc_clk);
+ if (rc) {
+ pr_err("Failed to enable dsi esc clk\n");
+ clk_unprepare(l_clks->lp_clks.esc_clk);
+ }
+error:
+ pr_debug("LP Link clocks are enabled\n");
+ return rc;
+}
+
+static int dsi_link_lp_clk_stop(
+ struct dsi_link_lp_clk_info *link_lp_clks)
+{
+ struct dsi_link_clks *l_clks;
+
+ l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks);
+
+ clk_disable_unprepare(l_clks->lp_clks.esc_clk);
+
+ pr_debug("LP Link clocks are disabled\n");
return 0;
}
@@ -556,7 +603,7 @@
}
static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,
- u32 ctrl_count, u32 master_ndx)
+ enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx)
{
int rc = 0;
int i;
@@ -570,27 +617,56 @@
m_clks = &clks[master_ndx];
- rc = dsi_link_clk_start(m_clks, master_ndx);
- if (rc) {
- pr_err("failed to turn on master clocks, rc=%d\n", rc);
- goto error;
+ if (l_type & DSI_LINK_LP_CLK) {
+ rc = dsi_link_lp_clk_start(&m_clks->lp_clks);
+ if (rc) {
+ pr_err("failed to turn on master lp link clocks, rc=%d\n",
+ rc);
+ goto error;
+ }
}
- /* Turn on rest of the core clocks */
+ if (l_type & DSI_LINK_HS_CLK) {
+ rc = dsi_link_hs_clk_start(&m_clks->hs_clks,
+ DSI_LINK_CLK_START, master_ndx);
+ if (rc) {
+ pr_err("failed to turn on master hs link clocks, rc=%d\n",
+ rc);
+ goto error;
+ }
+ }
+
for (i = 0; i < ctrl_count; i++) {
clk = &clks[i];
if (!clk || (clk == m_clks))
continue;
- rc = dsi_link_clk_start(clk, i);
- if (rc) {
- pr_err("failed to turn on clocks, rc=%d\n", rc);
- goto error_disable_master;
+ if (l_type & DSI_LINK_LP_CLK) {
+ rc = dsi_link_lp_clk_start(&clk->lp_clks);
+ if (rc) {
+ pr_err("failed to turn on lp link clocks, rc=%d\n",
+ rc);
+ goto error_disable_master;
+ }
+ }
+
+ if (l_type & DSI_LINK_HS_CLK) {
+ rc = dsi_link_hs_clk_start(&clk->hs_clks,
+ DSI_LINK_CLK_START, i);
+ if (rc) {
+ pr_err("failed to turn on hs link clocks, rc=%d\n",
+ rc);
+ goto error_disable_master;
+ }
}
}
return rc;
+
error_disable_master:
- (void)dsi_link_clk_stop(m_clks);
+ if (l_type == DSI_LINK_LP_CLK)
+ (void)dsi_link_lp_clk_stop(&m_clks->lp_clks);
+ else if (l_type == DSI_LINK_HS_CLK)
+ (void)dsi_link_hs_clk_stop(&m_clks->hs_clks);
error:
return rc;
}
@@ -646,7 +722,7 @@
}
static int dsi_display_link_clk_disable(struct dsi_link_clks *clks,
- u32 ctrl_count, u32 master_ndx)
+ enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx)
{
int rc = 0;
int i;
@@ -667,15 +743,100 @@
if (!clk || (clk == m_clks))
continue;
- rc = dsi_link_clk_stop(clk);
- if (rc)
- pr_err("failed to turn off clocks, rc=%d\n", rc);
+ if (l_type & DSI_LINK_LP_CLK) {
+ rc = dsi_link_lp_clk_stop(&clk->lp_clks);
+ if (rc)
+ pr_err("failed to turn off lp link clocks, rc=%d\n",
+ rc);
+ }
+
+ if (l_type & DSI_LINK_HS_CLK) {
+ rc = dsi_link_hs_clk_stop(&clk->hs_clks);
+ if (rc)
+ pr_err("failed to turn off hs link clocks, rc=%d\n",
+ rc);
+ }
}
- rc = dsi_link_clk_stop(m_clks);
- if (rc)
- pr_err("failed to turn off master clocks, rc=%d\n", rc);
+ if (l_type & DSI_LINK_LP_CLK) {
+ rc = dsi_link_lp_clk_stop(&m_clks->lp_clks);
+ if (rc)
+ pr_err("failed to turn off master lp link clocks, rc=%d\n",
+ rc);
+ }
+ if (l_type & DSI_LINK_HS_CLK) {
+ rc = dsi_link_hs_clk_stop(&m_clks->hs_clks);
+ if (rc)
+ pr_err("failed to turn off master hs link clocks, rc=%d\n",
+ rc);
+ }
+
+ return rc;
+}
+
+static int dsi_clk_update_link_clk_state(struct dsi_link_clks *l_clks,
+ enum dsi_lclk_type l_type, u32 l_state, bool enable)
+{
+ int rc = 0;
+ struct dsi_clk_mngr *mngr;
+
+ mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
+ if (!mngr)
+ return -EINVAL;
+
+ if (enable) {
+ if (mngr->pre_clkon_cb) {
+ rc = mngr->pre_clkon_cb(mngr->priv_data, DSI_LINK_CLK,
+ l_type, l_state);
+ if (rc) {
+ pr_err("pre link clk on cb failed for type %d\n",
+ l_type);
+ goto error;
+ }
+ }
+ rc = dsi_display_link_clk_enable(l_clks, l_type,
+ mngr->dsi_ctrl_count, mngr->master_ndx);
+ if (rc) {
+ pr_err("failed to start link clk type %d rc=%d\n",
+ l_type, rc);
+ goto error;
+ }
+
+ if (mngr->post_clkon_cb) {
+ rc = mngr->post_clkon_cb(mngr->priv_data, DSI_LINK_CLK,
+ l_type, l_state);
+ if (rc) {
+ pr_err("post link clk on cb failed for type %d\n",
+ l_type);
+ goto error;
+ }
+ }
+ } else {
+ if (mngr->pre_clkoff_cb) {
+ rc = mngr->pre_clkoff_cb(mngr->priv_data,
+ DSI_LINK_CLK, l_type, l_state);
+ if (rc)
+ pr_err("pre link clk off cb failed\n");
+ }
+
+ rc = dsi_display_link_clk_disable(l_clks, l_type,
+ mngr->dsi_ctrl_count, mngr->master_ndx);
+ if (rc) {
+ pr_err("failed to stop link clk type %d, rc = %d\n",
+ l_type, rc);
+ goto error;
+ }
+
+ if (mngr->post_clkoff_cb) {
+ rc = mngr->post_clkoff_cb(mngr->priv_data,
+ DSI_LINK_CLK, l_type, l_state);
+ if (rc)
+ pr_err("post link clk off cb failed\n");
+ }
+ }
+
+error:
return rc;
}
@@ -710,6 +871,7 @@
if (mngr->core_clk_state == DSI_CLK_OFF) {
rc = mngr->pre_clkon_cb(mngr->priv_data,
DSI_CORE_CLK,
+ DSI_LINK_NONE,
DSI_CLK_ON);
if (rc) {
pr_err("failed to turn on MDP FS rc= %d\n", rc);
@@ -726,6 +888,7 @@
if (mngr->post_clkon_cb) {
rc = mngr->post_clkon_cb(mngr->priv_data,
DSI_CORE_CLK,
+ DSI_LINK_NONE,
DSI_CLK_ON);
if (rc)
pr_err("post clk on cb failed, rc = %d\n", rc);
@@ -735,25 +898,15 @@
if (l_clks) {
if (l_state == DSI_CLK_ON) {
- if (mngr->pre_clkon_cb) {
- rc = mngr->pre_clkon_cb(mngr->priv_data,
- DSI_LINK_CLK, l_state);
- if (rc)
- pr_err("pre link clk on cb failed\n");
- }
- rc = dsi_display_link_clk_enable(l_clks,
- mngr->dsi_ctrl_count, mngr->master_ndx);
- if (rc) {
- pr_err("failed to start link clk rc= %d\n", rc);
+ rc = dsi_clk_update_link_clk_state(l_clks,
+ DSI_LINK_LP_CLK, l_state, true);
+ if (rc)
goto error;
- }
- if (mngr->post_clkon_cb) {
- rc = mngr->post_clkon_cb(mngr->priv_data,
- DSI_LINK_CLK,
- l_state);
- if (rc)
- pr_err("post link clk on cb failed\n");
- }
+
+ rc = dsi_clk_update_link_clk_state(l_clks,
+ DSI_LINK_HS_CLK, l_state, true);
+ if (rc)
+ goto error;
} else {
/*
* Two conditions that need to be checked for Link
@@ -784,36 +937,26 @@
}
rc = dsi_display_link_clk_enable(l_clks,
+ (DSI_LINK_LP_CLK & DSI_LINK_HS_CLK),
mngr->dsi_ctrl_count, mngr->master_ndx);
if (rc) {
- pr_err("Link clks did not start\n");
+ pr_err("LP Link clks did not start\n");
goto error;
}
l_c_on = true;
pr_debug("ECG: core and Link_on\n");
}
- if (mngr->pre_clkoff_cb) {
- rc = mngr->pre_clkoff_cb(mngr->priv_data,
- DSI_LINK_CLK, l_state);
- if (rc)
- pr_err("pre link clk off cb failed\n");
- }
-
- rc = dsi_display_link_clk_disable(l_clks,
- mngr->dsi_ctrl_count, mngr->master_ndx);
- if (rc) {
- pr_err("failed to stop link clk, rc = %d\n",
- rc);
+ rc = dsi_clk_update_link_clk_state(l_clks,
+ DSI_LINK_HS_CLK, l_state, false);
+ if (rc)
goto error;
- }
- if (mngr->post_clkoff_cb) {
- rc = mngr->post_clkoff_cb(mngr->priv_data,
- DSI_LINK_CLK, l_state);
- if (rc)
- pr_err("post link clk off cb failed\n");
- }
+ rc = dsi_clk_update_link_clk_state(l_clks,
+ DSI_LINK_LP_CLK, l_state, false);
+ if (rc)
+ goto error;
+
/*
* This check is to save unnecessary clock state
* change when going from EARLY_GATE to OFF. In the
@@ -872,6 +1015,7 @@
if (mngr->pre_clkoff_cb) {
rc = mngr->pre_clkoff_cb(mngr->priv_data,
DSI_CORE_CLK,
+ DSI_LINK_NONE,
c_state);
if (rc)
pr_err("pre core clk off cb failed\n");
@@ -888,6 +1032,7 @@
if (mngr->post_clkoff_cb) {
rc = mngr->post_clkoff_cb(mngr->priv_data,
DSI_CORE_CLK,
+ DSI_LINK_NONE,
DSI_CLK_OFF);
if (rc)
pr_err("post clkoff cb fail, rc = %d\n",
@@ -1095,7 +1240,8 @@
}
rc = dsi_display_link_clk_disable(l_clks,
- mngr->dsi_ctrl_count, mngr->master_ndx);
+ (DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
+ mngr->dsi_ctrl_count, mngr->master_ndx);
if (rc) {
pr_err("%s, failed to stop link clk, rc = %d\n",
__func__, rc);
@@ -1103,7 +1249,8 @@
}
rc = dsi_display_link_clk_enable(l_clks,
- mngr->dsi_ctrl_count, mngr->master_ndx);
+ (DSI_LINK_LP_CLK | DSI_LINK_HS_CLK),
+ mngr->dsi_ctrl_count, mngr->master_ndx);
if (rc) {
pr_err("%s, failed to start link clk rc= %d\n",
__func__, rc);
@@ -1267,8 +1414,10 @@
for (i = 0; i < mngr->dsi_ctrl_count; i++) {
memcpy(&mngr->core_clks[i].clks, &info->c_clks[i],
sizeof(struct dsi_core_clk_info));
- memcpy(&mngr->link_clks[i].clks, &info->l_clks[i],
- sizeof(struct dsi_link_clk_info));
+ memcpy(&mngr->link_clks[i].hs_clks, &info->l_hs_clks[i],
+ sizeof(struct dsi_link_hs_clk_info));
+ memcpy(&mngr->link_clks[i].lp_clks, &info->l_lp_clks[i],
+ sizeof(struct dsi_link_lp_clk_info));
mngr->core_clks[i].bus_handle = info->bus_handle[i];
mngr->ctrl_index[i] = info->ctrl_index[i];
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index c7c640f5..32bc3eb 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -498,7 +498,8 @@
static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl)
{
struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks;
- struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks;
+ struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks;
+ struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks;
struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks;
if (core->mdp_core_clk)
@@ -514,16 +515,17 @@
memset(core, 0x0, sizeof(*core));
- if (link->byte_clk)
- devm_clk_put(&ctrl->pdev->dev, link->byte_clk);
- if (link->pixel_clk)
- devm_clk_put(&ctrl->pdev->dev, link->pixel_clk);
- if (link->esc_clk)
- devm_clk_put(&ctrl->pdev->dev, link->esc_clk);
- if (link->byte_intf_clk)
- devm_clk_put(&ctrl->pdev->dev, link->byte_intf_clk);
+ if (hs_link->byte_clk)
+ devm_clk_put(&ctrl->pdev->dev, hs_link->byte_clk);
+ if (hs_link->pixel_clk)
+ devm_clk_put(&ctrl->pdev->dev, hs_link->pixel_clk);
+ if (lp_link->esc_clk)
+ devm_clk_put(&ctrl->pdev->dev, lp_link->esc_clk);
+ if (hs_link->byte_intf_clk)
+ devm_clk_put(&ctrl->pdev->dev, hs_link->byte_intf_clk);
- memset(link, 0x0, sizeof(*link));
+ memset(hs_link, 0x0, sizeof(*hs_link));
+ memset(lp_link, 0x0, sizeof(*lp_link));
if (rcg->byte_clk)
devm_clk_put(&ctrl->pdev->dev, rcg->byte_clk);
@@ -540,7 +542,8 @@
{
int rc = 0;
struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks;
- struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks;
+ struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks;
+ struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks;
struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks;
core->mdp_core_clk = devm_clk_get(&pdev->dev, "mdp_core_clk");
@@ -573,30 +576,30 @@
pr_debug("can't get mnoc clock, rc=%d\n", rc);
}
- link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk");
- if (IS_ERR(link->byte_clk)) {
- rc = PTR_ERR(link->byte_clk);
+ hs_link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk");
+ if (IS_ERR(hs_link->byte_clk)) {
+ rc = PTR_ERR(hs_link->byte_clk);
pr_err("failed to get byte_clk, rc=%d\n", rc);
goto fail;
}
- link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk");
- if (IS_ERR(link->pixel_clk)) {
- rc = PTR_ERR(link->pixel_clk);
+ hs_link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk");
+ if (IS_ERR(hs_link->pixel_clk)) {
+ rc = PTR_ERR(hs_link->pixel_clk);
pr_err("failed to get pixel_clk, rc=%d\n", rc);
goto fail;
}
- link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
- if (IS_ERR(link->esc_clk)) {
- rc = PTR_ERR(link->esc_clk);
+ lp_link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
+ if (IS_ERR(lp_link->esc_clk)) {
+ rc = PTR_ERR(lp_link->esc_clk);
pr_err("failed to get esc_clk, rc=%d\n", rc);
goto fail;
}
- link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk");
- if (IS_ERR(link->byte_intf_clk)) {
- link->byte_intf_clk = NULL;
+ hs_link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk");
+ if (IS_ERR(hs_link->byte_intf_clk)) {
+ hs_link->byte_intf_clk = NULL;
pr_debug("can't find byte intf clk, rc=%d\n", rc);
}
@@ -1338,9 +1341,6 @@
u32 dlen, diff, rlen = msg->rx_len;
unsigned char *buff;
char cmd;
- struct dsi_cmd_desc *of_cmd;
-
- of_cmd = container_of(msg, struct dsi_cmd_desc, msg);
if (msg->rx_len <= 2) {
short_resp = true;
@@ -1378,9 +1378,9 @@
* wait before reading rdbk_data register, if any delay is
* required after sending the read command.
*/
- if (of_cmd && of_cmd->post_wait_ms)
- usleep_range(of_cmd->post_wait_ms * 1000,
- ((of_cmd->post_wait_ms * 1000) + 10));
+ if (msg->wait_ms)
+ usleep_range(msg->wait_ms * 1000,
+ ((msg->wait_ms * 1000) + 10));
dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw,
buff, total_bytes_read,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index e08ef99..b059fc5 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -100,7 +100,8 @@
/**
* struct dsi_ctrl_clk_info - clock information for DSI controller
* @core_clks: Core clocks needed to access DSI controller registers.
- * @link_clks: Link clocks required to transmit data over DSI link.
+ * @hs_link_clks: Clocks required to transmit high speed data over DSI
+ * @lp_link_clks: Clocks required to perform low power ops over DSI
* @rcg_clks: Root clock generation clocks generated in MMSS_CC. The
* output of the PLL is set as parent for these root
* clocks. These clocks are specific to controller
@@ -114,7 +115,8 @@
struct dsi_ctrl_clk_info {
/* Clocks parsed from DT */
struct dsi_core_clk_info core_clks;
- struct dsi_link_clk_info link_clks;
+ struct dsi_link_hs_clk_info hs_link_clks;
+ struct dsi_link_lp_clk_info lp_link_clks;
struct dsi_clk_link_set rcg_clks;
/* Clocks set by DSI Manager */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index adcec15..7194f1a 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -559,9 +559,6 @@
if (dsi_ctrl_validate_host_state(ctrl->ctrl))
return 1;
- /* acquire panel_lock to make sure no commands are in progress */
- dsi_panel_acquire_panel_lock(panel);
-
config = &(panel->esd_config);
lenp = config->status_valid_params ?: config->status_cmds_rlen;
count = config->status_cmd.count;
@@ -580,7 +577,7 @@
rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags);
if (rc <= 0) {
pr_err("rx cmd transfer failed rc=%d\n", rc);
- goto error;
+ return rc;
}
memcpy(config->return_buf + start,
@@ -588,9 +585,6 @@
start += lenp[i];
}
-error:
- /* release panel_lock */
- dsi_panel_release_panel_lock(panel);
return rc;
}
@@ -709,15 +703,16 @@
u32 status_mode;
int rc = 0x1;
- if (dsi_display == NULL)
+ if (!dsi_display || !dsi_display->panel)
return -EINVAL;
- mutex_lock(&dsi_display->display_lock);
-
panel = dsi_display->panel;
+
+ dsi_panel_acquire_panel_lock(panel);
+
if (!panel->panel_initialized) {
pr_debug("Panel not initialized\n");
- mutex_unlock(&dsi_display->display_lock);
+ dsi_panel_release_panel_lock(panel);
return rc;
}
@@ -742,7 +737,7 @@
dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
DSI_ALL_CLKS, DSI_CLK_OFF);
- mutex_unlock(&dsi_display->display_lock);
+ dsi_panel_release_panel_lock(panel);
return rc;
}
@@ -758,7 +753,7 @@
cmd->msg.channel = cmd_buf[2];
cmd->msg.flags = cmd_buf[3];
cmd->msg.ctrl = 0;
- cmd->post_wait_ms = cmd_buf[4];
+ cmd->post_wait_ms = cmd->msg.wait_ms = cmd_buf[4];
cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6]));
if (cmd->msg.tx_len > payload_len) {
@@ -1582,9 +1577,19 @@
m_ctrl = &display->ctrl[display->cmd_master_idx];
ulps_enabled = display->ulps_enabled;
+ /*
+ * Clamp control can be either through the DSI controller or
+ * the DSI PHY depending on hardware variation
+ */
rc = dsi_ctrl_set_clamp_state(m_ctrl->ctrl, enable, ulps_enabled);
if (rc) {
- pr_err("DSI Clamp state change(%d) failed\n", enable);
+ pr_err("DSI ctrl clamp state change(%d) failed\n", enable);
+ return rc;
+ }
+
+ rc = dsi_phy_set_clamp_state(m_ctrl->phy, enable);
+ if (rc) {
+ pr_err("DSI phy clamp state change(%d) failed\n", enable);
return rc;
}
@@ -1598,7 +1603,18 @@
pr_err("DSI Clamp state change(%d) failed\n", enable);
return rc;
}
+
+ rc = dsi_phy_set_clamp_state(ctrl->phy, enable);
+ if (rc) {
+ pr_err("DSI phy clamp state change(%d) failed\n",
+ enable);
+ return rc;
+ }
+
+ pr_debug("Clamps %s for ctrl%d\n",
+ enable ? "enabled" : "disabled", i);
}
+
display->clamp_enabled = enable;
return 0;
}
@@ -3003,12 +3019,14 @@
int dsi_pre_clkoff_cb(void *priv,
enum dsi_clk_type clk,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state new_state)
{
int rc = 0;
struct dsi_display *display = priv;
- if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) {
+ if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) &&
+ (l_type && DSI_LINK_LP_CLK)) {
/*
* If ULPS feature is enabled, enter ULPS first.
* However, when blanking the panel, we should enter ULPS
@@ -3060,13 +3078,14 @@
int dsi_post_clkon_cb(void *priv,
enum dsi_clk_type clk,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state curr_state)
{
int rc = 0;
struct dsi_display *display = priv;
bool mmss_clamp = false;
- if (clk & DSI_CORE_CLK) {
+ if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_LP_CLK)) {
mmss_clamp = display->clamp_enabled;
/*
* controller setup is needed if coming out of idle
@@ -3075,6 +3094,13 @@
if (mmss_clamp)
dsi_display_ctrl_setup(display);
+ /*
+ * Phy setup is needed if coming out of idle
+ * power collapse with clamps enabled.
+ */
+ if (display->phy_idle_power_off || mmss_clamp)
+ dsi_display_phy_idle_on(display, mmss_clamp);
+
if (display->ulps_enabled && mmss_clamp) {
/*
* ULPS Entry Request. This is needed if the lanes were
@@ -3113,17 +3139,11 @@
goto error;
}
- /*
- * Phy setup is needed if coming out of idle
- * power collapse with clamps enabled.
- */
- if (display->phy_idle_power_off || mmss_clamp)
- dsi_display_phy_idle_on(display, mmss_clamp);
-
/* enable dsi to serve irqs */
dsi_display_ctrl_irq_update(display, true);
}
- if (clk & DSI_LINK_CLK) {
+
+ if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_HS_CLK)) {
/*
* Toggle the resync FIFO everytime clock changes, except
* when cont-splash screen transition is going on.
@@ -3148,6 +3168,7 @@
int dsi_post_clkoff_cb(void *priv,
enum dsi_clk_type clk_type,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state curr_state)
{
int rc = 0;
@@ -3175,6 +3196,7 @@
int dsi_pre_clkon_cb(void *priv,
enum dsi_clk_type clk_type,
+ enum dsi_lclk_type l_type,
enum dsi_clk_state new_state)
{
int rc = 0;
@@ -4391,10 +4413,16 @@
goto error_ctrl_deinit;
}
- memcpy(&info.c_clks[i], &display_ctrl->ctrl->clk_info.core_clks,
- sizeof(struct dsi_core_clk_info));
- memcpy(&info.l_clks[i], &display_ctrl->ctrl->clk_info.link_clks,
- sizeof(struct dsi_link_clk_info));
+ memcpy(&info.c_clks[i],
+ (&display_ctrl->ctrl->clk_info.core_clks),
+ sizeof(struct dsi_core_clk_info));
+ memcpy(&info.l_hs_clks[i],
+ (&display_ctrl->ctrl->clk_info.hs_link_clks),
+ sizeof(struct dsi_link_hs_clk_info));
+ memcpy(&info.l_lp_clks[i],
+ (&display_ctrl->ctrl->clk_info.lp_link_clks),
+ sizeof(struct dsi_link_lp_clk_info));
+
info.c_clks[i].phandle = &priv->phandle;
info.bus_handle[i] =
display_ctrl->ctrl->axi_bus_info.bus_handle;
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 6b1c029..5612016 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -497,12 +497,14 @@
* dsi_pre_clkoff_cb() - Callback before clock is turned off
* @priv: private data pointer.
* @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @new_state: next state for the clock.
*
* @return: error code.
*/
int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
- enum dsi_clk_state new_state);
+ enum dsi_lclk_type l_type,
+ enum dsi_clk_state new_state);
/**
* dsi_display_update_pps() - update PPS buffer.
@@ -519,35 +521,40 @@
* dsi_post_clkoff_cb() - Callback after clock is turned off
* @priv: private data pointer.
* @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @curr_state: current state for the clock.
*
* @return: error code.
*/
int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type,
- enum dsi_clk_state curr_state);
+ enum dsi_lclk_type l_type,
+ enum dsi_clk_state curr_state);
/**
* dsi_post_clkon_cb() - Callback after clock is turned on
* @priv: private data pointer.
* @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @curr_state: current state for the clock.
*
* @return: error code.
*/
int dsi_post_clkon_cb(void *priv, enum dsi_clk_type clk_type,
- enum dsi_clk_state curr_state);
-
+ enum dsi_lclk_type l_type,
+ enum dsi_clk_state curr_state);
/**
* dsi_pre_clkon_cb() - Callback before clock is turned on
* @priv: private data pointer.
* @clk_type: clock which is being turned on.
+ * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks.
* @new_state: next state for the clock.
*
* @return: error code.
*/
int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type,
- enum dsi_clk_state new_state);
+ enum dsi_lclk_type l_type,
+ enum dsi_clk_state new_state);
/**
* dsi_display_unprepare() - power off display hardware.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
index 5b47865..6b5bfb4 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c
@@ -186,6 +186,7 @@
{
int rc = 0;
struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
+ struct dsi_display *display;
if (!bridge) {
pr_err("Invalid params\n");
@@ -197,11 +198,15 @@
pr_debug("[%d] seamless enable\n", c_bridge->id);
return;
}
+ display = c_bridge->display;
- rc = dsi_display_post_enable(c_bridge->display);
+ rc = dsi_display_post_enable(display);
if (rc)
pr_err("[%d] DSI display post enabled failed, rc=%d\n",
c_bridge->id, rc);
+
+ if (display && display->drm_conn)
+ sde_connector_helper_bridge_enable(display->drm_conn);
}
static void dsi_bridge_disable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
index 79df631..cb9c1fa 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c
@@ -1536,7 +1536,7 @@
cmd[i].msg.channel = data[2];
cmd[i].msg.flags |= (data[3] == 1 ? MIPI_DSI_MSG_REQ_ACK : 0);
cmd[i].msg.ctrl = 0;
- cmd[i].post_wait_ms = data[4];
+ cmd[i].post_wait_ms = cmd[i].msg.wait_ms = data[4];
cmd[i].msg.tx_len = ((data[5] << 8) | (data[6]));
size = cmd[i].msg.tx_len * sizeof(u8);
@@ -1771,6 +1771,9 @@
panel->sync_broadcast_en = of_property_read_bool(of_node,
"qcom,cmd-sync-wait-broadcast");
+
+ panel->lp11_init = of_property_read_bool(of_node,
+ "qcom,mdss-dsi-lp11-init");
return 0;
}
@@ -3511,6 +3514,7 @@
set->cmds[0].msg.tx_buf = caset;
set->cmds[0].msg.rx_len = 0;
set->cmds[0].msg.rx_buf = 0;
+ set->cmds[0].msg.wait_ms = 0;
set->cmds[0].last_command = 0;
set->cmds[0].post_wait_ms = 0;
@@ -3522,6 +3526,7 @@
set->cmds[1].msg.tx_buf = paset;
set->cmds[1].msg.rx_len = 0;
set->cmds[1].msg.rx_buf = 0;
+ set->cmds[1].msg.wait_ms = 0;
set->cmds[1].last_command = 1;
set->cmds[1].post_wait_ms = 0;
@@ -3746,14 +3751,6 @@
goto error;
}
- if (panel->lp11_init) {
- rc = dsi_panel_power_off(panel);
- if (rc) {
- pr_err("[%s] panel power_Off failed, rc=%d\n",
- panel->name, rc);
- goto error;
- }
- }
error:
mutex_unlock(&panel->panel_lock);
return rc;
@@ -3773,13 +3770,11 @@
mutex_lock(&panel->panel_lock);
- if (!panel->lp11_init) {
- rc = dsi_panel_power_off(panel);
- if (rc) {
- pr_err("[%s] panel power_Off failed, rc=%d\n",
- panel->name, rc);
- goto error;
- }
+ rc = dsi_panel_power_off(panel);
+ if (rc) {
+ pr_err("[%s] panel power_Off failed, rc=%d\n",
+ panel->name, rc);
+ goto error;
}
error:
mutex_unlock(&panel->panel_lock);
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index 6a7a84c..2e2d0d8 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -902,6 +902,26 @@
}
/**
+ * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
+ * @phy: DSI PHY handle.
+ * @enable: boolean to specify clamp enable/disable.
+ *
+ * Return: error code.
+ */
+int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable)
+{
+ if (!phy)
+ return -EINVAL;
+
+ pr_debug("[%s] enable=%d\n", phy->name, enable);
+
+ if (phy->hw.ops.clamp_ctrl)
+ phy->hw.ops.clamp_ctrl(&phy->hw, enable);
+
+ return 0;
+}
+
+/**
* dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen
* @phy: DSI PHY handle
* @enable: boolean to specify PHY enable/disable.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
index 56d5ee3..4163411 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h
@@ -218,6 +218,15 @@
int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable);
/**
+ * dsi_phy_set_clamp_state() - configure clamps for DSI lanes
+ * @phy: DSI PHY handle.
+ * @enable: boolean to specify clamp enable/disable.
+ *
+ * Return: error code.
+ */
+int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable);
+
+/**
* dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting
* @phy: DSI PHY handle
* @clk_freq: link clock frequency
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
index e31899d4..d24a613 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h
@@ -234,6 +234,14 @@
u32 *timing, u32 size);
/**
+ * clamp_ctrl() - configure clamps for DSI lanes
+ * @phy: DSI PHY handle.
+ * @enable: boolean to specify clamp enable/disable.
+ * Return: error code.
+ */
+ void (*clamp_ctrl)(struct dsi_phy_hw *phy, bool enable);
+
+ /**
* phy_lane_reset() - Reset dsi phy lanes in case of error.
* @phy: Pointer to DSI PHY hardware object.
* Return: error code.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
index b078231..5015806 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c
@@ -196,10 +196,31 @@
DSI_W32(phy, DSIPHY_LNX_OFFSET_BOT_CTRL(i), 0x0);
DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]);
}
+}
- /* Toggle BIT 0 to release freeze I/0 */
- DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x05);
- DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x04);
+void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable)
+{
+ u32 reg;
+
+ pr_debug("enable=%s\n", enable ? "true" : "false");
+
+ /*
+ * DSI PHY lane clamps, also referred to as PHY FreezeIO is
+ * enalbed by default as part of the initialization sequnce.
+ * This would get triggered anytime the chip FreezeIO is asserted.
+ */
+ if (enable)
+ return;
+
+ /*
+ * Toggle BIT 0 to exlplictly release PHY freeze I/0 to disable
+ * the clamps.
+ */
+ reg = DSI_R32(phy, DSIPHY_LNX_TX_DCTRL(3));
+ DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg | BIT(0));
+ wmb(); /* Ensure that the freezeio bit is toggled */
+ DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg & ~BIT(0));
+ wmb(); /* Ensure that the freezeio bit is toggled */
}
/**
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 19df8be..0697db8 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -947,6 +947,14 @@
struct msm_kms *kms = priv->kms;
int i;
+ /* check for splash status before triggering cleanup
+ * if we end up here with splash status ON i.e before first
+ * commit then ignore the last close call
+ */
+ if (kms && kms->funcs && kms->funcs->check_for_splash
+ && kms->funcs->check_for_splash(kms))
+ return;
+
/*
* clean up vblank disable immediately as this is the last close.
*/
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index ce4197b..fcdddb3 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -155,6 +155,7 @@
CRTC_PROP_SECURITY_LEVEL,
CRTC_PROP_IDLE_TIMEOUT,
CRTC_PROP_DEST_SCALER,
+ CRTC_PROP_CAPTURE_OUTPUT,
CRTC_PROP_ENABLE_SUI_ENHANCEMENT,
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index db9e7ee..e99ff9c 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -106,6 +106,8 @@
unsigned int domain);
/* handle continuous splash */
int (*cont_splash_config)(struct msm_kms *kms);
+ /* check for continuous splash status */
+ bool (*check_for_splash)(struct msm_kms *kms);
};
struct msm_kms {
diff --git a/drivers/gpu/drm/msm/sde/sde_ad4.h b/drivers/gpu/drm/msm/sde/sde_ad4.h
index bf08360..b254d7d 100644
--- a/drivers/gpu/drm/msm/sde/sde_ad4.h
+++ b/drivers/gpu/drm/msm/sde/sde_ad4.h
@@ -52,6 +52,7 @@
AD_IPC_SUSPEND,
AD_IPC_RESUME,
AD_IPC_RESET,
+ AD_VSYNC_UPDATE,
AD_PROPMAX,
};
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c
index 0f55b19..47ff024 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.c
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c
@@ -88,6 +88,7 @@
enum ad_property ad_prop);
static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg);
+static void sde_cp_update_ad_vsync_prop(struct sde_crtc *sde_crtc, u32 val);
#define setup_dspp_prop_install_funcs(func) \
do { \
@@ -138,6 +139,7 @@
SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS,
SDE_CP_CRTC_DSPP_AD_BACKLIGHT,
SDE_CP_CRTC_DSPP_AD_STRENGTH,
+ SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT,
SDE_CP_CRTC_DSPP_MAX,
/* DSPP features end */
@@ -407,6 +409,7 @@
if (IS_ERR(sde_crtc->hist_blob))
sde_crtc->hist_blob = NULL;
+ sde_crtc->ad_vsync_count = 0;
mutex_init(&sde_crtc->crtc_cp_lock);
INIT_LIST_HEAD(&sde_crtc->active_list);
INIT_LIST_HEAD(&sde_crtc->dirty_list);
@@ -789,6 +792,9 @@
ad_cfg.prop = AD_MODE;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
case SDE_CP_CRTC_DSPP_AD_INIT:
if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -798,6 +804,9 @@
ad_cfg.prop = AD_INIT;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
case SDE_CP_CRTC_DSPP_AD_CFG:
if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -807,6 +816,9 @@
ad_cfg.prop = AD_CFG;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
case SDE_CP_CRTC_DSPP_AD_INPUT:
if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -816,6 +828,9 @@
ad_cfg.prop = AD_INPUT;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS:
if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -825,6 +840,9 @@
ad_cfg.prop = AD_ASSERTIVE;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
case SDE_CP_CRTC_DSPP_AD_BACKLIGHT:
if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -834,6 +852,9 @@
ad_cfg.prop = AD_BACKLIGHT;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
case SDE_CP_CRTC_DSPP_AD_STRENGTH:
if (!hw_dspp || !hw_dspp->ops.setup_ad) {
@@ -843,6 +864,9 @@
ad_cfg.prop = AD_STRENGTH;
ad_cfg.hw_cfg = &hw_cfg;
hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg);
+ sde_crtc->ad_vsync_count = 0;
+ sde_cp_update_ad_vsync_prop(sde_crtc,
+ sde_crtc->ad_vsync_count);
break;
default:
ret = -EINVAL;
@@ -924,10 +948,15 @@
DRM_DEBUG_DRIVER("Dirty list is empty\n");
goto exit;
}
- sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
set_dspp_flush = true;
}
+ if (!list_empty(&sde_crtc->ad_active)) {
+ sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET);
+ sde_cp_ad_set_prop(sde_crtc, AD_VSYNC_UPDATE);
+ sde_cp_update_ad_vsync_prop(sde_crtc, sde_crtc->ad_vsync_count);
+ }
+
list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list,
dirty_list) {
sde_dspp_feature = crtc_feature_map[prop_node->feature];
@@ -1449,6 +1478,9 @@
"SDE_DSPP_AD_V4_BACKLIGHT",
SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1),
0);
+ sde_cp_crtc_install_range_property(crtc,
+ "SDE_DSPP_AD_V4_VSYNC_COUNT",
+ SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT, 0, U32_MAX, 0);
break;
default:
DRM_ERROR("version %d not supported\n", version);
@@ -1867,6 +1899,11 @@
hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width;
hw_cfg.displayv = hw_lm->cfg.out_height;
hw_cfg.mixer_info = hw_lm;
+
+ if (ad_prop == AD_VSYNC_UPDATE) {
+ hw_cfg.payload = &sde_crtc->ad_vsync_count;
+ hw_cfg.len = sizeof(sde_crtc->ad_vsync_count);
+ }
ad_cfg.prop = ad_prop;
ad_cfg.hw_cfg = &hw_cfg;
ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop);
@@ -2118,3 +2155,35 @@
exit:
return ret;
}
+
+void sde_cp_update_ad_vsync_count(struct drm_crtc *crtc, u32 val)
+{
+ struct sde_crtc *sde_crtc;
+
+ if (!crtc) {
+ DRM_ERROR("invalid crtc %pK\n", crtc);
+ return;
+ }
+
+ sde_crtc = to_sde_crtc(crtc);
+ if (!sde_crtc) {
+ DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc);
+ return;
+ }
+
+ sde_crtc->ad_vsync_count = val;
+ sde_cp_update_ad_vsync_prop(sde_crtc, val);
+}
+
+static void sde_cp_update_ad_vsync_prop(struct sde_crtc *sde_crtc, u32 val)
+{
+ struct sde_cp_node *prop_node = NULL;
+
+ list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) {
+ if (prop_node->feature == SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT) {
+ prop_node->prop_val = val;
+ pr_debug("AD vsync count updated to %d\n", val);
+ return;
+ }
+ }
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.h b/drivers/gpu/drm/msm/sde/sde_color_processing.h
index 7eb1738..620db26 100644
--- a/drivers/gpu/drm/msm/sde/sde_color_processing.h
+++ b/drivers/gpu/drm/msm/sde/sde_color_processing.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -146,4 +146,11 @@
*/
int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
struct sde_irq_callback *hist_irq);
+
+/**
+ * sde_cp_update_ad_vsync_count: Api to update AD vsync count
+ * @crtc: Pointer to crtc.
+ * @val: vsync count value
+ */
+void sde_cp_update_ad_vsync_count(struct drm_crtc *crtc, u32 val);
#endif /*_SDE_COLOR_PROCESSING_H */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index d2f8d12..07d1ad7 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -623,6 +623,7 @@
void sde_connector_helper_bridge_disable(struct drm_connector *connector)
{
int rc;
+ struct sde_connector *c_conn = NULL;
if (!connector)
return;
@@ -633,6 +634,34 @@
connector->base.id, rc);
SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
}
+
+ /* Disable ESD thread */
+ sde_connector_schedule_status_work(connector, false);
+
+ c_conn = to_sde_connector(connector);
+ if (c_conn->panel_dead) {
+ c_conn->bl_device->props.power = FB_BLANK_POWERDOWN;
+ c_conn->bl_device->props.state |= BL_CORE_FBBLANK;
+ backlight_update_status(c_conn->bl_device);
+ }
+}
+
+void sde_connector_helper_bridge_enable(struct drm_connector *connector)
+{
+ struct sde_connector *c_conn = NULL;
+
+ if (!connector)
+ return;
+
+ c_conn = to_sde_connector(connector);
+
+ /* Special handling for ESD recovery case */
+ if (c_conn->panel_dead) {
+ c_conn->bl_device->props.power = FB_BLANK_UNBLANK;
+ c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK;
+ backlight_update_status(c_conn->bl_device);
+ c_conn->panel_dead = false;
+ }
}
int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable)
@@ -1207,7 +1236,7 @@
}
void sde_connector_complete_commit(struct drm_connector *connector,
- ktime_t ts)
+ ktime_t ts, enum sde_fence_event fence_event)
{
if (!connector) {
SDE_ERROR("invalid connector\n");
@@ -1215,7 +1244,8 @@
}
/* signal connector's retire fence */
- sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false);
+ sde_fence_signal(&to_sde_connector(connector)->retire_fence,
+ ts, fence_event);
}
void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts)
@@ -1226,7 +1256,8 @@
}
/* signal connector's retire fence */
- sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true);
+ sde_fence_signal(&to_sde_connector(connector)->retire_fence,
+ ts, SDE_FENCE_RESET_TIMELINE);
}
static void sde_connector_update_hdr_props(struct drm_connector *connector)
@@ -1734,15 +1765,15 @@
static void _sde_connector_report_panel_dead(struct sde_connector *conn)
{
struct drm_event event;
- bool panel_dead = true;
if (!conn)
return;
+ conn->panel_dead = true;
event.type = DRM_EVENT_PANEL_DEAD;
event.length = sizeof(bool);
msm_mode_object_event_notify(&conn->base.base,
- conn->base.dev, &event, (u8 *)&panel_dead);
+ conn->base.dev, &event, (u8 *)&conn->panel_dead);
sde_encoder_display_failure_notification(conn->encoder);
SDE_EVT32(SDE_EVTLOG_ERROR);
SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n",
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index c6f348e..51dc92d 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -324,6 +324,8 @@
* @status_work: work object to perform status checks
* @force_panel_dead: variable to trigger forced ESD recovery
* @esd_status_interval: variable to change ESD check interval in millisec
+ * @panel_dead: Flag to indicate if panel has gone bad
+ * @esd_status_check: Flag to indicate if ESD thread is scheduled or not
* @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed
* @bl_scale: BL scale value for ABA feature
* @bl_scale_ad: BL scale value for AD feature
@@ -365,7 +367,7 @@
struct delayed_work status_work;
u32 force_panel_dead;
u32 esd_status_interval;
-
+ bool panel_dead;
bool esd_status_check;
bool bl_scale_dirty;
@@ -583,8 +585,10 @@
* sde_connector_complete_commit - signal completion of current commit
* @connector: Pointer to drm connector object
* @ts: timestamp to be updated in the fence signalling
+ * @fence_event: enum value to indicate nature of fence event
*/
-void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts);
+void sde_connector_complete_commit(struct drm_connector *connector,
+ ktime_t ts, enum sde_fence_event fence_event);
/**
* sde_connector_commit_reset - reset the completion signal
@@ -763,6 +767,12 @@
void sde_connector_helper_bridge_disable(struct drm_connector *connector);
/**
+ * sde_connector_helper_bridge_enable - helper function for drm bridge enable
+ * @connector: Pointer to DRM connector object
+ */
+void sde_connector_helper_bridge_enable(struct drm_connector *connector);
+
+/**
* sde_connector_get_panel_vfp - helper to get panel vfp
* @connector: pointer to drm connector
* @h_active: panel width
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 7daab2a..cefa513 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -936,7 +936,9 @@
struct sde_crtc *sde_crtc;
struct sde_crtc_state *crtc_state;
struct sde_rect *crtc_roi;
- int i, num_attached_conns = 0;
+ struct msm_mode_info mode_info;
+ int i = 0;
+ int rc;
bool is_crtc_roi_dirty;
bool is_any_conn_roi_dirty;
@@ -958,13 +960,14 @@
if (!conn_state || conn_state->crtc != crtc)
continue;
- if (num_attached_conns) {
- SDE_ERROR(
- "crtc%d: unsupported: roi on crtc w/ >1 connectors\n",
- DRMID(crtc));
+ rc = sde_connector_get_mode_info(conn_state, &mode_info);
+ if (rc) {
+ SDE_ERROR("failed to get mode info\n");
return -EINVAL;
}
- ++num_attached_conns;
+
+ if (!mode_info.roi_caps.enabled)
+ continue;
sde_conn = to_sde_connector(conn_state->connector);
sde_conn_state = to_sde_connector_state(conn_state);
@@ -1285,13 +1288,6 @@
sde_crtc = to_sde_crtc(crtc);
sde_crtc_state = to_sde_crtc_state(state);
- if (hweight_long(state->connector_mask) != 1) {
- SDE_ERROR("invalid connector count(%d) for crtc: %d\n",
- (int)hweight_long(state->connector_mask),
- crtc->base.id);
- return -EINVAL;
- }
-
/*
* check connector array cached at modeset time since incoming atomic
* state may not include any connectors if they aren't modified
@@ -1307,42 +1303,41 @@
SDE_ERROR("failed to get mode info\n");
return -EINVAL;
}
- break;
- }
- if (!mode_info.roi_caps.enabled)
- return 0;
+ if (!mode_info.roi_caps.enabled)
+ continue;
- if (sde_crtc_state->user_roi_list.num_rects >
- mode_info.roi_caps.num_roi) {
- SDE_ERROR("roi count is more than supported limit, %d > %d\n",
- sde_crtc_state->user_roi_list.num_rects,
- mode_info.roi_caps.num_roi);
- return -E2BIG;
- }
+ if (sde_crtc_state->user_roi_list.num_rects >
+ mode_info.roi_caps.num_roi) {
+ SDE_ERROR("roi count is exceeding limit, %d > %d\n",
+ sde_crtc_state->user_roi_list.num_rects,
+ mode_info.roi_caps.num_roi);
+ return -E2BIG;
+ }
- rc = _sde_crtc_set_crtc_roi(crtc, state);
- if (rc)
- return rc;
+ rc = _sde_crtc_set_crtc_roi(crtc, state);
+ if (rc)
+ return rc;
- rc = _sde_crtc_check_autorefresh(crtc, state);
- if (rc)
- return rc;
+ rc = _sde_crtc_check_autorefresh(crtc, state);
+ if (rc)
+ return rc;
- for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
- rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
+ for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+ rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx);
+ if (rc)
+ return rc;
+ }
+
+ rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
+ if (rc)
+ return rc;
+
+ rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
if (rc)
return rc;
}
- rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state);
- if (rc)
- return rc;
-
- rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state);
- if (rc)
- return rc;
-
return 0;
}
@@ -2116,15 +2111,62 @@
}
}
+static void sde_crtc_frame_event_cb(void *data, u32 event)
+{
+ struct drm_crtc *crtc = (struct drm_crtc *)data;
+ struct sde_crtc *sde_crtc;
+ struct msm_drm_private *priv;
+ struct sde_crtc_frame_event *fevent;
+ struct sde_crtc_frame_event_cb_data *cb_data;
+ unsigned long flags;
+ u32 crtc_id;
+
+ cb_data = (struct sde_crtc_frame_event_cb_data *)data;
+ if (!data) {
+ SDE_ERROR("invalid parameters\n");
+ return;
+ }
+
+ crtc = cb_data->crtc;
+ if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
+ SDE_ERROR("invalid parameters\n");
+ return;
+ }
+ sde_crtc = to_sde_crtc(crtc);
+ priv = crtc->dev->dev_private;
+ crtc_id = drm_crtc_index(crtc);
+
+ SDE_DEBUG("crtc%d\n", crtc->base.id);
+ SDE_EVT32_VERBOSE(DRMID(crtc), event);
+
+ spin_lock_irqsave(&sde_crtc->spin_lock, flags);
+ fevent = list_first_entry_or_null(&sde_crtc->frame_event_list,
+ struct sde_crtc_frame_event, list);
+ if (fevent)
+ list_del_init(&fevent->list);
+ spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
+
+ if (!fevent) {
+ SDE_ERROR("crtc%d event %d overflow\n",
+ crtc->base.id, event);
+ SDE_EVT32(DRMID(crtc), event);
+ return;
+ }
+
+ fevent->event = event;
+ fevent->crtc = crtc;
+ fevent->connector = cb_data->connector;
+ fevent->ts = ktime_get();
+ kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
+}
+
void sde_crtc_prepare_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
struct sde_crtc *sde_crtc;
struct sde_crtc_state *cstate;
struct drm_connector *conn;
- struct sde_crtc_retire_event *retire_event = NULL;
- unsigned long flags;
- int i;
+ struct drm_encoder *encoder;
if (!crtc || !crtc->state) {
SDE_ERROR("invalid crtc\n");
@@ -2141,31 +2183,17 @@
drm_for_each_connector(conn, crtc->dev)
if (conn->state && conn->state->crtc == crtc &&
cstate->num_connectors < MAX_CONNECTORS) {
+ encoder = conn->state->best_encoder;
+ if (encoder)
+ sde_encoder_register_frame_event_callback(
+ encoder,
+ sde_crtc_frame_event_cb,
+ crtc);
+
cstate->connectors[cstate->num_connectors++] = conn;
sde_connector_prepare_fence(conn);
}
- for (i = 0; i < SDE_CRTC_FRAME_EVENT_SIZE; i++) {
- retire_event = &sde_crtc->retire_events[i];
- if (list_empty(&retire_event->list))
- break;
- retire_event = NULL;
- }
-
- if (retire_event) {
- retire_event->num_connectors = cstate->num_connectors;
- for (i = 0; i < cstate->num_connectors; i++)
- retire_event->connectors[i] = cstate->connectors[i];
-
- spin_lock_irqsave(&sde_crtc->spin_lock, flags);
- list_add_tail(&retire_event->list,
- &sde_crtc->retire_event_list);
- spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
- } else {
- SDE_ERROR("crtc%d retire event overflow\n", crtc->base.id);
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR);
- }
-
/* prepare main output fence */
sde_fence_prepare(&sde_crtc->output_fence);
}
@@ -2216,9 +2244,16 @@
return INTF_MODE_NONE;
}
- drm_for_each_encoder(encoder, crtc->dev)
- if (encoder->crtc == crtc)
- return sde_encoder_get_intf_mode(encoder);
+ drm_for_each_encoder(encoder, crtc->dev) {
+ if (encoder->crtc != crtc)
+ continue;
+
+ /* continue if copy encoder is encountered */
+ if (sde_encoder_in_clone_mode(encoder))
+ continue;
+
+ return sde_encoder_get_intf_mode(encoder);
+ }
return INTF_MODE_NONE;
}
@@ -2243,38 +2278,16 @@
SDE_EVT32_VERBOSE(DRMID(crtc));
}
-static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts)
+static void _sde_crtc_retire_event(struct drm_connector *connector,
+ ktime_t ts, bool is_error)
{
- struct sde_crtc_retire_event *retire_event;
- struct sde_crtc *sde_crtc;
- unsigned long flags;
- int i;
-
- if (!crtc) {
+ if (!connector) {
SDE_ERROR("invalid param\n");
return;
}
- sde_crtc = to_sde_crtc(crtc);
- spin_lock_irqsave(&sde_crtc->spin_lock, flags);
- retire_event = list_first_entry_or_null(&sde_crtc->retire_event_list,
- struct sde_crtc_retire_event, list);
- if (retire_event)
- list_del_init(&retire_event->list);
- spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
-
- if (!retire_event) {
- SDE_ERROR("crtc%d retire event without kickoff\n",
- crtc->base.id);
- SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR);
- return;
- }
-
SDE_ATRACE_BEGIN("signal_retire_fence");
- for (i = 0; (i < retire_event->num_connectors) &&
- retire_event->connectors[i]; ++i)
- sde_connector_complete_commit(
- retire_event->connectors[i], ts);
+ sde_connector_complete_commit(connector, ts, is_error);
SDE_ATRACE_END("signal_retire_fence");
}
@@ -2287,6 +2300,7 @@
struct sde_kms *sde_kms;
unsigned long flags;
bool frame_done = false;
+ bool in_clone_mode = false;
if (!work) {
SDE_ERROR("invalid work handle\n");
@@ -2315,10 +2329,11 @@
SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY);
- if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE
- | SDE_ENCODER_FRAME_EVENT_ERROR
- | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
+ in_clone_mode = sde_encoder_in_clone_mode(fevent->connector->encoder);
+ if (!in_clone_mode && (fevent->event & (SDE_ENCODER_FRAME_EVENT_ERROR
+ | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD
+ | SDE_ENCODER_FRAME_EVENT_DONE))) {
if (atomic_read(&sde_crtc->frame_pending) < 1) {
/* this should not happen */
SDE_ERROR("crtc%d ts:%lld invalid frame_pending:%d\n",
@@ -2347,13 +2362,17 @@
if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) {
SDE_ATRACE_BEGIN("signal_release_fence");
- sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false);
+ sde_fence_signal(&sde_crtc->output_fence, fevent->ts,
+ (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
+ ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);
SDE_ATRACE_END("signal_release_fence");
}
if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE)
/* this api should be called without spin_lock */
- _sde_crtc_retire_event(crtc, fevent->ts);
+ _sde_crtc_retire_event(fevent->connector, fevent->ts,
+ (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR)
+ ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL);
if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)
SDE_ERROR("crtc%d ts:%lld received panel dead event\n",
@@ -2368,46 +2387,6 @@
SDE_ATRACE_END("crtc_frame_event");
}
-static void sde_crtc_frame_event_cb(void *data, u32 event)
-{
- struct drm_crtc *crtc = (struct drm_crtc *)data;
- struct sde_crtc *sde_crtc;
- struct msm_drm_private *priv;
- struct sde_crtc_frame_event *fevent;
- unsigned long flags;
- u32 crtc_id;
-
- if (!crtc || !crtc->dev || !crtc->dev->dev_private) {
- SDE_ERROR("invalid parameters\n");
- return;
- }
- sde_crtc = to_sde_crtc(crtc);
- priv = crtc->dev->dev_private;
- crtc_id = drm_crtc_index(crtc);
-
- SDE_DEBUG("crtc%d\n", crtc->base.id);
- SDE_EVT32_VERBOSE(DRMID(crtc), event);
-
- spin_lock_irqsave(&sde_crtc->spin_lock, flags);
- fevent = list_first_entry_or_null(&sde_crtc->frame_event_list,
- struct sde_crtc_frame_event, list);
- if (fevent)
- list_del_init(&fevent->list);
- spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
-
- if (!fevent) {
- SDE_ERROR("crtc%d event %d overflow\n",
- crtc->base.id, event);
- SDE_EVT32(DRMID(crtc), event);
- return;
- }
-
- fevent->event = event;
- fevent->crtc = crtc;
- fevent->ts = ktime_get();
- kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work);
-}
-
void sde_crtc_complete_commit(struct drm_crtc *crtc,
struct drm_crtc_state *old_state)
{
@@ -2440,6 +2419,23 @@
}
/**
+ * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings
+ * @cstate: Pointer to sde crtc state
+ */
+static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate)
+{
+ u32 i;
+
+ if (!cstate)
+ return;
+
+ for (i = 0; i < cstate->num_dim_layers; i++)
+ memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i]));
+
+ cstate->num_dim_layers = 0;
+}
+
+/**
* _sde_crtc_set_dim_layer_v1 - copy dim layer settings from userspace
* @cstate: Pointer to sde crtc state
* @user_ptr: User ptr for sde_drm_dim_layer_v1 struct
@@ -2459,6 +2455,8 @@
dim_layer = cstate->dim_layer;
if (!usr_ptr) {
+ /* usr_ptr is null when setting the default property value */
+ _sde_crtc_clear_dim_layers_v1(cstate);
SDE_DEBUG("dim_layer data removed\n");
return;
}
@@ -2958,6 +2956,10 @@
if (enc->crtc != crtc)
continue;
+ /* avoid overwriting mixers info from a copy encoder */
+ if (sde_encoder_in_clone_mode(enc))
+ continue;
+
_sde_crtc_setup_mixer_for_encoder(crtc, enc);
}
@@ -4125,6 +4127,7 @@
event.type = DRM_EVENT_CRTC_POWER;
event.length = sizeof(u32);
sde_cp_crtc_suspend(crtc);
+ sde_cp_update_ad_vsync_count(crtc, 0);
power_on = 0;
msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
(u8 *)&power_on);
@@ -4191,7 +4194,8 @@
* reset the fence timeline if crtc will not be enabled for this commit
*/
if (!crtc->state->active || !crtc->state->enable) {
- sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true);
+ sde_fence_signal(&sde_crtc->output_fence,
+ ktime_get(), SDE_FENCE_RESET_TIMELINE);
for (i = 0; i < cstate->num_connectors; ++i)
sde_connector_commit_reset(cstate->connectors[i],
ktime_get());
@@ -4256,7 +4260,7 @@
if (encoder->crtc != crtc)
continue;
sde_encoder_register_frame_event_callback(encoder,
- sde_crtc_frame_event_cb, (void *)crtc);
+ sde_crtc_frame_event_cb, crtc);
}
if (!sde_crtc->enabled && !sde_crtc->suspend &&
@@ -4915,6 +4919,11 @@
{SDE_DRM_SEC_ONLY, "sec_only"},
};
+ static const struct drm_prop_enum_list e_cwb_data_points[] = {
+ {CAPTURE_MIXER_OUT, "capture_mixer_out"},
+ {CAPTURE_DSPP_OUT, "capture_pp_out"},
+ };
+
SDE_DEBUG("\n");
if (!crtc || !catalog) {
@@ -4994,6 +5003,12 @@
"enable_sui_enhancement", 0, 0, U64_MAX, 0,
CRTC_PROP_ENABLE_SUI_ENHANCEMENT);
+ if (catalog->has_cwb_support)
+ msm_property_install_enum(&sde_crtc->property_info,
+ "capture_mode", 0, 0, e_cwb_data_points,
+ ARRAY_SIZE(e_cwb_data_points),
+ CRTC_PROP_CAPTURE_OUTPUT);
+
msm_property_install_blob(&sde_crtc->property_info, "capabilities",
DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO);
@@ -5867,10 +5882,6 @@
list_add_tail(&sde_crtc->event_cache[i].list,
&sde_crtc->event_free_list);
- INIT_LIST_HEAD(&sde_crtc->retire_event_list);
- for (i = 0; i < ARRAY_SIZE(sde_crtc->retire_events); i++)
- INIT_LIST_HEAD(&sde_crtc->retire_events[i].list);
-
return rc;
}
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h
index 64f3821..53b8df9 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.h
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.h
@@ -31,7 +31,8 @@
#define SDE_CRTC_NAME_SIZE 12
/* define the maximum number of in-flight frame events */
-#define SDE_CRTC_FRAME_EVENT_SIZE 4
+/* Expand it to 2x for handling atleast 2 connectors safely */
+#define SDE_CRTC_FRAME_EVENT_SIZE (4 * 2)
/**
* enum sde_crtc_client_type: crtc client type
@@ -48,6 +49,16 @@
};
/**
+ * enum sde_crtc_output_capture_point
+ * @MIXER_OUT : capture mixer output
+ * @DSPP_OUT : capture output of dspp
+ */
+enum sde_crtc_output_capture_point {
+ CAPTURE_MIXER_OUT,
+ CAPTURE_DSPP_OUT
+};
+
+/**
* @connectors : Currently associated drm connectors for retire event
* @num_connectors: Number of associated drm connectors for retire event
* @list: event list
@@ -81,9 +92,20 @@
};
/**
+ * struct sde_crtc_frame_event_cb_data : info of drm objects of a frame event
+ * @crtc: pointer to drm crtc object registered for frame event
+ * @connector: pointer to drm connector which is source of frame event
+ */
+struct sde_crtc_frame_event_cb_data {
+ struct drm_crtc *crtc;
+ struct drm_connector *connector;
+};
+
+/**
* struct sde_crtc_frame_event: stores crtc frame event for crtc processing
* @work: base work structure
* @crtc: Pointer to crtc handling this event
+ * @connector: pointer to drm connector which is source of frame event
* @list: event list
* @ts: timestamp at queue entry
* @event: event identifier
@@ -91,6 +113,7 @@
struct sde_crtc_frame_event {
struct kthread_work work;
struct drm_crtc *crtc;
+ struct drm_connector *connector;
struct list_head list;
ktime_t ts;
u32 event;
@@ -155,13 +178,12 @@
* @dirty_list : list of color processing features are dirty
* @ad_dirty: list containing ad properties that are dirty
* @ad_active: list containing ad properties that are active
+ * @ad_vsync_count : count of vblank since last reset for AD
* @crtc_lock : crtc lock around create, destroy and access.
* @frame_pending : Whether or not an update is pending
* @frame_events : static allocation of in-flight frame events
* @frame_event_list : available frame event list
* @spin_lock : spin lock for frame event, transaction status, etc...
- * @retire_events : static allocation of retire fence connector
- * @retire_event_list : available retire fence connector list
* @frame_done_comp : for frame_event_done synchronization
* @event_thread : Pointer to event handler thread
* @event_worker : Event worker queue
@@ -224,6 +246,7 @@
struct list_head ad_dirty;
struct list_head ad_active;
struct list_head user_event_list;
+ u32 ad_vsync_count;
struct mutex crtc_lock;
struct mutex crtc_cp_lock;
@@ -232,8 +255,6 @@
struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE];
struct list_head frame_event_list;
spinlock_t spin_lock;
- struct sde_crtc_retire_event retire_events[SDE_CRTC_FRAME_EVENT_SIZE];
- struct list_head retire_event_list;
struct completion frame_done_comp;
/* for handling internal event thread */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index bea6693..2ce8b2e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -80,6 +80,11 @@
/* Maximum number of VSYNC wait attempts for RSC state transition */
#define MAX_RSC_WAIT 5
+#define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \
+ (((x) == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) || \
+ ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE) || \
+ ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC))
+
/**
* enum sde_enc_rc_events - events for resource control state machine
* @SDE_ENC_RC_EVENT_KICKOFF:
@@ -215,6 +220,7 @@
struct sde_encoder_virt {
struct drm_encoder base;
spinlock_t enc_spinlock;
+ struct mutex vblank_ctl_lock;
uint32_t bus_scaling_client;
uint32_t display_num_of_h_tiles;
@@ -234,7 +240,7 @@
struct mutex enc_lock;
DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL);
void (*crtc_frame_event_cb)(void *, u32 event);
- void *crtc_frame_event_cb_data;
+ struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data;
struct timer_list vsync_event_timer;
@@ -416,6 +422,14 @@
return false;
}
+int sde_encoder_in_clone_mode(struct drm_encoder *drm_enc)
+{
+ struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
+
+ return sde_enc && sde_enc->cur_master &&
+ sde_enc->cur_master->in_clone_mode;
+}
+
static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc,
bool enable)
{
@@ -1586,11 +1600,16 @@
* only primary command mode panel can request CMD state.
* all other panels/displays can request for VID state including
* secondary command mode panel.
+ * Clone mode encoder can request CLK STATE only.
*/
- rsc_state = enable ?
- (((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) &&
- disp_info->is_primary) ? SDE_RSC_CMD_STATE :
- SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+ if (sde_encoder_in_clone_mode(drm_enc))
+ rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE;
+ else
+ rsc_state = enable ?
+ (((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE)
+ && disp_info->is_primary) ? SDE_RSC_CMD_STATE :
+ SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE;
+
prefill_lines = config ? mode_info.prefill_lines +
config->inline_rotate_prefill : mode_info.prefill_lines;
@@ -2301,10 +2320,17 @@
_sde_encoder_resource_control_rsc_update(drm_enc, true);
_sde_encoder_resource_control_helper(drm_enc, true);
+ /*
+ * In some cases, commit comes with slight delay
+ * (> 80 ms)after early wake up, prevent clock switch
+ * off to avoid jank in next update. So, increase the
+ * command mode idle timeout sufficiently to prevent
+ * such case.
+ */
kthread_mod_delayed_work(&disp_thread->worker,
- &sde_enc->delayed_off_work,
- msecs_to_jiffies(
- IDLE_POWERCOLLAPSE_DURATION));
+ &sde_enc->delayed_off_work,
+ msecs_to_jiffies(
+ IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP));
sde_enc->rc_state = SDE_ENC_RC_STATE_ON;
}
@@ -2648,7 +2674,6 @@
struct sde_encoder_virt *sde_enc = NULL;
struct msm_drm_private *priv;
struct sde_kms *sde_kms;
- struct drm_connector *drm_conn = NULL;
enum sde_intf_mode intf_mode;
int i = 0;
@@ -2677,10 +2702,6 @@
SDE_EVT32(DRMID(drm_enc));
- /* Disable ESD thread */
- drm_conn = sde_enc->cur_master->connector;
- sde_connector_schedule_status_work(drm_conn, false);
-
/* wait for idle */
sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE);
@@ -2838,8 +2859,8 @@
}
void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc,
- void (*frame_event_cb)(void *, u32 event),
- void *frame_event_cb_data)
+ void (*frame_event_cb)(void *, u32 event),
+ struct drm_crtc *crtc)
{
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
unsigned long lock_flags;
@@ -2856,7 +2877,7 @@
spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags);
sde_enc->crtc_frame_event_cb = frame_event_cb;
- sde_enc->crtc_frame_event_cb_data = frame_event_cb_data;
+ sde_enc->crtc_frame_event_cb_data.crtc = crtc;
spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags);
}
@@ -2867,6 +2888,9 @@
struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc);
unsigned int i;
+ sde_enc->crtc_frame_event_cb_data.connector =
+ sde_enc->cur_master->connector;
+
if (event & (SDE_ENCODER_FRAME_EVENT_DONE
| SDE_ENCODER_FRAME_EVENT_ERROR
| SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
@@ -2895,13 +2919,13 @@
if (sde_enc->crtc_frame_event_cb)
sde_enc->crtc_frame_event_cb(
- sde_enc->crtc_frame_event_cb_data,
+ &sde_enc->crtc_frame_event_cb_data,
event);
}
} else {
if (sde_enc->crtc_frame_event_cb)
sde_enc->crtc_frame_event_cb(
- sde_enc->crtc_frame_event_cb_data, event);
+ &sde_enc->crtc_frame_event_cb_data, event);
}
}
@@ -3010,6 +3034,10 @@
return;
}
+ /* avoid ctrl start for encoder in clone mode */
+ if (phys->in_clone_mode)
+ return;
+
ctl = phys->hw_ctl;
if (phys->split_role == ENC_ROLE_SKIP) {
SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent),
@@ -3402,13 +3430,14 @@
static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys)
{
void *dither_cfg;
- int ret = 0, rc;
+ int ret = 0, rc, i = 0;
size_t len = 0;
enum sde_rm_topology_name topology;
struct drm_encoder *drm_enc;
struct msm_mode_info mode_info;
struct msm_display_dsc_info *dsc = NULL;
struct sde_encoder_virt *sde_enc;
+ struct sde_hw_pingpong *hw_pp;
if (!phys || !phys->connector || !phys->hw_pp ||
!phys->hw_pp->ops.setup_dither || !phys->parent)
@@ -3431,12 +3460,24 @@
/* disable dither for 10 bpp or 10bpc dsc config */
if (dsc->bpp == 10 || dsc->bpc == 10) {
phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0);
+ return;
+ }
+
+ ret = sde_connector_get_dither_cfg(phys->connector,
+ phys->connector->state, &dither_cfg, &len);
+ if (ret)
+ return;
+
+ if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) {
+ for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) {
+ hw_pp = sde_enc->hw_pp[i];
+ if (hw_pp) {
+ phys->hw_pp->ops.setup_dither(hw_pp, dither_cfg,
+ len);
+ }
+ }
} else {
- ret = sde_connector_get_dither_cfg(phys->connector,
- phys->connector->state, &dither_cfg, &len);
- if (!ret)
- phys->hw_pp->ops.setup_dither(phys->hw_pp,
- dither_cfg, len);
+ phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len);
}
}
@@ -4388,6 +4429,7 @@
phys_params.parent = &sde_enc->base;
phys_params.parent_ops = parent_ops;
phys_params.enc_spinlock = &sde_enc->enc_spinlock;
+ phys_params.vblank_ctl_lock = &sde_enc->vblank_ctl_lock;
SDE_DEBUG("\n");
@@ -4530,6 +4572,7 @@
sde_enc->cur_master = NULL;
spin_lock_init(&sde_enc->enc_spinlock);
+ mutex_init(&sde_enc->vblank_ctl_lock);
drm_enc = &sde_enc->base;
drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL);
drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs);
@@ -4858,10 +4901,14 @@
SDE_EVT32_VERBOSE(DRMID(enc));
disp_thread = &priv->disp_thread[sde_enc->crtc->index];
-
- kthread_queue_work(&disp_thread->worker,
- &sde_enc->esd_trigger_work);
- kthread_flush_work(&sde_enc->esd_trigger_work);
+ if (current->tgid == disp_thread->thread->tgid) {
+ sde_encoder_resource_control(&sde_enc->base,
+ SDE_ENC_RC_EVENT_KICKOFF);
+ } else {
+ kthread_queue_work(&disp_thread->worker,
+ &sde_enc->esd_trigger_work);
+ kthread_flush_work(&sde_enc->esd_trigger_work);
+ }
/**
* panel may stop generating te signal (vsync) during esd failure. rsc
* hardware may hang without vsync. Avoid rsc hang by generating the
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 0e8e9dd..42b9e58 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -31,6 +31,7 @@
#define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE BIT(4)
#define IDLE_POWERCOLLAPSE_DURATION (66 - 16/2)
+#define IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP (200 - 16/2)
/**
* Encoder functions and data types
@@ -97,10 +98,10 @@
* will be called after the request is complete, or other events.
* @encoder: encoder pointer
* @cb: callback pointer, provide NULL to deregister
- * @data: user data provided to callback
+ * @crtc: pointer to drm_crtc object interested in frame events
*/
void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder,
- void (*cb)(void *, u32), void *data);
+ void (*cb)(void *, u32), struct drm_crtc *crtc);
/**
* sde_encoder_get_rsc_client - gets the rsc client state for primary
@@ -242,14 +243,18 @@
* esd timeout or other display failure notification. This event flows from
* dsi, sde_connector to sde_encoder.
*
- * This api must not be called from crtc_commit (display) thread because it
- * requests the flush work on same thread. It is called from esd check thread
- * based on current design.
- *
* TODO: manage the event at sde_kms level for forward processing.
* @drm_enc: Pointer to drm encoder structure
* @Return: true if successful in updating the encoder structure
*/
int sde_encoder_display_failure_notification(struct drm_encoder *enc);
+/**
+ * sde_encoder_in_clone_mode - checks if underlying phys encoder is in clone
+ * mode or independent display mode. ref@ WB in Concurrent writeback mode.
+ * @drm_enc: Pointer to drm encoder structure
+ * @Return: true if successful in updating the encoder structure
+ */
+int sde_encoder_in_clone_mode(struct drm_encoder *enc);
+
#endif /* __SDE_ENCODER_H__ */
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 9557d41..4e9430e 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -194,6 +194,9 @@
* @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel
* @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel
* @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel
+ * @INTR_IDX_WB_DONE: Writeback done interrupt for WB
+ * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB
+ * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP3 for Concurrent WB
* @INTR_IDX_AUTOREFRESH_DONE: Autorefresh done for cmd mode panel meaning
* autorefresh has triggered a double buffer flip
*/
@@ -204,6 +207,9 @@
INTR_IDX_CTL_START,
INTR_IDX_RDPTR,
INTR_IDX_AUTOREFRESH_DONE,
+ INTR_IDX_WB_DONE,
+ INTR_IDX_PP2_OVFL,
+ INTR_IDX_PP3_OVFL,
INTR_IDX_MAX,
};
@@ -263,6 +269,7 @@
* @irq: IRQ tracking structures
* @cont_splash_single_flush Variable to check if single flush is enabled.
* @cont_splash_settings Variable to store continuous splash settings.
+ * @in_clone_mode Indicates if encoder is in clone mode ref@CWB
* @vfp_cached: cached vertical front porch to be used for
* programming ROT and MDP fetch start
*/
@@ -284,6 +291,7 @@
enum msm_display_compression_type comp_type;
spinlock_t *enc_spinlock;
enum sde_enc_enable_state enable_state;
+ struct mutex *vblank_ctl_lock;
atomic_t vblank_refcount;
atomic_t vsync_cnt;
atomic_t underrun_cnt;
@@ -294,6 +302,7 @@
struct sde_encoder_irq irq[INTR_IDX_MAX];
u32 cont_splash_single_flush;
bool cont_splash_settings;
+ bool in_clone_mode;
int vfp_cached;
};
@@ -367,7 +376,6 @@
* writeback specific operations
* @base: Baseclass physical encoder structure
* @hw_wb: Hardware interface to the wb registers
- * @irq_idx: IRQ interface lookup index
* @wbdone_timeout: Timeout value for writeback done in msec
* @bypass_irqreg: Bypass irq register/unregister if non-zero
* @wbdone_complete: for wbdone irq synchronization
@@ -391,8 +399,6 @@
struct sde_encoder_phys_wb {
struct sde_encoder_phys base;
struct sde_hw_wb *hw_wb;
- int irq_idx;
- struct sde_irq_callback irq_cb;
u32 wbdone_timeout;
u32 bypass_irqreg;
struct completion wbdone_complete;
@@ -434,6 +440,7 @@
enum sde_wb wb_idx;
enum msm_display_compression_type comp_type;
spinlock_t *enc_spinlock;
+ struct mutex *vblank_ctl_lock;
};
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 828d771..f06ceb7 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -680,6 +680,7 @@
return -EINVAL;
}
+ mutex_lock(phys_enc->vblank_ctl_lock);
refcount = atomic_read(&phys_enc->vblank_refcount);
/* Slave encoders don't report vblank */
@@ -713,6 +714,7 @@
enable, refcount, SDE_EVTLOG_ERROR);
}
+ mutex_unlock(phys_enc->vblank_ctl_lock);
return ret;
}
@@ -1398,6 +1400,7 @@
phys_enc->split_role = p->split_role;
phys_enc->intf_mode = INTF_MODE_CMD;
phys_enc->enc_spinlock = p->enc_spinlock;
+ phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
cmd_enc->stream_sel = 0;
phys_enc->enable_state = SDE_ENC_DISABLED;
phys_enc->comp_type = p->comp_type;
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 862a8b3..d363d62 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -625,6 +625,7 @@
return -EINVAL;
}
+ mutex_lock(phys_enc->vblank_ctl_lock);
refcount = atomic_read(&phys_enc->vblank_refcount);
vid_enc = to_sde_encoder_phys_vid(phys_enc);
@@ -645,11 +646,17 @@
SDE_EVT32(DRMID(phys_enc->parent), enable,
atomic_read(&phys_enc->vblank_refcount));
- if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1)
+ if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) {
ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_VSYNC);
- else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0)
+ if (ret)
+ atomic_dec_return(&phys_enc->vblank_refcount);
+ } else if (!enable &&
+ atomic_dec_return(&phys_enc->vblank_refcount) == 0) {
ret = sde_encoder_helper_unregister_irq(phys_enc,
INTR_IDX_VSYNC);
+ if (ret)
+ atomic_inc_return(&phys_enc->vblank_refcount);
+ }
end:
if (ret) {
@@ -660,6 +667,7 @@
vid_enc->hw_intf->idx - INTF_0,
enable, refcount, SDE_EVTLOG_ERROR);
}
+ mutex_unlock(phys_enc->vblank_ctl_lock);
return ret;
}
@@ -1233,6 +1241,7 @@
phys_enc->split_role = p->split_role;
phys_enc->intf_mode = INTF_MODE_VIDEO;
phys_enc->enc_spinlock = p->enc_spinlock;
+ phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
phys_enc->comp_type = p->comp_type;
for (i = 0; i < INTR_IDX_MAX; i++) {
irq = &phys_enc->irq[i];
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 9a90075..bad608d 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
+ * 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
@@ -32,6 +32,7 @@
#define TO_S15D16(_x_) ((_x_) << 7)
+#define MULTIPLE_CONN_DETECTED(x) (x > 1)
/**
* sde_rgb2yuv_601l - rgb to yuv color space conversion matrix
*
@@ -398,6 +399,31 @@
}
}
+static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc,
+ bool enable)
+{
+ struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+ struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
+ struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
+ struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl;
+ struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc);
+
+ if (!phys_enc->in_clone_mode) {
+ SDE_DEBUG("not in CWB mode. early return\n");
+ return;
+ }
+
+ memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
+ intf_cfg->intf = SDE_NONE;
+ intf_cfg->wb = hw_wb->idx;
+
+ hw_ctl = crtc->mixers[0].hw_ctl;
+ if (hw_ctl && hw_ctl->ops.update_wb_cfg) {
+ hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable);
+ SDE_DEBUG("in CWB mode adding WB for CTL_%d\n",
+ hw_ctl->idx - CTL_0);
+ }
+}
/**
* sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block
* @phys_enc: Pointer to physical encoder
@@ -408,8 +434,12 @@
struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg;
- memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
+ if (phys_enc->in_clone_mode) {
+ SDE_DEBUG("in CWB mode. early return\n");
+ return;
+ }
+ memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg));
intf_cfg->intf = SDE_NONE;
intf_cfg->wb = hw_wb->idx;
intf_cfg->mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc);
@@ -417,6 +447,98 @@
if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg)
phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl,
intf_cfg);
+
+}
+
+static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
+ 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;
+
+ /* Check if WB has CWB support */
+ if (!(wb_cfg->features & 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++;
+ }
+
+
+ /* 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);
+}
+
+static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state);
+ struct sde_rect wb_roi = {0,};
+ int data_pt;
+ int ds_outw = 0;
+ int ds_outh = 0;
+ int ds_in_use = false;
+ int i = 0;
+ int ret = 0;
+
+ if (!phys_enc->in_clone_mode) {
+ SDE_DEBUG("not in CWB mode. early return\n");
+ goto exit;
+ }
+
+ ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
+ if (ret) {
+ SDE_ERROR("failed to get roi %d\n", ret);
+ goto exit;
+ }
+
+ data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT);
+
+ /* compute cumulative ds output dimensions if in use */
+ for (i = 0; i < cstate->num_ds; i++)
+ if (cstate->ds_cfg[i].scl3_cfg.enable) {
+ ds_in_use = true;
+ ds_outw += cstate->ds_cfg[i].scl3_cfg.dst_width;
+ ds_outh += cstate->ds_cfg[i].scl3_cfg.dst_height;
+ }
+
+ /* if ds in use check wb roi against ds output dimensions */
+ if ((data_pt == CAPTURE_DSPP_OUT) && ds_in_use &&
+ ((wb_roi.w != ds_outw) || (wb_roi.h != ds_outh))) {
+ SDE_ERROR("invalid wb roi with dest scalar [%dx%d vs %dx%d]\n",
+ wb_roi.w, wb_roi.h, ds_outw, ds_outh);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* validate conn roi against pu rect */
+ if (!sde_kms_rect_is_null(&cstate->crtc_roi)) {
+ if (wb_roi.w != cstate->crtc_roi.w ||
+ wb_roi.h != cstate->crtc_roi.h) {
+ SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n",
+ wb_roi.w, wb_roi.h, cstate->crtc_roi.w,
+ cstate->crtc_roi.h);
+ ret = -EINVAL;
+ goto exit;
+ }
+ }
+exit:
+ return ret;
}
/**
@@ -453,6 +575,8 @@
return -EINVAL;
}
+ _sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state);
+
memset(&wb_roi, 0, sizeof(struct sde_rect));
rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi);
@@ -542,7 +666,62 @@
}
}
- return 0;
+ rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, conn_state);
+ if (rc) {
+ SDE_ERROR("failed in cwb validation %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static void _sde_encoder_phys_wb_update_cwb_flush(
+ struct sde_encoder_phys *phys_enc)
+{
+ struct sde_encoder_phys_wb *wb_enc;
+ struct sde_hw_wb *hw_wb;
+ struct sde_hw_ctl *hw_ctl;
+ struct sde_hw_cdm *hw_cdm;
+ struct sde_crtc *crtc;
+ struct sde_crtc_state *crtc_state;
+ u32 flush_mask = 0;
+ int capture_point = 0;
+
+ if (!phys_enc->in_clone_mode) {
+ SDE_DEBUG("not in CWB mode. early return\n");
+ return;
+ }
+
+ wb_enc = to_sde_encoder_phys_wb(phys_enc);
+ crtc = to_sde_crtc(wb_enc->crtc);
+ crtc_state = to_sde_crtc_state(wb_enc->crtc->state);
+
+ hw_wb = wb_enc->hw_wb;
+ hw_cdm = phys_enc->hw_cdm;
+
+ /* In CWB mode, program actual source master sde_hw_ctl from crtc */
+ hw_ctl = crtc->mixers[0].hw_ctl;
+ if (!hw_ctl) {
+ SDE_DEBUG("[wb:%d] no ctl assigned for CWB\n",
+ hw_wb->idx - WB_0);
+ return;
+ }
+
+ capture_point = sde_crtc_get_property(crtc_state,
+ CRTC_PROP_CAPTURE_OUTPUT);
+
+ phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop,
+ crtc->num_mixers == CRTC_DUAL_MIXERS,
+ capture_point == CAPTURE_DSPP_OUT);
+
+ if (hw_ctl->ops.get_bitmask_wb)
+ hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx);
+
+ if (hw_ctl->ops.get_bitmask_cdm && hw_cdm)
+ hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx);
+
+ if (hw_ctl->ops.update_pending_flush)
+ hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask);
}
/**
@@ -551,7 +730,7 @@
*/
static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc)
{
- struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
+ struct sde_encoder_phys_wb *wb_enc;
struct sde_hw_wb *hw_wb;
struct sde_hw_ctl *hw_ctl;
struct sde_hw_cdm *hw_cdm;
@@ -560,12 +739,18 @@
if (!phys_enc)
return;
+ wb_enc = to_sde_encoder_phys_wb(phys_enc);
hw_wb = wb_enc->hw_wb;
- hw_ctl = phys_enc->hw_ctl;
hw_cdm = phys_enc->hw_cdm;
+ hw_ctl = phys_enc->hw_ctl;
SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0);
+ if (phys_enc->in_clone_mode) {
+ SDE_DEBUG("in CWB mode. early return\n");
+ return;
+ }
+
if (!hw_ctl) {
SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0);
return;
@@ -659,54 +844,28 @@
sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi);
sde_encoder_phys_wb_setup_cdp(phys_enc);
+
+ _sde_encoder_phys_wb_setup_cwb(phys_enc, true);
}
-/**
- * sde_encoder_phys_wb_unregister_irq - unregister writeback interrupt handler
- * @phys_enc: Pointer to physical encoder
- */
-static int sde_encoder_phys_wb_unregister_irq(
- struct sde_encoder_phys *phys_enc)
-{
- struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
- struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
-
- if (wb_enc->bypass_irqreg)
- return 0;
-
- sde_core_irq_disable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
- sde_core_irq_unregister_callback(phys_enc->sde_kms, wb_enc->irq_idx,
- &wb_enc->irq_cb);
-
- SDE_DEBUG("un-register IRQ for wb %d, irq_idx=%d\n",
- hw_wb->idx - WB_0,
- wb_enc->irq_idx);
-
- return 0;
-}
-
-/**
- * sde_encoder_phys_wb_done_irq - writeback interrupt handler
- * @arg: Pointer to writeback encoder
- * @irq_idx: interrupt index
- */
-static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
+static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error)
{
struct sde_encoder_phys_wb *wb_enc = arg;
struct sde_encoder_phys *phys_enc = &wb_enc->base;
struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
- u32 event = 0;
+ u32 event = frame_error ? SDE_ENCODER_FRAME_EVENT_ERROR : 0;
- SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0,
- wb_enc->frame_count);
+ event |= SDE_ENCODER_FRAME_EVENT_DONE |
+ SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE;
+
+ SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count);
/* don't notify upper layer for internal commit */
if (phys_enc->enable_state == SDE_ENC_DISABLING)
goto complete;
- event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE
- | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE
- | SDE_ENCODER_FRAME_EVENT_DONE;
+ if (!phys_enc->in_clone_mode)
+ event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE;
atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0);
if (phys_enc->parent_ops.handle_frame_done)
@@ -724,58 +883,60 @@
}
/**
- * sde_encoder_phys_wb_register_irq - register writeback interrupt handler
- * @phys_enc: Pointer to physical encoder
+ * sde_encoder_phys_wb_done_irq - Pingpong overflow interrupt handler for CWB
+ * @arg: Pointer to writeback encoder
+ * @irq_idx: interrupt index
*/
-static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc)
+static void sde_encoder_phys_cwb_ovflow(void *arg, int irq_idx)
{
- struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
- struct sde_hw_wb *hw_wb = wb_enc->hw_wb;
- struct sde_irq_callback *irq_cb = &wb_enc->irq_cb;
- enum sde_intr_type intr_type;
- int ret = 0;
+ _sde_encoder_phys_wb_frame_done_helper(arg, true);
+}
+
+/**
+ * sde_encoder_phys_wb_done_irq - writeback interrupt handler
+ * @arg: Pointer to writeback encoder
+ * @irq_idx: interrupt index
+ */
+static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx)
+{
+ _sde_encoder_phys_wb_frame_done_helper(arg, false);
+}
+
+/**
+ * sde_encoder_phys_wb_irq_ctrl - irq control of WB
+ * @phys: Pointer to physical encoder
+ * @enable: indicates enable or disable interrupts
+ */
+static void sde_encoder_phys_wb_irq_ctrl(
+ struct sde_encoder_phys *phys, bool enable)
+{
+
+ struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys);
+ int index = 0;
+
+ if (!wb_enc)
+ return;
if (wb_enc->bypass_irqreg)
- return 0;
+ return;
- intr_type = sde_encoder_phys_wb_get_intr_type(hw_wb);
- wb_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms,
- intr_type, hw_wb->idx);
- if (wb_enc->irq_idx < 0) {
- SDE_ERROR(
- "failed to lookup IRQ index for WB_DONE with wb=%d\n",
- hw_wb->idx - WB_0);
- return -EINVAL;
+ if (enable) {
+ sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE);
+ if (phys->in_clone_mode) {
+ for (index = 0; index < CRTC_DUAL_MIXERS; index++)
+ sde_encoder_helper_register_irq(phys,
+ index ? INTR_IDX_PP3_OVFL
+ : INTR_IDX_PP2_OVFL);
+ }
+ } else {
+ sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE);
+ if (phys->in_clone_mode) {
+ for (index = 0; index < CRTC_DUAL_MIXERS; index++)
+ sde_encoder_helper_unregister_irq(phys,
+ index ? INTR_IDX_PP3_OVFL
+ : INTR_IDX_PP2_OVFL);
+ }
}
-
- irq_cb->func = sde_encoder_phys_wb_done_irq;
- irq_cb->arg = wb_enc;
- ret = sde_core_irq_register_callback(phys_enc->sde_kms,
- wb_enc->irq_idx, irq_cb);
- if (ret) {
- SDE_ERROR("failed to register IRQ callback WB_DONE\n");
- return ret;
- }
-
- ret = sde_core_irq_enable(phys_enc->sde_kms, &wb_enc->irq_idx, 1);
- if (ret) {
- SDE_ERROR(
- "failed to enable IRQ for WB_DONE, wb %d, irq_idx=%d\n",
- hw_wb->idx - WB_0,
- wb_enc->irq_idx);
- wb_enc->irq_idx = -EINVAL;
-
- /* Unregister callback on IRQ enable failure */
- sde_core_irq_unregister_callback(phys_enc->sde_kms,
- wb_enc->irq_idx, irq_cb);
- return ret;
- }
-
- SDE_DEBUG("registered IRQ for wb %d, irq_idx=%d\n",
- hw_wb->idx - WB_0,
- wb_enc->irq_idx);
-
- return ret;
}
/**
@@ -846,6 +1007,7 @@
u32 irq_status, event = 0;
u64 wb_time = 0;
int rc = 0;
+ int irq_idx = phys_enc->irq[INTR_IDX_WB_DONE].irq_idx;
u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS);
/* Return EWOULDBLOCK since we know the wait isn't necessary */
@@ -860,7 +1022,7 @@
/* signal completion if commit with no framebuffer */
if (!wb_enc->wb_fb) {
SDE_DEBUG("no output framebuffer\n");
- sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
+ _sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
}
ret = wait_for_completion_timeout(&wb_enc->wbdone_complete,
@@ -870,11 +1032,11 @@
SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc),
wb_enc->frame_count);
irq_status = sde_core_irq_read(phys_enc->sde_kms,
- wb_enc->irq_idx, true);
+ irq_idx, true);
if (irq_status) {
SDE_DEBUG("wb:%d done but irq not triggered\n",
WBID(wb_enc));
- sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx);
+ _sde_encoder_phys_wb_frame_done_helper(wb_enc, false);
} else {
SDE_ERROR("wb:%d kickoff timed out\n",
WBID(wb_enc));
@@ -891,8 +1053,6 @@
}
}
- sde_encoder_phys_wb_unregister_irq(phys_enc);
-
if (!rc)
wb_enc->end_time = ktime_get();
@@ -937,19 +1097,12 @@
struct sde_encoder_kickoff_params *params)
{
struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc);
- int ret;
SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0,
wb_enc->kickoff_count);
reinit_completion(&wb_enc->wbdone_complete);
- ret = sde_encoder_phys_wb_register_irq(phys_enc);
- if (ret) {
- SDE_ERROR("failed to register irq %d\n", ret);
- return ret;
- }
-
wb_enc->kickoff_count++;
/* set OT limit & enable traffic shaper */
@@ -957,6 +1110,8 @@
_sde_encoder_phys_wb_update_flush(phys_enc);
+ _sde_encoder_phys_wb_update_cwb_flush(phys_enc);
+
/* vote for iommu/clk/bus */
wb_enc->start_time = ktime_get();
@@ -977,6 +1132,15 @@
return;
}
+ /*
+ * Bail out iff in CWB mode. In case of CWB, primary control-path
+ * which is actually driving would trigger the flush
+ */
+ if (phys_enc->in_clone_mode) {
+ SDE_DEBUG("in CWB mode. early return\n");
+ return;
+ }
+
SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0);
/* clear pending flush if commit with no framebuffer */
@@ -1183,6 +1347,13 @@
goto exit;
}
+ /* avoid reset frame for CWB */
+ if (phys_enc->in_clone_mode) {
+ _sde_encoder_phys_wb_setup_cwb(phys_enc, false);
+ phys_enc->in_clone_mode = false;
+ goto exit;
+ }
+
/* reset h/w before final flush */
if (phys_enc->hw_ctl->ops.clear_pending_flush)
phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl);
@@ -1320,6 +1491,7 @@
ops->trigger_flush = sde_encoder_phys_wb_trigger_flush;
ops->trigger_start = sde_encoder_helper_trigger_start;
ops->hw_reset = sde_encoder_helper_hw_reset;
+ ops->irq_control = sde_encoder_phys_wb_irq_ctrl;
}
/**
@@ -1332,6 +1504,7 @@
struct sde_encoder_phys *phys_enc;
struct sde_encoder_phys_wb *wb_enc;
struct sde_hw_mdp *hw_mdp;
+ struct sde_encoder_irq *irq;
int ret = 0;
SDE_DEBUG("\n");
@@ -1348,7 +1521,6 @@
ret = -ENOMEM;
goto fail_alloc;
}
- wb_enc->irq_idx = -EINVAL;
wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS;
init_completion(&wb_enc->wbdone_complete);
@@ -1410,8 +1582,38 @@
phys_enc->intf_mode = INTF_MODE_WB_LINE;
phys_enc->intf_idx = p->intf_idx;
phys_enc->enc_spinlock = p->enc_spinlock;
+ phys_enc->vblank_ctl_lock = p->vblank_ctl_lock;
atomic_set(&phys_enc->pending_retire_fence_cnt, 0);
- INIT_LIST_HEAD(&wb_enc->irq_cb.list);
+
+ irq = &phys_enc->irq[INTR_IDX_WB_DONE];
+ INIT_LIST_HEAD(&irq->cb.list);
+ irq->name = "wb_done";
+ irq->hw_idx = wb_enc->hw_wb->idx;
+ irq->irq_idx = -1;
+ irq->intr_type = sde_encoder_phys_wb_get_intr_type(wb_enc->hw_wb);
+ irq->intr_idx = INTR_IDX_WB_DONE;
+ irq->cb.arg = wb_enc;
+ irq->cb.func = sde_encoder_phys_wb_done_irq;
+
+ irq = &phys_enc->irq[INTR_IDX_PP2_OVFL];
+ INIT_LIST_HEAD(&irq->cb.list);
+ irq->name = "pp2_overflow";
+ irq->hw_idx = CWB_2;
+ irq->irq_idx = -1;
+ irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
+ irq->intr_idx = INTR_IDX_PP2_OVFL;
+ irq->cb.arg = wb_enc;
+ irq->cb.func = sde_encoder_phys_cwb_ovflow;
+
+ irq = &phys_enc->irq[INTR_IDX_PP3_OVFL];
+ INIT_LIST_HEAD(&irq->cb.list);
+ irq->name = "pp3_overflow";
+ irq->hw_idx = CWB_3;
+ irq->irq_idx = -1;
+ irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW;
+ irq->intr_idx = INTR_IDX_PP3_OVFL;
+ irq->cb.arg = wb_enc;
+ irq->cb.func = sde_encoder_phys_cwb_ovflow;
/* create internal buffer for disable logic */
if (_sde_encoder_phys_wb_init_internal_fb(wb_enc,
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c
index 686c640..1f30a5c 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.c
+++ b/drivers/gpu/drm/msm/sde/sde_fence.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -278,7 +278,8 @@
}
}
-static void _sde_fence_trigger(struct sde_fence_context *ctx, ktime_t ts)
+static void _sde_fence_trigger(struct sde_fence_context *ctx,
+ ktime_t ts, bool error)
{
unsigned long flags;
struct sde_fence *fc, *next;
@@ -300,6 +301,7 @@
list_for_each_entry_safe(fc, next, &local_list_head, fence_list) {
spin_lock_irqsave(&ctx->lock, flags);
+ fc->base.error = error ? -EBUSY : 0;
fc->base.timestamp = ts;
is_signaled = fence_is_signaled_locked(&fc->base);
spin_unlock_irqrestore(&ctx->lock, flags);
@@ -351,7 +353,7 @@
if (fd >= 0) {
rc = 0;
- _sde_fence_trigger(ctx, ktime_get());
+ _sde_fence_trigger(ctx, ktime_get(), false);
} else {
rc = fd;
}
@@ -360,7 +362,7 @@
}
void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts,
- bool reset_timeline)
+ enum sde_fence_event fence_event)
{
unsigned long flags;
@@ -370,7 +372,7 @@
}
spin_lock_irqsave(&ctx->lock, flags);
- if (reset_timeline) {
+ if (fence_event == SDE_FENCE_RESET_TIMELINE) {
if ((int)(ctx->done_count - ctx->commit_count) < 0) {
SDE_ERROR(
"timeline reset attempt! done count:%d commit:%d\n",
@@ -378,7 +380,7 @@
ctx->done_count = ctx->commit_count;
SDE_EVT32(ctx->drm_id, ctx->done_count,
ctx->commit_count, ktime_to_us(ts),
- reset_timeline, SDE_EVTLOG_FATAL);
+ fence_event, SDE_EVTLOG_FATAL);
} else {
spin_unlock_irqrestore(&ctx->lock, flags);
return;
@@ -391,7 +393,7 @@
SDE_ERROR("extra signal attempt! done count:%d commit:%d\n",
ctx->done_count, ctx->commit_count);
SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
- ktime_to_us(ts), reset_timeline, SDE_EVTLOG_FATAL);
+ ktime_to_us(ts), fence_event, SDE_EVTLOG_FATAL);
spin_unlock_irqrestore(&ctx->lock, flags);
return;
}
@@ -400,7 +402,7 @@
SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count,
ktime_to_us(ts));
- _sde_fence_trigger(ctx, ts);
+ _sde_fence_trigger(ctx, ts, (fence_event == SDE_FENCE_SIGNAL_ERROR));
}
void sde_fence_timeline_status(struct sde_fence_context *ctx,
diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h
index 29d2ec7..7891be4 100644
--- a/drivers/gpu/drm/msm/sde/sde_fence.h
+++ b/drivers/gpu/drm/msm/sde/sde_fence.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -47,6 +47,18 @@
char name[SDE_FENCE_NAME_SIZE];
};
+/**
+ * enum sde_fence_event - sde fence event as hint fence operation
+ * @SDE_FENCE_SIGNAL: Signal the fence cleanly with current timeline
+ * @SDE_FENCE_RESET_TIMELINE: Reset timeline of the fence context
+ * @SDE_FENCE_SIGNAL: Signal the fence but indicate error throughfence status
+ */
+enum sde_fence_event {
+ SDE_FENCE_SIGNAL,
+ SDE_FENCE_RESET_TIMELINE,
+ SDE_FENCE_SIGNAL_ERROR
+};
+
#if IS_ENABLED(CONFIG_SYNC_FILE)
/**
* sde_sync_get - Query sync fence object from a file handle
@@ -128,10 +140,10 @@
* sde_fence_signal - advance fence timeline to signal outstanding fences
* @fence: Pointer fence container
* @ts: fence timestamp
- * @reset_timeline: reset the fence timeline to done count equal to commit count
+ * @fence_event: fence event to indicate nature of fence signal.
*/
void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts,
- bool reset_timeline);
+ enum sde_fence_event fence_event);
/**
* sde_fence_timeline_status - prints fence timeline status
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
index 66445da..e60defd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c
@@ -109,6 +109,9 @@
static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp,
struct sde_ad_hw_cfg *cfg);
+static int ad4_vsync_update(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg);
+
static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = {
[ad4_state_idle][AD_MODE] = ad4_mode_setup_common,
[ad4_state_idle][AD_INIT] = ad4_init_setup_idle,
@@ -121,6 +124,7 @@
[ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup,
[ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup,
[ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup,
+ [ad4_state_idle][AD_VSYNC_UPDATE] = ad4_no_op_setup,
[ad4_state_startup][AD_MODE] = ad4_mode_setup_common,
[ad4_state_startup][AD_INIT] = ad4_init_setup,
@@ -133,6 +137,7 @@
[ad4_state_startup][AD_STRENGTH] = ad4_no_op_setup,
[ad4_state_startup][AD_IPC_RESUME] = ad4_no_op_setup,
[ad4_state_startup][AD_IPC_RESET] = ad4_ipc_reset_setup_startup,
+ [ad4_state_startup][AD_VSYNC_UPDATE] = ad4_vsync_update,
[ad4_state_run][AD_MODE] = ad4_mode_setup_common,
[ad4_state_run][AD_INIT] = ad4_init_setup_run,
@@ -145,6 +150,7 @@
[ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run,
[ad4_state_run][AD_IPC_RESUME] = ad4_no_op_setup,
[ad4_state_run][AD_IPC_RESET] = ad4_setup_debug,
+ [ad4_state_run][AD_VSYNC_UPDATE] = ad4_vsync_update,
[ad4_state_ipcs][AD_MODE] = ad4_no_op_setup,
[ad4_state_ipcs][AD_INIT] = ad4_no_op_setup,
@@ -157,6 +163,7 @@
[ad4_state_ipcs][AD_IPC_SUSPEND] = ad4_no_op_setup,
[ad4_state_ipcs][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcs,
[ad4_state_ipcs][AD_IPC_RESET] = ad4_no_op_setup,
+ [ad4_state_ipcs][AD_VSYNC_UPDATE] = ad4_no_op_setup,
[ad4_state_ipcr][AD_MODE] = ad4_mode_setup_common,
[ad4_state_ipcr][AD_INIT] = ad4_init_setup_ipcr,
@@ -169,6 +176,7 @@
[ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_ipcr,
[ad4_state_ipcr][AD_IPC_RESUME] = ad4_no_op_setup,
[ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr,
+ [ad4_state_ipcr][AD_VSYNC_UPDATE] = ad4_no_op_setup,
[ad4_state_manual][AD_MODE] = ad4_mode_setup_common,
[ad4_state_manual][AD_INIT] = ad4_init_setup,
@@ -181,6 +189,7 @@
[ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup,
[ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup,
[ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual,
+ [ad4_state_manual][AD_VSYNC_UPDATE] = ad4_no_op_setup,
};
struct ad4_info {
@@ -201,6 +210,7 @@
u32 irdx_control_0;
u32 tf_ctrl;
u32 vc_control_0;
+ u32 frame_pushes;
};
static struct ad4_info info[DSPP_MAX] = {
@@ -905,6 +915,8 @@
val = (ad_cfg->cfg_param_046 & (BIT(16) - 1));
SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val);
+ info[dspp->idx].frame_pushes = ad_cfg->cfg_param_047;
+
return 0;
}
@@ -1546,3 +1558,25 @@
ad4_mode_setup(dspp, info[dspp->idx].mode);
return 0;
}
+
+static int ad4_vsync_update(struct sde_hw_dspp *dspp,
+ struct sde_ad_hw_cfg *cfg)
+{
+ u32 *count;
+ struct sde_hw_mixer *hw_lm;
+
+ if (cfg->hw_cfg->len != sizeof(u32) || !cfg->hw_cfg->payload) {
+ DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n",
+ sizeof(u32), cfg->hw_cfg->len, cfg->hw_cfg->payload);
+ return -EINVAL;
+ }
+
+ count = (u32 *)(cfg->hw_cfg->payload);
+ hw_lm = cfg->hw_cfg->mixer_info;
+
+ if (hw_lm && !hw_lm->cfg.right_mixer &&
+ (*count < info[dspp->idx].frame_pushes))
+ (*count)++;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
index eacafe6..475f8d0 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c
@@ -1694,6 +1694,9 @@
set_bit(SDE_WB_XY_ROI_OFFSET, &wb->features);
+ if (sde_cfg->has_cwb_support)
+ set_bit(SDE_WB_HAS_CWB, &wb->features);
+
for (j = 0; j < sde_cfg->mdp_count; j++) {
sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off =
PROP_BITVALUE_ACCESS(prop_value,
@@ -3248,6 +3251,7 @@
} else if (IS_SDM845_TARGET(hw_rev)) {
/* update sdm845 target here */
sde_cfg->has_wb_ubwc = true;
+ sde_cfg->has_cwb_support = true;
sde_cfg->perf.min_prefill_lines = 24;
sde_cfg->vbif_qos_nlvl = 8;
sde_cfg->ts_prefill_rev = 2;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
index 963b48f..65919e9 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h
@@ -261,6 +261,7 @@
* @SDE_WB_QOS, Writeback supports QoS control, danger/safe/creq
* @SDE_WB_QOS_8LVL, Writeback supports 8-level QoS control
* @SDE_WB_CDP Writeback supports client driven prefetch
+ * @SDE_WB_HAS_CWB Writeback block supports concurrent writeback
* @SDE_WB_MAX maximum value
*/
enum {
@@ -279,6 +280,7 @@
SDE_WB_QOS,
SDE_WB_QOS_8LVL,
SDE_WB_CDP,
+ SDE_WB_HAS_CWB,
SDE_WB_MAX
};
@@ -922,6 +924,7 @@
* @has_src_split source split feature status
* @has_cdp Client driven prefetch feature status
* @has_wb_ubwc UBWC feature supported on WB
+ * @has_cwb_support indicates if device supports primary capture through CWB
* @ubwc_version UBWC feature version (0x0 for not supported)
* @has_sbuf indicate if stream buffer is available
* @sbuf_headroom stream buffer headroom in lines
@@ -959,6 +962,7 @@
bool has_cdp;
bool has_dim_layer;
bool has_wb_ubwc;
+ bool has_cwb_support;
u32 ubwc_version;
bool has_sbuf;
u32 sbuf_headroom;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index 303d96e..2146611 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -576,6 +576,23 @@
SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
}
+static void sde_hw_ctl_update_wb_cfg(struct sde_hw_ctl *ctx,
+ struct sde_hw_intf_cfg *cfg, bool enable) {
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+ u32 intf_cfg = 0;
+
+ if (!cfg->wb)
+ return;
+
+ intf_cfg = SDE_REG_READ(c, CTL_TOP);
+ if (enable)
+ intf_cfg |= (cfg->wb & 0x3) + 2;
+ else
+ intf_cfg &= ~((cfg->wb & 0x3) + 2);
+
+ SDE_REG_WRITE(c, CTL_TOP, intf_cfg);
+}
+
static inline u32 sde_hw_ctl_read_ctl_top(struct sde_hw_ctl *ctx)
{
struct sde_hw_blk_reg_map *c;
@@ -638,6 +655,7 @@
ops->read_ctl_top = sde_hw_ctl_read_ctl_top;
ops->read_ctl_layers = sde_hw_ctl_read_ctl_layers;
ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
+ ops->update_wb_cfg = sde_hw_ctl_update_wb_cfg;
ops->reset = sde_hw_ctl_reset_control;
ops->get_reset = sde_hw_ctl_get_reset_status;
ops->hard_reset = sde_hw_ctl_hard_reset;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 9eb31f1..75631dd8 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -150,6 +150,15 @@
void (*setup_intf_cfg)(struct sde_hw_ctl *ctx,
struct sde_hw_intf_cfg *cfg);
+ /**
+ * Update the interface selection with input WB config
+ * @ctx : ctl path ctx pointer
+ * @cfg : pointer to input wb config
+ * @enable : set if true, clear otherwise
+ */
+ void (*update_wb_cfg)(struct sde_hw_ctl *ctx,
+ struct sde_hw_intf_cfg *cfg, bool enable);
+
int (*reset)(struct sde_hw_ctl *c);
/**
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
index 4e677c2..97a3ea4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -179,7 +179,7 @@
u32 reset = BIT(16), val;
reset = ~reset;
- for (i = SDE_STAGE_0; i < sblk->maxblendstages; i++) {
+ for (i = SDE_STAGE_0; i <= sblk->maxblendstages; i++) {
stage_off = _stage_offset(ctx, i);
if (WARN_ON(stage_off < 0))
return;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
index 8022f23..9b4e03d 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h
@@ -570,7 +570,8 @@
/**
* struct sde_splash_data - Struct contains details of continuous splash
* memory region and initial pipeline configuration.
- * @smmu_handoff_pending:boolean to notify handoff from splash memory to smmu
+ * @resource_handoff_pending: boolean to notify boot up resource handoff
+ * is pending.
* @splash_base: Base address of continuous splash region reserved
* by bootloader
* @splash_size: Size of continuous splash region
@@ -585,7 +586,7 @@
* @single_flush_en: Stores if the single flush is enabled.
*/
struct sde_splash_data {
- bool smmu_handoff_pending;
+ bool resource_handoff_pending;
unsigned long splash_base;
u32 splash_size;
struct ctl_top top[CTL_MAX - CTL_0];
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c
index 8b89ebb..cf646bd 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c
@@ -376,6 +376,18 @@
SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
}
+static void sde_hw_program_cwb_ppb_ctrl(struct sde_hw_mdp *mdp,
+ bool dual, bool dspp_out)
+{
+ u32 value = dspp_out ? 0x4 : 0x0;
+
+ SDE_REG_WRITE(&mdp->hw, PPB2_CNTL, value);
+ if (dual) {
+ value |= 0x1;
+ SDE_REG_WRITE(&mdp->hw, PPB3_CNTL, value);
+ }
+}
+
static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
unsigned long cap)
{
@@ -385,6 +397,7 @@
ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
ops->get_danger_status = sde_hw_get_danger_status;
ops->setup_vsync_source = sde_hw_setup_vsync_source;
+ ops->set_cwb_ppb_cntl = sde_hw_program_cwb_ppb_ctrl;
ops->get_safe_status = sde_hw_get_safe_status;
ops->get_split_flush_status = sde_hw_get_split_flush;
ops->setup_dce = sde_hw_setup_dce;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h
index 950a62c..210ea53 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_top.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h
@@ -194,6 +194,15 @@
* @mdp: mdp top context driver
*/
void (*intf_audio_select)(struct sde_hw_mdp *mdp);
+
+ /**
+ * set_cwb_ppb_cntl - select the data point for CWB
+ * @mdp: mdp top context driver
+ * @dual: indicates if dual pipe line needs to be programmed
+ * @dspp_out : true if dspp output required. LM is default tap point
+ */
+ void (*set_cwb_ppb_cntl)(struct sde_hw_mdp *mdp,
+ bool dual, bool dspp_out);
};
struct sde_hw_mdp {
diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h
index cc020d9..a592223 100644
--- a/drivers/gpu/drm/msm/sde/sde_hwio.h
+++ b/drivers/gpu/drm/msm/sde/sde_hwio.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -40,6 +40,8 @@
#define PPB0_CONFIG 0x334
#define PPB1_CNTL 0x338
#define PPB1_CONFIG 0x33C
+#define PPB2_CNTL 0x370
+#define PPB3_CNTL 0x374
#define HW_EVENTS_CTL 0x37C
#define CLK_CTRL3 0x3A8
#define CLK_STATUS3 0x3AC
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 33bdec9..b0a52a7 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -936,9 +936,6 @@
}
}
- if (sde_kms->splash_data.smmu_handoff_pending)
- sde_kms->splash_data.smmu_handoff_pending = false;
-
/*
* NOTE: for secure use cases we want to apply the new HW
* configuration only after completing preparation for secure
@@ -972,6 +969,62 @@
}
}
+static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms,
+ struct drm_atomic_state *old_state)
+{
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ bool primary_crtc_active = false;
+ struct msm_drm_private *priv;
+ int i, rc = 0;
+
+ priv = sde_kms->dev->dev_private;
+
+ if (!sde_kms->splash_data.resource_handoff_pending)
+ return;
+
+ SDE_EVT32(SDE_EVTLOG_FUNC_CASE1);
+ for_each_crtc_in_state(old_state, crtc, crtc_state, i) {
+ if (crtc->state->active)
+ primary_crtc_active = true;
+ SDE_EVT32(crtc->base.id, crtc->state->active);
+ }
+
+ if (!primary_crtc_active) {
+ SDE_EVT32(SDE_EVTLOG_FUNC_CASE2);
+ return;
+ }
+
+ sde_kms->splash_data.resource_handoff_pending = false;
+
+ if (sde_kms->splash_data.cont_splash_en) {
+ SDE_DEBUG("disabling cont_splash feature\n");
+ sde_kms->splash_data.cont_splash_en = false;
+
+ for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
+ sde_power_data_bus_set_quota(&priv->phandle,
+ sde_kms->core_client,
+ SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, i,
+ SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
+ SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA);
+
+ sde_power_resource_enable(&priv->phandle, sde_kms->core_client,
+ false);
+ }
+
+ if (sde_kms->splash_data.splash_base) {
+ _sde_kms_splash_smmu_unmap(sde_kms);
+
+ rc = _sde_kms_release_splash_buffer(
+ sde_kms->splash_data.splash_base,
+ sde_kms->splash_data.splash_size);
+ if (rc)
+ pr_err("failed to release splash memory\n");
+ sde_kms->splash_data.splash_base = 0;
+ sde_kms->splash_data.splash_size = 0;
+ }
+}
+
static void sde_kms_complete_commit(struct msm_kms *kms,
struct drm_atomic_state *old_state)
{
@@ -1019,39 +1072,9 @@
sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false);
+ _sde_kms_release_splash_resource(sde_kms, old_state);
+
SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT);
-
- if (sde_kms->splash_data.cont_splash_en) {
- /* Releasing splash resources as we have first frame update */
- rc = _sde_kms_splash_smmu_unmap(sde_kms);
- SDE_DEBUG("Disabling cont_splash feature\n");
- sde_kms->splash_data.cont_splash_en = false;
-
- for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++)
- sde_power_data_bus_set_quota(&priv->phandle,
- sde_kms->core_client,
- SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, i,
- SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA,
- SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA);
-
- sde_power_resource_enable(&priv->phandle,
- sde_kms->core_client, false);
- SDE_DEBUG("removing Vote for MDP Resources\n");
- }
-
- /*
- * Even for continuous splash disabled cases we have to release
- * splash memory reservation back to system after first frame update.
- */
- if (sde_kms->splash_data.splash_base) {
- rc = _sde_kms_release_splash_buffer(
- sde_kms->splash_data.splash_base,
- sde_kms->splash_data.splash_size);
- if (rc)
- pr_err("Failed to release splash memory\n");
- sde_kms->splash_data.splash_base = 0;
- sde_kms->splash_data.splash_size = 0;
- }
}
static void sde_kms_wait_for_commit_done(struct msm_kms *kms,
@@ -2704,6 +2727,19 @@
return rc;
}
+static bool sde_kms_check_for_splash(struct msm_kms *kms)
+{
+ struct sde_kms *sde_kms;
+
+ if (!kms) {
+ SDE_ERROR("invalid kms\n");
+ return false;
+ }
+
+ sde_kms = to_sde_kms(kms);
+ return sde_kms->splash_data.cont_splash_en;
+}
+
static int sde_kms_pm_suspend(struct device *dev)
{
struct drm_device *ddev;
@@ -2904,6 +2940,7 @@
.register_events = _sde_kms_register_events,
.get_address_space = _sde_kms_get_address_space,
.postopen = _sde_kms_post_open,
+ .check_for_splash = sde_kms_check_for_splash,
};
/* the caller api needs to turn on clock before calling it */
@@ -2956,8 +2993,7 @@
* address. To facilitate this requirement we need to have a
* one to one mapping on SMMU until we have our first frame.
*/
- if ((i == MSM_SMMU_DOMAIN_UNSECURE) &&
- sde_kms->splash_data.smmu_handoff_pending) {
+ if (i == MSM_SMMU_DOMAIN_UNSECURE) {
ret = mmu->funcs->set_attribute(mmu,
DOMAIN_ATTR_EARLY_MAP,
&early_map);
@@ -2986,27 +3022,27 @@
}
aspace->domain_attached = true;
early_map = 0;
+
/* Mapping splash memory block */
if ((i == MSM_SMMU_DOMAIN_UNSECURE) &&
- sde_kms->splash_data.smmu_handoff_pending) {
+ sde_kms->splash_data.splash_base) {
ret = _sde_kms_splash_smmu_map(sde_kms->dev, mmu,
&sde_kms->splash_data);
if (ret) {
SDE_ERROR("failed to map ret:%d\n", ret);
goto fail;
}
- /*
- * Turning off early map after generating one to one
- * mapping for splash address space.
- */
- ret = mmu->funcs->set_attribute(mmu,
- DOMAIN_ATTR_EARLY_MAP,
- &early_map);
- if (ret) {
- SDE_ERROR("failed to set map att ret:%d\n",
- ret);
- goto early_map_fail;
- }
+ }
+
+ /*
+ * Turning off early map after generating one to one
+ * mapping for splash address space.
+ */
+ ret = mmu->funcs->set_attribute(mmu, DOMAIN_ATTR_EARLY_MAP,
+ &early_map);
+ if (ret) {
+ SDE_ERROR("failed to set map att ret:%d\n", ret);
+ goto early_map_fail;
}
}
@@ -3285,12 +3321,7 @@
&sde_kms->splash_data,
sde_kms->catalog);
- /*
- * SMMU handoff is necessary for continuous splash enabled
- * scenario.
- */
- if (sde_kms->splash_data.cont_splash_en)
- sde_kms->splash_data.smmu_handoff_pending = true;
+ sde_kms->splash_data.resource_handoff_pending = true;
/* Initialize reg dma block which is a singleton */
rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog,
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index 505dee0db..ca91651 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -195,7 +195,7 @@
size_t size = PAGE_SIZE * n;
loff_t off = mmap_offset(obj) +
(entry->obj_pgoff << PAGE_SHIFT);
- const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+ const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
if (m > 1) {
int i;
@@ -442,7 +442,7 @@
* into account in some of the math, so figure out virtual stride
* in pages
*/
- const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+ const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE);
/* We don't use vmf->pgoff since that has the fake offset: */
pgoff = ((unsigned long)vmf->virtual_address -
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 41b72ce..83e1345 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -238,9 +238,10 @@
* may be slow
* See https://bugs.freedesktop.org/show_bug.cgi?id=88758
*/
-
+#ifndef CONFIG_COMPILE_TEST
#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
thanks to write-combining
+#endif
if (bo->flags & RADEON_GEM_GTT_WC)
DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index 574ab00..b82ef5e 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -5969,9 +5969,9 @@
{
u32 lane_width;
u32 new_lane_width =
- (radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+ ((radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
u32 current_lane_width =
- (radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT;
+ ((radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
if (new_lane_width != current_lane_width) {
radeon_set_pcie_lanes(rdev, new_lane_width);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 6e3c4ac..32d87c6 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -1386,6 +1386,9 @@
usleep_range(10, 20);
reset_control_deassert(ahb_rst);
+ VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1);
+ VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0);
+
memcpy(vop->regsbak, vop->regs, vop->len);
for (i = 0; i < vop_data->table_size; i++)
@@ -1541,17 +1544,9 @@
mutex_init(&vop->vsync_mutex);
- ret = devm_request_irq(dev, vop->irq, vop_isr,
- IRQF_SHARED, dev_name(dev), vop);
- if (ret)
- return ret;
-
- /* IRQ is initially disabled; it gets enabled in power_on */
- disable_irq(vop->irq);
-
ret = vop_create_crtc(vop);
if (ret)
- goto err_enable_irq;
+ return ret;
pm_runtime_enable(&pdev->dev);
@@ -1561,13 +1556,19 @@
goto err_disable_pm_runtime;
}
+ ret = devm_request_irq(dev, vop->irq, vop_isr,
+ IRQF_SHARED, dev_name(dev), vop);
+ if (ret)
+ goto err_disable_pm_runtime;
+
+ /* IRQ is initially disabled; it gets enabled in power_on */
+ disable_irq(vop->irq);
+
return 0;
err_disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
vop_destroy_crtc(vop);
-err_enable_irq:
- enable_irq(vop->irq); /* To balance out the disable_irq above */
return ret;
}
diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c
index 9e77fc0..aad2f4a 100644
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -212,6 +212,11 @@
.unbind = sun4i_drv_unbind,
};
+static bool sun4i_drv_node_is_connector(struct device_node *node)
+{
+ return of_device_is_compatible(node, "hdmi-connector");
+}
+
static bool sun4i_drv_node_is_frontend(struct device_node *node)
{
return of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") ||
@@ -252,6 +257,13 @@
!of_device_is_available(node))
return 0;
+ /*
+ * The connectors will be the last nodes in our pipeline, we
+ * can just bail out.
+ */
+ if (sun4i_drv_node_is_connector(node))
+ return 0;
+
if (!sun4i_drv_node_is_frontend(node)) {
/* Add current component */
DRM_DEBUG_DRIVER("Adding component %s\n",
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index ab30169..b608cd4 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -110,8 +110,8 @@
&handle);
if (ret) {
- state->bo_count = i - 1;
- goto err;
+ state->bo_count = i;
+ goto err_delete_handle;
}
bo_state[i].handle = handle;
bo_state[i].paddr = vc4_bo->base.paddr;
@@ -123,13 +123,16 @@
state->bo_count * sizeof(*bo_state)))
ret = -EFAULT;
- kfree(bo_state);
+err_delete_handle:
+ if (ret) {
+ for (i = 0; i < state->bo_count; i++)
+ drm_gem_handle_delete(file_priv, bo_state[i].handle);
+ }
err_free:
-
vc4_free_hang_state(dev, kernel_state);
+ kfree(bo_state);
-err:
return ret;
}
diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h
index 44ecb0b..8e21958 100644
--- a/drivers/gpu/msm/adreno.h
+++ b/drivers/gpu/msm/adreno.h
@@ -1808,7 +1808,7 @@
return ret;
}
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val);
- if (val != *perfctr_pwr_hi) {
+ if (val > *perfctr_pwr_hi) {
*perfctr_pwr_hi = val;
ret = true;
}
@@ -1823,14 +1823,17 @@
unsigned int ret = 0;
bool overflow = true;
static unsigned int perfctr_pwr_hi;
+ unsigned int prev_perfctr_pwr_hi = 0;
/* Read the value */
kgsl_regread(device, reg, &val);
if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg
- (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO))
+ (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO)) {
+ prev_perfctr_pwr_hi = perfctr_pwr_hi;
overflow = is_power_counter_overflow(adreno_dev, reg,
*counter, &perfctr_pwr_hi);
+ }
/* Return 0 for the first read */
if (*counter != 0) {
@@ -1843,9 +1846,12 @@
* Since KGSL got abnormal value from the counter,
* We will drop the value from being accumulated.
*/
- pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n",
- val, *counter, reg);
- return 0;
+ KGSL_DRV_ERR_RATELIMIT(device,
+ "Abnormal value:0x%llx (0x%llx) from perf counter : 0x%x\n",
+ val | ((uint64_t)perfctr_pwr_hi << 32),
+ *counter |
+ ((uint64_t)prev_perfctr_pwr_hi << 32),
+ reg);
}
}
diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c
index b8c282d..a634d98 100644
--- a/drivers/gpu/msm/adreno_dispatch.c
+++ b/drivers/gpu/msm/adreno_dispatch.c
@@ -208,8 +208,8 @@
if (!kgsl_state_is_awake(KGSL_DEVICE(adreno_dev)))
goto ret;
- if (adreno_rb_empty(adreno_dev->cur_rb))
- goto ret;
+ if (!adreno_rb_empty(adreno_dev->cur_rb))
+ return false;
/* only check rbbm status to determine if GPU is idle */
adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS, ®_rbbm_status);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index 2e84bad..14653ea 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -110,27 +110,25 @@
id++, entry = idr_get_next(&priv->mem_idr, &id)) {
int egl_surface_count = 0, egl_image_count = 0;
- struct kgsl_memdesc *m;
+ struct kgsl_memdesc *m = &entry->memdesc;
- if (kgsl_mem_entry_get(entry) == 0)
+ if ((kgsl_memdesc_usermem_type(m) != KGSL_MEM_ENTRY_ION) ||
+ entry->pending_free || (kgsl_mem_entry_get(entry) == 0))
continue;
spin_unlock(&priv->mem_lock);
- m = &entry->memdesc;
- if (kgsl_memdesc_usermem_type(m) == KGSL_MEM_ENTRY_ION) {
- kgsl_get_egl_counts(entry, &egl_surface_count,
- &egl_image_count);
+ kgsl_get_egl_counts(entry, &egl_surface_count,
+ &egl_image_count);
- if (kgsl_memdesc_get_memtype(m) ==
- KGSL_MEMTYPE_EGL_SURFACE)
- imported_mem += m->size;
- else if (egl_surface_count == 0) {
- uint64_t size = m->size;
+ if (kgsl_memdesc_get_memtype(m) ==
+ KGSL_MEMTYPE_EGL_SURFACE)
+ imported_mem += m->size;
+ else if (egl_surface_count == 0) {
+ uint64_t size = m->size;
- do_div(size, (egl_image_count ?
- egl_image_count : 1));
- imported_mem += size;
- }
+ do_div(size, (egl_image_count ?
+ egl_image_count : 1));
+ imported_mem += size;
}
kgsl_mem_entry_put(entry);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index ac7d2c6..aea6267 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1370,7 +1370,7 @@
* of implement() working on 8 byte chunks
*/
- int len = hid_report_len(report) + 7;
+ u32 len = hid_report_len(report) + 7;
return kmalloc(len, flags);
}
@@ -1435,7 +1435,7 @@
{
char *buf;
int ret;
- int len;
+ u32 len;
buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf)
@@ -1461,14 +1461,14 @@
}
EXPORT_SYMBOL_GPL(__hid_request);
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
int interrupt)
{
struct hid_report_enum *report_enum = hid->report_enum + type;
struct hid_report *report;
struct hid_driver *hdrv;
unsigned int a;
- int rsize, csize = size;
+ u32 rsize, csize = size;
u8 *cdata = data;
int ret = 0;
@@ -1526,7 +1526,7 @@
*
* This is data entry for lower layers.
*/
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt)
{
struct hid_report_enum *report_enum;
struct hid_driver *hdrv;
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 40233315..5ff6dd8 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -1279,7 +1279,8 @@
led_work);
struct hid_field *field;
struct hid_report *report;
- int len, ret;
+ int ret;
+ u32 len;
__u8 *buf;
field = hidinput_get_led_field(hid);
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 89e9032..fba655d 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -315,7 +315,8 @@
static void mt_get_feature(struct hid_device *hdev, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hdev);
- int ret, size = hid_report_len(report);
+ int ret;
+ u32 size = hid_report_len(report);
u8 *buf;
/*
@@ -919,7 +920,7 @@
struct hid_report_enum *re;
struct mt_class *cls = &td->mtclass;
char *buf;
- int report_len;
+ u32 report_len;
if (td->inputmode < 0)
return;
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index be89bcb..276d12d 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -110,8 +110,8 @@
u8 *writeReport;
u8 *readReport;
- int input_report_size;
- int output_report_size;
+ u32 input_report_size;
+ u32 output_report_size;
unsigned long flags;
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index b0bb99a..1b1dccd 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -1056,7 +1056,6 @@
u8 battery_charging;
u8 battery_capacity;
u8 led_state[MAX_LEDS];
- u8 resume_led_state[MAX_LEDS];
u8 led_delay_on[MAX_LEDS];
u8 led_delay_off[MAX_LEDS];
u8 led_count;
@@ -1793,6 +1792,7 @@
led->name = name;
led->brightness = sc->led_state[n];
led->max_brightness = max_brightness[n];
+ led->flags = LED_CORE_SUSPENDRESUME;
led->brightness_get = sony_led_get_brightness;
led->brightness_set = sony_led_set_brightness;
@@ -2509,47 +2509,32 @@
static int sony_suspend(struct hid_device *hdev, pm_message_t message)
{
- /*
- * On suspend save the current LED state,
- * stop running force-feedback and blank the LEDS.
- */
- if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) {
+#ifdef CONFIG_SONY_FF
+
+ /* On suspend stop any running force-feedback events */
+ if (SONY_FF_SUPPORT) {
struct sony_sc *sc = hid_get_drvdata(hdev);
-#ifdef CONFIG_SONY_FF
sc->left = sc->right = 0;
-#endif
-
- memcpy(sc->resume_led_state, sc->led_state,
- sizeof(sc->resume_led_state));
- memset(sc->led_state, 0, sizeof(sc->led_state));
-
sony_send_output_report(sc);
}
+#endif
return 0;
}
static int sony_resume(struct hid_device *hdev)
{
- /* Restore the state of controller LEDs on resume */
- if (SONY_LED_SUPPORT) {
- struct sony_sc *sc = hid_get_drvdata(hdev);
+ struct sony_sc *sc = hid_get_drvdata(hdev);
- memcpy(sc->led_state, sc->resume_led_state,
- sizeof(sc->led_state));
-
- /*
- * The Sixaxis and navigation controllers on USB need to be
- * reinitialized on resume or they won't behave properly.
- */
- if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
- (sc->quirks & NAVIGATION_CONTROLLER_USB)) {
- sixaxis_set_operational_usb(sc->hdev);
- sc->defer_initialization = 1;
- }
-
- sony_set_leds(sc);
+ /*
+ * The Sixaxis and navigation controllers on USB need to be
+ * reinitialized on resume or they won't behave properly.
+ */
+ if ((sc->quirks & SIXAXIS_CONTROLLER_USB) ||
+ (sc->quirks & NAVIGATION_CONTROLLER_USB)) {
+ sixaxis_set_operational_usb(sc->hdev);
+ sc->defer_initialization = 1;
}
return 0;
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index f0e2757..216f033 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -192,6 +192,11 @@
int ret = 0, len;
unsigned char report_number;
+ if (!hidraw_table[minor] || !hidraw_table[minor]->exist) {
+ ret = -ENODEV;
+ goto out;
+ }
+
dev = hidraw_table[minor]->hid;
if (!dev->ll_driver->raw_request) {
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 865e7c2..2548c5d 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -142,10 +142,10 @@
* register of the HID
* descriptor. */
unsigned int bufsize; /* i2c buffer size */
- char *inbuf; /* Input buffer */
- char *rawbuf; /* Raw Input buffer */
- char *cmdbuf; /* Command buffer */
- char *argsbuf; /* Command arguments buffer */
+ u8 *inbuf; /* Input buffer */
+ u8 *rawbuf; /* Raw Input buffer */
+ u8 *cmdbuf; /* Command buffer */
+ u8 *argsbuf; /* Command arguments buffer */
unsigned long flags; /* device flags */
unsigned long quirks; /* Various quirks */
@@ -451,7 +451,8 @@
static void i2c_hid_get_input(struct i2c_hid *ihid)
{
- int ret, ret_size;
+ int ret;
+ u32 ret_size;
int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
if (size > ihid->bufsize)
@@ -476,7 +477,7 @@
return;
}
- if (ret_size > size) {
+ if ((ret_size > size) || (ret_size <= 2)) {
dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
__func__, size, ret_size);
return;
@@ -968,6 +969,15 @@
return ret < 0 && ret != -ENXIO ? ret : 0;
}
+static void i2c_hid_acpi_fix_up_power(struct device *dev)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+ struct acpi_device *adev;
+
+ if (handle && acpi_bus_get_device(handle, &adev) == 0)
+ acpi_device_fix_up_power(adev);
+}
+
static const struct acpi_device_id i2c_hid_acpi_match[] = {
{"ACPI0C50", 0 },
{"PNP0C50", 0 },
@@ -980,6 +990,8 @@
{
return -ENODEV;
}
+
+static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {}
#endif
#ifdef CONFIG_OF
@@ -1082,6 +1094,8 @@
if (ret < 0)
goto err;
+ i2c_hid_acpi_fix_up_power(&client->dev);
+
pm_runtime_get_noresume(&client->dev);
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 7a4d39c..e8b90b5 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -351,7 +351,7 @@
u8 *rep_data;
struct hid_report *r;
struct hid_report_enum *re;
- int length;
+ u32 length;
int error = -ENOMEM, limit = 0;
if (wacom_wac->mode_report < 0)
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index d8bc4b9..9360cdc 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -70,7 +70,7 @@
/* PCIE */
{ .dev_type = HV_PCIE,
HV_PCIE_GUID,
- .perf_device = true,
+ .perf_device = false,
},
/* Synthetic Frame Buffer */
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index b24f1d3..ac63e56 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -94,18 +94,20 @@
struct ina2xx_config {
u16 config_default;
- int calibration_factor;
+ int calibration_value;
int registers;
int shunt_div;
int bus_voltage_shift;
int bus_voltage_lsb; /* uV */
- int power_lsb; /* uW */
+ int power_lsb_factor;
};
struct ina2xx_data {
const struct ina2xx_config *config;
long rshunt;
+ long current_lsb_uA;
+ long power_lsb_uW;
struct mutex config_lock;
struct regmap *regmap;
@@ -115,21 +117,21 @@
static const struct ina2xx_config ina2xx_config[] = {
[ina219] = {
.config_default = INA219_CONFIG_DEFAULT,
- .calibration_factor = 40960000,
+ .calibration_value = 4096,
.registers = INA219_REGISTERS,
.shunt_div = 100,
.bus_voltage_shift = 3,
.bus_voltage_lsb = 4000,
- .power_lsb = 20000,
+ .power_lsb_factor = 20,
},
[ina226] = {
.config_default = INA226_CONFIG_DEFAULT,
- .calibration_factor = 5120000,
+ .calibration_value = 2048,
.registers = INA226_REGISTERS,
.shunt_div = 400,
.bus_voltage_shift = 0,
.bus_voltage_lsb = 1250,
- .power_lsb = 25000,
+ .power_lsb_factor = 25,
},
};
@@ -168,12 +170,16 @@
return INA226_SHIFT_AVG(avg_bits);
}
+/*
+ * Calibration register is set to the best value, which eliminates
+ * truncation errors on calculating current register in hardware.
+ * According to datasheet (eq. 3) the best values are 2048 for
+ * ina226 and 4096 for ina219. They are hardcoded as calibration_value.
+ */
static int ina2xx_calibrate(struct ina2xx_data *data)
{
- u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
- data->rshunt);
-
- return regmap_write(data->regmap, INA2XX_CALIBRATION, val);
+ return regmap_write(data->regmap, INA2XX_CALIBRATION,
+ data->config->calibration_value);
}
/*
@@ -186,10 +192,6 @@
if (ret < 0)
return ret;
- /*
- * Set current LSB to 1mA, shunt is in uOhms
- * (equation 13 in datasheet).
- */
return ina2xx_calibrate(data);
}
@@ -267,15 +269,15 @@
val = DIV_ROUND_CLOSEST(val, 1000);
break;
case INA2XX_POWER:
- val = regval * data->config->power_lsb;
+ val = regval * data->power_lsb_uW;
break;
case INA2XX_CURRENT:
- /* signed register, LSB=1mA (selected), in mA */
- val = (s16)regval;
+ /* signed register, result in mA */
+ val = regval * data->current_lsb_uA;
+ val = DIV_ROUND_CLOSEST(val, 1000);
break;
case INA2XX_CALIBRATION:
- val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
- regval);
+ val = regval;
break;
default:
/* programmer goofed */
@@ -303,9 +305,32 @@
ina2xx_get_value(data, attr->index, regval));
}
-static ssize_t ina2xx_set_shunt(struct device *dev,
- struct device_attribute *da,
- const char *buf, size_t count)
+/*
+ * In order to keep calibration register value fixed, the product
+ * of current_lsb and shunt_resistor should also be fixed and equal
+ * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order
+ * to keep the scale.
+ */
+static int ina2xx_set_shunt(struct ina2xx_data *data, long val)
+{
+ unsigned int dividend = DIV_ROUND_CLOSEST(1000000000,
+ data->config->shunt_div);
+ if (val <= 0 || val > dividend)
+ return -EINVAL;
+
+ mutex_lock(&data->config_lock);
+ data->rshunt = val;
+ data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val);
+ data->power_lsb_uW = data->config->power_lsb_factor *
+ data->current_lsb_uA;
+ mutex_unlock(&data->config_lock);
+
+ return 0;
+}
+
+static ssize_t ina2xx_store_shunt(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
{
unsigned long val;
int status;
@@ -315,18 +340,9 @@
if (status < 0)
return status;
- if (val == 0 ||
- /* Values greater than the calibration factor make no sense. */
- val > data->config->calibration_factor)
- return -EINVAL;
-
- mutex_lock(&data->config_lock);
- data->rshunt = val;
- status = ina2xx_calibrate(data);
- mutex_unlock(&data->config_lock);
+ status = ina2xx_set_shunt(data, val);
if (status < 0)
return status;
-
return count;
}
@@ -386,7 +402,7 @@
/* shunt resistance */
static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
- ina2xx_show_value, ina2xx_set_shunt,
+ ina2xx_show_value, ina2xx_store_shunt,
INA2XX_CALIBRATION);
/* update interval (ina226 only) */
@@ -431,6 +447,7 @@
/* set the device type */
data->config = &ina2xx_config[id->driver_data];
+ mutex_init(&data->config_lock);
if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) {
struct ina2xx_platform_data *pdata = dev_get_platdata(dev);
@@ -441,10 +458,7 @@
val = INA2XX_RSHUNT_DEFAULT;
}
- if (val <= 0 || val > data->config->calibration_factor)
- return -ENODEV;
-
- data->rshunt = val;
+ ina2xx_set_shunt(data, val);
ina2xx_regmap_config.max_register = data->config->registers;
@@ -460,8 +474,6 @@
return -ENODEV;
}
- mutex_init(&data->config_lock);
-
data->groups[group++] = &ina2xx_group;
if (id->driver_data == ina226)
data->groups[group++] = &ina226_group;
diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c
index f57ad2e..3bbcc95 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2012, 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2012, 2016, 2018, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Program Flow Trace driver
*
@@ -39,6 +39,7 @@
#include "coresight-etm.h"
#include "coresight-etm-perf.h"
+#include "coresight-priv.h"
/*
* Not really modular but using module_param is the easiest way to
@@ -711,6 +712,10 @@
CS_UNLOCK(drvdata->base);
+ /* check the state of the fuse */
+ if (!coresight_authstatus_enabled(drvdata->base))
+ goto out;
+
/* First dummy read */
(void)etm_readl(drvdata, ETMPDSR);
/* Provide power to ETM: ETMPDCR[3] == 1 */
@@ -742,6 +747,7 @@
etm_set_pwrdwn(drvdata);
etm_clr_pwrup(drvdata);
+out:
CS_LOCK(drvdata->base);
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c
index a4bf109..5db74f0 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014, 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
@@ -38,6 +38,7 @@
#include "coresight-etm4x.h"
#include "coresight-etm-perf.h"
+#include "coresight-priv.h"
static int boot_enable;
module_param_named(boot_enable, boot_enable, int, 0444);
@@ -436,6 +437,9 @@
CS_UNLOCK(drvdata->base);
+ if (!coresight_authstatus_enabled(drvdata->base))
+ goto out;
+
/* find all capabilities of the tracing unit */
etmidr0 = readl_relaxed(drvdata->base + TRCIDR0);
@@ -582,6 +586,8 @@
drvdata->nrseqstate = BMVAL(etmidr5, 25, 27);
/* NUMCNTR, bits[30:28] number of counters available for tracing */
drvdata->nr_cntr = BMVAL(etmidr5, 28, 30);
+
+out:
CS_LOCK(drvdata->base);
}
diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c
index 87d9162..287f901 100644
--- a/drivers/hwtracing/coresight/coresight-tmc.c
+++ b/drivers/hwtracing/coresight/coresight-tmc.c
@@ -733,6 +733,13 @@
ret = tmc_etr_bam_init(adev, drvdata);
if (ret)
goto out;
+ /*
+ * ETR configuration uses a 40-bit AXI master in place of
+ * the embedded SRAM of ETB/ETF.
+ */
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+ if (ret)
+ goto out;
} else {
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.ops = &tmc_etf_cs_ops;
diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c
index 1cf60f3..85a16b1 100644
--- a/drivers/hwtracing/coresight/coresight.c
+++ b/drivers/hwtracing/coresight/coresight.c
@@ -589,6 +589,9 @@
int ret = 0;
struct coresight_device *sink;
struct list_head *path;
+ enum coresight_dev_subtype_source subtype;
+
+ subtype = csdev->subtype.source_subtype;
mutex_lock(&coresight_mutex);
@@ -596,8 +599,16 @@
if (ret)
goto out;
- if (csdev->enable)
+ if (csdev->enable) {
+ /*
+ * There could be multiple applications driving the software
+ * source. So keep the refcount for each such user when the
+ * source is already enabled.
+ */
+ if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+ atomic_inc(csdev->refcnt);
goto out;
+ }
/*
* Search for a valid sink for this session but don't reset the
diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c
index c6a90b4..91b10af 100644
--- a/drivers/i2c/muxes/i2c-mux-reg.c
+++ b/drivers/i2c/muxes/i2c-mux-reg.c
@@ -196,20 +196,25 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mux->data.reg_size = resource_size(res);
mux->data.reg = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mux->data.reg))
- return PTR_ERR(mux->data.reg);
+ if (IS_ERR(mux->data.reg)) {
+ ret = PTR_ERR(mux->data.reg);
+ goto err_put_parent;
+ }
}
if (mux->data.reg_size != 4 && mux->data.reg_size != 2 &&
mux->data.reg_size != 1) {
dev_err(&pdev->dev, "Invalid register size\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_put_parent;
}
muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0,
i2c_mux_reg_select, NULL);
- if (!muxc)
- return -ENOMEM;
+ if (!muxc) {
+ ret = -ENOMEM;
+ goto err_put_parent;
+ }
muxc->priv = mux;
platform_set_drvdata(pdev, muxc);
@@ -235,6 +240,8 @@
add_adapter_failed:
i2c_mux_del_adapters(muxc);
+err_put_parent:
+ i2c_put_adapter(parent);
return ret;
}
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index 678e8c7..fec696e 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -121,10 +121,21 @@
enum iio_event_direction dir, int state)
{
struct hi8435_priv *priv = iio_priv(idev);
+ int ret;
+ u32 tmp;
- priv->event_scan_mask &= ~BIT(chan->channel);
- if (state)
+ if (state) {
+ ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
+ if (ret < 0)
+ return ret;
+ if (tmp & BIT(chan->channel))
+ priv->event_prev_val |= BIT(chan->channel);
+ else
+ priv->event_prev_val &= ~BIT(chan->channel);
+
priv->event_scan_mask |= BIT(chan->channel);
+ } else
+ priv->event_scan_mask &= ~BIT(chan->channel);
return 0;
}
@@ -442,13 +453,15 @@
priv->spi = spi;
reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
- if (IS_ERR(reset_gpio)) {
- /* chip s/w reset if h/w reset failed */
+ if (!IS_ERR(reset_gpio)) {
+ /* need >=100ns low pulse to reset chip */
+ gpiod_set_raw_value_cansleep(reset_gpio, 0);
+ udelay(1);
+ gpiod_set_raw_value_cansleep(reset_gpio, 1);
+ } else {
+ /* s/w reset chip if h/w reset is not available */
hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
hi8435_writeb(priv, HI8435_CTRL_REG, 0);
- } else {
- udelay(5);
- gpiod_set_value(reset_gpio, 1);
}
spi_set_drvdata(spi, idev);
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 1f1ad41..0a8b763 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -39,6 +39,7 @@
be called kmx61.
source "drivers/iio/imu/inv_mpu6050/Kconfig"
+source "drivers/iio/imu/inv_icm20602/Kconfig"
endmenu
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index c71bcd3..fab6a5e 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -15,5 +15,6 @@
obj-y += bmi160/
obj-y += inv_mpu6050/
+obj-y += inv_icm20602/
obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/inv_icm20602/Kconfig b/drivers/iio/imu/inv_icm20602/Kconfig
new file mode 100644
index 0000000..fa88689
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/Kconfig
@@ -0,0 +1,14 @@
+#
+# inv-icm20602 drivers for Invensense MPU devices and combos
+#
+config INV_ICM20602_IIO
+ tristate "Invensense ICM20602 devices"
+ depends on I2C && SYSFS
+ select IIO_BUFFER
+ select IIO_BUFFER_CB
+ select IIO_TRIGGERED_BUFFER
+ help
+ This driver supports the Invensense ICM20602 devices.
+ It is a gyroscope/accelerometer combo device.
+ This driver can be built as a module. The module will be called
+ inv-icm20602.
diff --git a/drivers/iio/imu/inv_icm20602/Makefile b/drivers/iio/imu/inv_icm20602/Makefile
new file mode 100644
index 0000000..d60c10a
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for Invensense icm20602 device.
+#
+
+obj-$(CONFIG_INV_ICM20602_IIO) += inv-icm20602.o
+inv-icm20602-objs := inv_icm20602_core.o inv_icm20602_ring.o inv_icm20602_trigger.o inv_icm20602_bsp.o
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c
new file mode 100644
index 0000000..bfff285
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c
@@ -0,0 +1,932 @@
+/*
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <linux/i2c.h>
+#include <linux/spi/spi.h>
+#include "inv_icm20602_bsp.h"
+#include "inv_icm20602_iio.h"
+
+#define icm20602_init_reg_addr(head, tail, reg_map) { \
+ enum inv_icm20602_reg_addr i;\
+ for (i = head; i <= tail; i++) {\
+ reg_map->address = i;\
+ reg_map->reg_u.reg = 0x0;\
+ reg_map++;\
+ } \
+}
+
+#define icm20602_write_reg_simple(st, register) \
+ icm20602_write_reg(st, \
+ register.address, \
+ register.reg_u.reg)
+
+static struct inv_icm20602_reg_map reg_set_20602;
+
+int icm20602_init_reg_map(void)
+{
+ struct struct_XG_OFFS_TC_H *reg_map = &(reg_set_20602.XG_OFFS_TC_H);
+
+ icm20602_init_reg_addr(ADDR_XG_OFFS_TC_H,
+ ADDR_XG_OFFS_TC_L, reg_map);
+
+ icm20602_init_reg_addr(ADDR_YG_OFFS_TC_H,
+ ADDR_YG_OFFS_TC_L, reg_map);
+
+ icm20602_init_reg_addr(ADDR_ZG_OFFS_TC_H,
+ ADDR_ZG_OFFS_TC_L, reg_map);
+
+ icm20602_init_reg_addr(ADDR_SELF_TEST_X_ACCEL,
+ ADDR_SELF_TEST_Z_ACCEL, reg_map);
+
+ icm20602_init_reg_addr(ADDR_XG_OFFS_USRH,
+ ADDR_LP_MODE_CFG, reg_map);
+
+ icm20602_init_reg_addr(ADDR_ACCEL_WOM_X_THR,
+ ADDR_FIFO_EN, reg_map);
+
+ icm20602_init_reg_addr(ADDR_FSYNC_INT,
+ ADDR_GYRO_ZOUT_L, reg_map);
+
+ icm20602_init_reg_addr(ADDR_SELF_TEST_X_GYRO,
+ ADDR_SELF_TEST_Z_GYRO, reg_map);
+
+ icm20602_init_reg_addr(ADDR_FIFO_WM_TH1,
+ ADDR_FIFO_WM_TH2, reg_map);
+
+ icm20602_init_reg_addr(ADDR_SIGNAL_PATH_RESET,
+ ADDR_PWR_MGMT_2, reg_map);
+
+ icm20602_init_reg_addr(ADDR_I2C_IF,
+ ADDR_I2C_IF, reg_map);
+
+ icm20602_init_reg_addr(ADDR_FIFO_COUNTH,
+ ADDR_XA_OFFSET_L, reg_map);
+
+ icm20602_init_reg_addr(ADDR_YA_OFFSET_H,
+ ADDR_YA_OFFSET_L, reg_map);
+
+ icm20602_init_reg_addr(ADDR_ZA_OFFSET_H,
+ ADDR_ZA_OFFSET_L, reg_map);
+
+ return MPU_SUCCESS;
+}
+
+#define W_FLG 0
+#define R_FLG 1
+int icm20602_bulk_read(struct inv_icm20602_state *st,
+ int reg, char *buf, int size)
+{
+ int result = MPU_SUCCESS;
+ char tx_buf[2] = {0x0, 0x0};
+ int tmp_size = size;
+ int tmp_buf = buf;
+ struct i2c_msg msg[2];
+
+ if (!st || !buf)
+ return -MPU_FAIL;
+
+ if (st->interface == ICM20602_SPI) {
+ tx_buf[0] = ICM20602_READ_REG(reg);
+ result = spi_write_then_read(st->spi, &tx_buf[0],
+ 1, tmp_buf, size);
+ if (result) {
+ pr_err("mpu read reg %u failed, rc %d\n",
+ reg, result);
+ result = -MPU_READ_FAIL;
+ }
+ } else {
+ result = size;
+ while (tmp_size > 0) {
+#ifdef ICM20602_I2C_SMBUS
+ result += i2c_smbus_read_i2c_block_data(st->client,
+ reg, (tmp_size < 32)?tmp_size:32, tmp_buf);
+ tmp_size -= 32;
+ tmp_buf += tmp_size;
+#else
+ tx_buf[0] = reg;
+ msg[0].addr = st->client->addr;
+ msg[0].flags = W_FLG;
+ msg[0].len = 1;
+ msg[0].buf = tx_buf;
+
+ msg[1].addr = st->client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = (tmp_size < 32)?tmp_size:32;
+ msg[1].buf = tmp_buf;
+ i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg));
+ tmp_size -= 32;
+ tmp_buf += tmp_size;
+#endif
+ }
+ }
+
+ return result;
+}
+
+static int icm20602_write_reg(struct inv_icm20602_state *st,
+ uint8_t reg, uint8_t val)
+{
+ int result = MPU_SUCCESS;
+ char txbuf[2] = {0x0, 0x0};
+ struct i2c_msg msg[1];
+
+ if (st->interface == ICM20602_SPI) {
+ txbuf[0] = ICM20602_WRITE_REG(reg);
+ txbuf[1] = val;
+ result = spi_write_then_read(st->spi, &txbuf[0], 2, NULL, 0);
+ if (result) {
+ pr_err("mpu write reg %u failed, rc %d\n",
+ reg, val);
+ result = -MPU_READ_FAIL;
+ }
+ } else if (st->interface == ICM20602_I2C) {
+#ifdef ICM20602_I2C_SMBUS
+ result = i2c_smbus_write_i2c_block_data(st->client,
+ reg, 1, &val);
+#else
+ txbuf[0] = reg;
+ txbuf[1] = val;
+ msg[0].addr = st->client->addr;
+ msg[0].flags = I2C_M_IGNORE_NAK;
+ msg[0].len = 2;
+ msg[0].buf = txbuf;
+
+ i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg));
+#endif
+ }
+
+ return result;
+}
+
+static int icm20602_read_reg(struct inv_icm20602_state *st,
+ uint8_t reg, uint8_t *val)
+{
+ int result = MPU_SUCCESS;
+ char txbuf[1] = {0x0};
+ char rxbuf[1] = {0x0};
+ struct i2c_msg msg[2];
+
+ if (st->interface == ICM20602_SPI) {
+ txbuf[0] = ICM20602_READ_REG(reg);
+ result = spi_write_then_read(st->spi,
+ &txbuf[0], 1, rxbuf, 1);
+ if (result) {
+ pr_err("mpu read reg %u failed, rc %d\n",
+ reg, result);
+ result = -MPU_READ_FAIL;
+ }
+ } else if (st->interface == ICM20602_I2C) {
+#ifdef ICM20602_I2C_SMBUS
+ result = i2c_smbus_read_i2c_block_data(st->client,
+ reg, 1, rxbuf);
+ if (result != 1) {
+ pr_err("mpu read reg %u failed, rc %d\n",
+ reg, result);
+ result = -MPU_READ_FAIL;
+ }
+#else
+ txbuf[0] = reg;
+ msg[0].addr = st->client->addr;
+ msg[0].flags = W_FLG;
+ msg[0].len = 1;
+ msg[0].buf = txbuf;
+
+ msg[1].addr = st->client->addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].len = 1;
+ msg[1].buf = rxbuf;
+
+ i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg));
+#endif
+ }
+ *val = rxbuf[0];
+
+ return result;
+}
+
+#define combine_8_to_16(upper, lower) ((upper << 8) | lower)
+
+int icm20602_read_raw(struct inv_icm20602_state *st,
+ struct struct_icm20602_real_data *real_data, uint32_t type)
+{
+ struct struct_icm20602_raw_data raw_data;
+
+ if (type & ACCEL != 0) {
+ icm20602_read_reg(st,
+ reg_set_20602.ACCEL_XOUT_H.address,
+ &raw_data.ACCEL_XOUT_H);
+ icm20602_read_reg(st,
+ reg_set_20602.ACCEL_XOUT_L.address,
+ &raw_data.ACCEL_XOUT_L);
+ real_data->ACCEL_XOUT =
+ combine_8_to_16(raw_data.ACCEL_XOUT_H,
+ raw_data.ACCEL_XOUT_L);
+
+ icm20602_read_reg(st,
+ reg_set_20602.ACCEL_YOUT_H.address,
+ &raw_data.ACCEL_YOUT_H);
+ icm20602_read_reg(st,
+ reg_set_20602.ACCEL_YOUT_L.address,
+ &raw_data.ACCEL_YOUT_L);
+ real_data->ACCEL_YOUT =
+ combine_8_to_16(raw_data.ACCEL_YOUT_H,
+ raw_data.ACCEL_YOUT_L);
+
+ icm20602_read_reg(st,
+ reg_set_20602.ACCEL_ZOUT_H.address,
+ &raw_data.ACCEL_ZOUT_H);
+ icm20602_read_reg(st,
+ reg_set_20602.ACCEL_ZOUT_L.address,
+ &raw_data.ACCEL_ZOUT_L);
+ real_data->ACCEL_ZOUT =
+ combine_8_to_16(raw_data.ACCEL_ZOUT_H,
+ raw_data.ACCEL_ZOUT_L);
+ }
+
+ if (type & GYRO != 0) {
+ icm20602_read_reg(st,
+ reg_set_20602.GYRO_XOUT_H.address,
+ &raw_data.GYRO_XOUT_H);
+ icm20602_read_reg(st,
+ reg_set_20602.GYRO_XOUT_L.address,
+ &raw_data.GYRO_XOUT_L);
+ real_data->GYRO_XOUT =
+ combine_8_to_16(raw_data.GYRO_XOUT_H,
+ raw_data.GYRO_XOUT_L);
+
+ icm20602_read_reg(st,
+ reg_set_20602.GYRO_YOUT_H.address,
+ &raw_data.GYRO_YOUT_H);
+ icm20602_read_reg(st,
+ reg_set_20602.GYRO_YOUT_L.address,
+ &raw_data.GYRO_YOUT_L);
+ real_data->GYRO_YOUT =
+ combine_8_to_16(raw_data.GYRO_YOUT_H,
+ raw_data.GYRO_YOUT_L);
+
+ icm20602_read_reg(st,
+ reg_set_20602.GYRO_ZOUT_H.address,
+ &raw_data.GYRO_ZOUT_H);
+ icm20602_read_reg(st,
+ reg_set_20602.GYRO_ZOUT_L.address,
+ &raw_data.GYRO_ZOUT_L);
+ real_data->GYRO_ZOUT =
+ combine_8_to_16(raw_data.GYRO_ZOUT_H,
+ raw_data.GYRO_ZOUT_L);
+ }
+
+ return MPU_SUCCESS;
+}
+
+int icm20602_read_fifo(struct inv_icm20602_state *st,
+ void *buf, const int size)
+{
+ return icm20602_bulk_read(st,
+ reg_set_20602.FIFO_R_W.address, buf, size);
+}
+
+int icm20602_start_fifo(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = NULL;
+
+ config = st->config;
+
+ /* enable fifo */
+ if (config->fifo_enabled) {
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x1;
+ if (icm20602_write_reg_simple(st,
+ reg_set_20602.USER_CTRL)) {
+ pr_err("icm20602 start fifo failed\n");
+ return -MPU_FAIL;
+ }
+
+ /* enable interrupt, need to test */
+ reg_set_20602.INT_ENABLE.reg_u.REG.FIFO_OFLOW_EN = 0x1;
+ reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0;
+ if (icm20602_write_reg_simple(st,
+ reg_set_20602.INT_ENABLE)) {
+ pr_err("icm20602 set FIFO_OFLOW_EN failed\n");
+ return -MPU_FAIL;
+ }
+ }
+
+ return MPU_SUCCESS;
+}
+
+static int icm20602_stop_fifo(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = NULL;
+
+ config = st->config;
+ /* disable fifo */
+ if (config->fifo_enabled) {
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x0;
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1;
+ if (icm20602_write_reg_simple(st,
+ reg_set_20602.USER_CTRL)) {
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+ pr_err("icm20602 stop fifo failed\n");
+ return -MPU_FAIL;
+ }
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+ }
+
+ return MPU_SUCCESS;
+}
+
+static int icm20602_config_waterlevel(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = NULL;
+ uint8_t val = 0;
+
+ config = st->config;
+ if (config->fifo_enabled != true)
+ return MPU_SUCCESS;
+ /* config waterlevel as the fps need */
+ config->fifo_waterlevel = (config->user_fps_in_ms /
+ (1000 / config->gyro_accel_sample_rate))
+ *ICM20602_PACKAGE_SIZE;
+
+ if (config->fifo_waterlevel > 1023 ||
+ config->fifo_waterlevel/50 >
+ (1023-config->fifo_waterlevel)/ICM20602_PACKAGE_SIZE) {
+ pr_err("set fifo_waterlevel failed %d\n",
+ config->fifo_waterlevel);
+ return MPU_FAIL;
+ }
+ reg_set_20602.FIFO_WM_TH1.reg_u.reg =
+ (config->fifo_waterlevel & 0xff00) >> 8;
+ reg_set_20602.FIFO_WM_TH2.reg_u.reg =
+ (config->fifo_waterlevel & 0x00ff);
+
+ icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH1);
+ icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH2);
+ icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH1.address, &val);
+ icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH2.address, &val);
+
+ return MPU_SUCCESS;
+}
+
+static int icm20602_read_ST_code(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = NULL;
+ int result = 0;
+
+ config = st->config;
+ result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_ACCEL.address,
+ &(config->acc_self_test.X));
+ result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_ACCEL.address,
+ &(config->acc_self_test.Y));
+ result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_ACCEL.address,
+ &(config->acc_self_test.Z));
+
+ result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_GYRO.address,
+ &(config->gyro_self_test.X));
+ result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_GYRO.address,
+ &(config->gyro_self_test.Y));
+ result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_GYRO.address,
+ &(config->gyro_self_test.Z));
+
+ return result;
+}
+
+static int icm20602_set_self_test(struct inv_icm20602_state *st)
+{
+ uint8_t raw_data[6] = {0, 0, 0, 0, 0, 0};
+ uint8_t selfTest[6];
+ float factory_trim[6];
+ int result = 0;
+ int ii;
+
+ reg_set_20602.SMPLRT_DIV.reg_u.REG.SMPLRT_DIV = 0;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV);
+
+ reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = INV_ICM20602_GYRO_LFP_92HZ;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG);
+
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0;
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = ICM20602_GYRO_FSR_250DPS;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG);
+
+ reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = ICM20602_ACCLFP_99;
+ reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0X0;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG2);
+
+ reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = ICM20602_ACC_FSR_2G;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG);
+
+ //icm20602_read_ST_code(st);
+
+ return 0;
+}
+
+static int icm20602_do_test_acc(struct inv_icm20602_state *st,
+ struct X_Y_Z *acc, struct X_Y_Z *acc_st)
+{
+ struct struct_icm20602_real_data *real_data =
+ kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC);
+ struct icm20602_user_config *config = st->config;
+ int i, j;
+
+ for (i = 0; i < SELFTEST_COUNT; i++) {
+ icm20602_read_raw(st, real_data, ACCEL);
+ acc->X += real_data->ACCEL_XOUT;
+ acc->Y += real_data->ACCEL_YOUT;
+ acc->Z += real_data->ACCEL_ZOUT;
+ usleep_range(1000, 1001);
+ }
+ acc->X /= SELFTEST_COUNT;
+ acc->X *= ST_PRECISION;
+
+ acc->Y /= SELFTEST_COUNT;
+ acc->Y *= ST_PRECISION;
+
+ acc->Z /= SELFTEST_COUNT;
+ acc->Z *= ST_PRECISION;
+
+ reg_set_20602.ACCEL_CONFIG.reg_u.REG.XG_ST = 0x1;
+ reg_set_20602.ACCEL_CONFIG.reg_u.REG.YG_ST = 0x1;
+ reg_set_20602.ACCEL_CONFIG.reg_u.REG.ZG_ST = 0x1;
+ icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG);
+
+ for (i = 0; i < SELFTEST_COUNT; i++) {
+ icm20602_read_raw(st, real_data, ACCEL);
+ acc_st->X += real_data->ACCEL_XOUT;
+ acc_st->Y += real_data->ACCEL_YOUT;
+ acc_st->Z += real_data->ACCEL_ZOUT;
+ usleep_range(1000, 1001);
+ }
+ acc_st->X /= SELFTEST_COUNT;
+ acc_st->X *= ST_PRECISION;
+
+ acc_st->Y /= SELFTEST_COUNT;
+ acc_st->Y *= ST_PRECISION;
+
+ acc_st->Z /= SELFTEST_COUNT;
+ acc_st->Z *= ST_PRECISION;
+
+ return MPU_SUCCESS;
+}
+
+static int icm20602_do_test_gyro(struct inv_icm20602_state *st,
+ struct X_Y_Z *gyro, struct X_Y_Z *gyro_st)
+{
+ struct struct_icm20602_real_data *real_data =
+ kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC);
+ int i, j;
+
+ for (i = 0; i < SELFTEST_COUNT; i++) {
+ icm20602_read_raw(st, real_data, GYRO);
+ gyro->X += real_data->GYRO_XOUT;
+ gyro->Y += real_data->GYRO_YOUT;
+ gyro->Z += real_data->GYRO_ZOUT;
+ usleep_range(1000, 1001);
+ }
+ gyro->X /= SELFTEST_COUNT;
+ gyro->X *= ST_PRECISION;
+
+ gyro->Y /= SELFTEST_COUNT;
+ gyro->Y *= ST_PRECISION;
+
+ gyro->Z /= SELFTEST_COUNT;
+ gyro->Z *= ST_PRECISION;
+
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.XG_ST = 0x1;
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.YG_ST = 0x1;
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.ZG_ST = 0x1;
+ icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG);
+
+ for (i = 0; i < SELFTEST_COUNT; i++) {
+ icm20602_read_raw(st, real_data, ACCEL);
+ gyro_st->X += real_data->GYRO_XOUT;
+ gyro_st->Y += real_data->GYRO_YOUT;
+ gyro_st->Z += real_data->GYRO_ZOUT;
+ usleep_range(1000, 1001);
+ }
+ gyro_st->X /= SELFTEST_COUNT;
+ gyro_st->X *= ST_PRECISION;
+
+ gyro_st->Y /= SELFTEST_COUNT;
+ gyro_st->Y *= ST_PRECISION;
+
+ gyro_st->Z /= SELFTEST_COUNT;
+ gyro_st->Z *= ST_PRECISION;
+
+ return MPU_SUCCESS;
+}
+
+static bool icm20602_check_acc_selftest(struct inv_icm20602_state *st,
+ struct X_Y_Z *acc, struct X_Y_Z *acc_st)
+{
+ struct X_Y_Z acc_ST_code, st_otp, st_shift_cust;
+ bool otp_value_zero = false, test_result = true;
+
+ acc_ST_code.X = st->config->acc_self_test.X;
+ acc_ST_code.Y = st->config->acc_self_test.Y;
+ acc_ST_code.Z = st->config->acc_self_test.Z;
+
+ st_otp.X = (st_otp.X != 0) ? mpu_st_tb[acc_ST_code.X - 1] : 0;
+ st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[acc_ST_code.Y - 1] : 0;
+ st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[acc_ST_code.Z - 1] : 0;
+
+ if (st_otp.X & st_otp.Y & st_otp.Z == 0)
+ otp_value_zero = true;
+
+ st_shift_cust.X = acc_st->X - acc->X;
+ st_shift_cust.Y = acc_st->X - acc->Y;
+ st_shift_cust.Z = acc_st->X - acc->Z;
+ if (!otp_value_zero) {
+ if (
+ st_shift_cust.X <
+ (st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) ||
+ st_shift_cust.Y <
+ (st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) ||
+ st_shift_cust.Z <
+ (st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) ||
+
+ st_shift_cust.X >
+ (st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) ||
+ st_shift_cust.Y >
+ (st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) ||
+ st_shift_cust.Z >
+ (st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MAX / 100)
+ ) {
+ test_result = false;
+ }
+ } else {
+ if (
+ abs(st_shift_cust.X) <
+ (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) ||
+ abs(st_shift_cust.Y) <
+ (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) ||
+ abs(st_shift_cust.Z) <
+ (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) ||
+
+ abs(st_shift_cust.X) >
+ (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) ||
+ abs(st_shift_cust.Y) >
+ (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) ||
+ abs(st_shift_cust.Z) >
+ (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION)
+ ) {
+ test_result = false;
+ }
+ }
+
+ return test_result;
+}
+
+static int icm20602_check_gyro_selftest(struct inv_icm20602_state *st,
+ struct X_Y_Z *gyro, struct X_Y_Z *gyro_st)
+{
+ struct X_Y_Z gyro_ST_code, st_otp, st_shift_cust;
+ bool otp_value_zero = false, test_result = true;
+
+ gyro_ST_code.X = st->config->gyro_self_test.X;
+ gyro_ST_code.Y = st->config->gyro_self_test.Y;
+ gyro_ST_code.Z = st->config->gyro_self_test.Z;
+
+ st_otp.X = (st_otp.X != 0) ? mpu_st_tb[gyro_ST_code.X - 1] : 0;
+ st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0;
+ st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0;
+
+ if (st_otp.X & st_otp.Y & st_otp.Z == 0)
+ otp_value_zero = true;
+
+ st_shift_cust.X = gyro_st->X - gyro->X;
+ st_shift_cust.Y = gyro_st->X - gyro->Y;
+ st_shift_cust.Z = gyro_st->X - gyro->Z;
+ if (!otp_value_zero) {
+ if (
+ st_shift_cust.X <
+ (st_otp.X * ST_PRECISION * GYRO_ST_SHIFT / 100) ||
+ st_shift_cust.Y <
+ (st_otp.Y * ST_PRECISION * GYRO_ST_SHIFT / 100) ||
+ st_shift_cust.Z <
+ (st_otp.Z * ST_PRECISION * GYRO_ST_SHIFT / 100)
+ ) {
+ test_result = false;
+ }
+ } else {
+ if (
+ abs(st_shift_cust.X) <
+ (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) ||
+ abs(st_shift_cust.Y) <
+ (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) ||
+ abs(st_shift_cust.Z) <
+ (GYRO_ST_AL * 32768 / 250 * ST_PRECISION)
+ ) {
+ test_result = false;
+ }
+ }
+
+ if (test_result == true) {
+ /* Self Test Pass/Fail Criteria C */
+ if (
+ abs(st_shift_cust.X) >
+ GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION ||
+ abs(st_shift_cust.Y) >
+ GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION ||
+ abs(st_shift_cust.Z) >
+ GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION
+ ) {
+ test_result = false;
+ }
+ }
+
+ return test_result;
+}
+
+bool icm20602_self_test(struct inv_icm20602_state *st)
+{
+ struct X_Y_Z acc, acc_st;
+ struct X_Y_Z gyro, gyro_st;
+ bool test_result = true;
+
+ icm20602_set_self_test(st);
+ icm20602_do_test_acc(st, &acc, &acc_st);
+ icm20602_do_test_gyro(st, &gyro, &gyro_st);
+ test_result = icm20602_check_acc_selftest(st, &acc, &acc_st);
+ test_result = icm20602_check_gyro_selftest(st, &gyro, &gyro_st);
+
+ return test_result;
+}
+
+static int icm20602_config_fifo(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = NULL;
+
+ config = st->config;
+ if (config->fifo_enabled != true)
+ return MPU_SUCCESS;
+
+ /*
+ * Set CONFIG.USER_SET_BIT = 0, No reason as datasheet said
+ */
+ reg_set_20602.CONFIG.reg_u.REG.USER_SET_BIT = 0x0;
+ /*
+ * Set CONFIG.FIFO_MODE = 1,
+ * i.e. when FIFO is full, additional writes will
+ * not be written to FIFO
+ */
+ reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1;
+ if (icm20602_write_reg_simple(st, reg_set_20602.CONFIG))
+ return -MPU_FAIL;
+
+ /* reset fifo */
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1;
+ if (icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL)) {
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+ return -MPU_FAIL;
+ }
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+
+ /* Enable FIFO on specified sensors */
+ reg_set_20602.FIFO_EN.reg_u.REG.GYRO_FIFO_EN = 0x1;
+ reg_set_20602.FIFO_EN.reg_u.REG.ACCEL_FIFO_EN = 0x1;
+ if (icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN))
+ return -MPU_FAIL;
+
+ if (icm20602_config_waterlevel(st))
+ return -MPU_FAIL;
+
+ if (icm20602_start_fifo(st))
+ return -MPU_FAIL;
+
+ return MPU_SUCCESS;
+}
+
+static int icm20602_initialize_gyro(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = NULL;
+ int result = MPU_SUCCESS;
+ int sample_rate;
+ uint8_t fchoice_b;
+
+ if (st == NULL)
+ return -MPU_FAIL;
+
+ /*
+ * ICM20602 supports gyro sampling rate up to 32KHz
+ * when fchoice_b != 0x00
+ * In our driver, we supports up to 8KHz
+ * thus always set fchoice_b to 0x00;
+ */
+ config = st->config;
+ /*
+ * SAPLRT_DIV in ICM20602_REG_SMPLRT_DIV is only used for 1kHz internal
+ * sampling, i.e. fchoice_b in ICM20602_REG_GYRO_CONFIG is 00
+ * and 0 < dlpf_cfg in ICM20602_REG_CONFIG < 7
+ * SAMPLE_RATE=Internal_Sample_Rate / (1 + SMPLRT_DIV)
+ */
+ if (config->gyro_accel_sample_rate <= ICM20602_SAMPLE_RATE_1000HZ)
+ reg_set_20602.SMPLRT_DIV.reg_u.reg =
+ ICM20602_INTERNAL_SAMPLE_RATE_HZ /
+ config->gyro_accel_sample_rate - 1;
+
+ result = icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV);
+
+ /* Set gyro&temperature(combine) LPF */
+ reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = config->gyro_lpf;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG);
+
+ /* Set gyro full scale range */
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0;
+ reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = config->gyro_fsr;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG);
+
+ /* Set Accel full scale range */
+ reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = config->acc_fsr;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG);
+
+ /*
+ * Set accel LPF
+ * Support accel sample rate up to 1KHz
+ * thus set accel_fchoice_b to 0x00
+ * The actual accel sample rate is 1KHz/(1+SMPLRT_DIV)
+ */
+ reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0x0;
+ reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = config->acc_lpf;
+ result |= icm20602_write_reg_simple(st,
+ reg_set_20602.ACCEL_CONFIG2);
+
+ if (result) {
+ pr_err("icm20602 init gyro and accel failed\n");
+ return -MPU_FAIL;
+ }
+
+ return result;
+}
+
+int icm20602_set_power_itg(struct inv_icm20602_state *st, bool power_on)
+{
+ int result = MPU_SUCCESS;
+
+ if (power_on) {
+ reg_set_20602.PWR_MGMT_1.reg_u.reg = 0;
+ result = icm20602_write_reg_simple(st,
+ reg_set_20602.PWR_MGMT_1);
+ } else {
+ reg_set_20602.PWR_MGMT_1.reg_u.REG.SLEEP = 0x1;
+ result = icm20602_write_reg_simple(st,
+ reg_set_20602.PWR_MGMT_1);
+ }
+ if (result) {
+ pr_err("set power failed power %d err %d\n",
+ power_on, result);
+ return result;
+ }
+
+ if (power_on)
+ msleep(30);
+
+ return result;
+}
+
+int icm20602_init_device(struct inv_icm20602_state *st)
+{
+ int result = MPU_SUCCESS;
+ struct icm20602_user_config *config = NULL;
+ int package_count;
+
+ config = st->config;
+ if (st == NULL || st->config == NULL) {
+ pr_err("icm20602 validate config failed\n");
+ return -MPU_FAIL;
+ }
+
+ /* turn on gyro and accel */
+ reg_set_20602.PWR_MGMT_2.reg_u.reg = 0x0;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2);
+ msleep(30);
+
+ /* disable INT */
+ reg_set_20602.INT_ENABLE.reg_u.reg = 0x0;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.INT_ENABLE);
+
+ /* disbale FIFO */
+ reg_set_20602.FIFO_EN.reg_u.reg = 0x0;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN);
+
+ /* reset FIFO */
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1;
+ result |= icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL);
+ reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0;
+ msleep(30);
+
+ /* init gyro and accel */
+ if (icm20602_initialize_gyro(st)) {
+ pr_err("icm20602 init device failed\n");
+ return -MPU_FAIL;
+ }
+
+ /* if FIFO enable, config FIFO */
+ if (config->fifo_enabled) {
+ if (icm20602_config_fifo(st)) {
+ pr_err("icm20602 init config fifo failed\n");
+ return -MPU_FAIL;
+ }
+ } else {
+ /* enable interrupt */
+ reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0;
+ if (icm20602_write_reg_simple(st,
+ reg_set_20602.INT_ENABLE)) {
+ pr_err("icm20602 set raw rdy failed\n");
+ return -MPU_FAIL;
+ }
+ }
+
+ /* buffer malloc */
+ package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE;
+
+ st->buf = kzalloc(sizeof(config->fifo_waterlevel * 2), GFP_ATOMIC);
+ if (!st->buf)
+ return -ENOMEM;
+
+ st->data_push = kcalloc(package_count,
+ sizeof(struct struct_icm20602_data), GFP_ATOMIC);
+ if (!st->data_push)
+ return -ENOMEM;
+
+ return result;
+}
+
+void icm20602_rw_test(struct inv_icm20602_state *st)
+{
+ uint8_t val = 0;
+
+ reg_set_20602.PWR_MGMT_2.reg_u.REG.STBY_ZG = 0x1;
+ icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2);
+ reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1;
+ icm20602_write_reg_simple(st, reg_set_20602.CONFIG);
+
+ icm20602_read_reg(st, reg_set_20602.PWR_MGMT_2.address, &val);
+ icm20602_read_reg(st, reg_set_20602.CONFIG.address, &val);
+
+}
+
+int icm20602_detect(struct inv_icm20602_state *st)
+{
+ int result = MPU_SUCCESS;
+ uint8_t retry = 0, val = 0;
+ uint8_t usr_ctrl = 0;
+
+ pr_debug("icm20602_detect\n");
+ /* reset to make sure previous state are not there */
+ reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x1;
+ result = icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_1);
+ if (result) {
+ pr_err("mpu write reg 0x%x value 0x%x failed\n",
+ reg_set_20602.PWR_MGMT_1.reg_u.reg,
+ reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET);
+ return result;
+ }
+ reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x0;
+
+ /* the power up delay */
+ msleep(30);
+
+ /* out of sleep */
+ result = icm20602_set_power_itg(st, true);
+ if (result)
+ return result;
+ /* get who am i register */
+ while (retry < 10) {
+ /* get version (expecting 0x12 for the icm20602) */
+ icm20602_read_reg(st, reg_set_20602.WHO_AM_I.address, &val);
+ if (val == ICM20602_WHO_AM_I)
+ break;
+ retry++;
+ }
+
+ if (val != ICM20602_WHO_AM_I) {
+ pr_err("detect mpu failed,whoami reg 0x%x\n", val);
+ result = -MPU_FAIL;
+ } else {
+ pr_debug("detect mpu ok,whoami reg 0x%x\n", val);
+ }
+ icm20602_rw_test(st);
+
+ return result;
+}
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h
new file mode 100644
index 0000000..9c4dbd0
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h
@@ -0,0 +1,978 @@
+/*
+ * 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.
+ */
+
+/* register high bit=1 for read */
+#define ICM20602_READ_REG(reg) (reg | 0x80)
+
+/* register high bit=0 for write */
+#define ICM20602_WRITE_REG(reg) (reg & (~0x80))
+#define ICM20602_WHO_AM_I 0x12
+#define ICM20602_INTERNAL_SAMPLE_RATE_HZ 1000
+
+#define SELFTEST_COUNT 200
+#define ST_PRECISION 1000
+#define ACC_ST_SHIFT_MAX 150
+#define ACC_ST_SHIFT_MIN 50
+#define ACC_ST_AL_MIN 225
+#define ACC_ST_AL_MAX 675
+#define GYRO_ST_SHIFT 50
+#define GYRO_ST_AL 60
+#define GYRO_OFFSET_MAX 20
+
+static const uint16_t mpu_st_tb[256] = {
+ 2620, 2646, 2672, 2699, 2726, 2753, 2781, 2808,
+ 2837, 2865, 2894, 2923, 2952, 2981, 3011, 3041,
+ 3072, 3102, 3133, 3165, 3196, 3228, 3261, 3293,
+ 3326, 3359, 3393, 3427, 3461, 3496, 3531, 3566,
+ 3602, 3638, 3674, 3711, 3748, 3786, 3823, 3862,
+ 3900, 3939, 3979, 4019, 4059, 4099, 4140, 4182,
+ 4224, 4266, 4308, 4352, 4395, 4439, 4483, 4528,
+ 4574, 4619, 4665, 4712, 4759, 4807, 4855, 4903,
+ 4953, 5002, 5052, 5103, 5154, 5205, 5257, 5310,
+ 5363, 5417, 5471, 5525, 5581, 5636, 5693, 5750,
+ 5807, 5865, 5924, 5983, 6043, 6104, 6165, 6226,
+ 6289, 6351, 6415, 6479, 6544, 6609, 6675, 6742,
+ 6810, 6878, 6946, 7016, 7086, 7157, 7229, 7301,
+ 7374, 7448, 7522, 7597, 7673, 7750, 7828, 7906,
+ 7985, 8065, 8145, 8227, 8309, 8392, 8476, 8561,
+ 8647, 8733, 8820, 8909, 8998, 9088, 9178, 9270,
+ 9363, 9457, 9551, 9647, 9743, 9841, 9939, 10038,
+ 10139, 10240, 10343, 10446, 10550, 10656, 10763, 10870,
+ 10979, 11089, 11200, 11312, 11425, 11539, 11654, 11771,
+ 11889, 12008, 12128, 12249, 12371, 12495, 12620, 12746,
+ 12874, 13002, 13132, 13264, 13396, 13530, 13666, 13802,
+ 13940, 14080, 14221, 14363, 14506, 14652, 14798, 14946,
+ 15096, 15247, 15399, 15553, 15709, 15866, 16024, 16184,
+ 16346, 16510, 16675, 16842, 17010, 17180, 17352, 17526,
+ 17701, 17878, 18057, 18237, 18420, 18604, 18790, 18978,
+ 19167, 19359, 19553, 19748, 19946, 20145, 20347, 20550,
+ 20756, 20963, 21173, 21385, 21598, 21814, 22033, 22253,
+ 22475, 22700, 22927, 23156, 23388, 23622, 23858, 24097,
+ 24338, 24581, 24827, 25075, 25326, 25579, 25835, 26093,
+ 26354, 26618, 26884, 27153, 27424, 27699, 27976, 28255,
+ 28538, 28823, 29112, 29403, 29697, 29994, 30294, 30597,
+ 30903, 31212, 31524, 31839, 32157, 32479, 32804
+};
+
+enum inv_icm20602_reg_addr {
+ ADDR_XG_OFFS_TC_H = 0x04,
+ ADDR_XG_OFFS_TC_L,
+ ADDR_YG_OFFS_TC_H = 0x07,
+ ADDR_YG_OFFS_TC_L,
+ ADDR_ZG_OFFS_TC_H = 0x0A,
+ ADDR_ZG_OFFS_TC_L,
+
+ ADDR_SELF_TEST_X_ACCEL = 0x0D,
+ ADDR_SELF_TEST_Y_ACCEL,
+ ADDR_SELF_TEST_Z_ACCEL,
+
+ ADDR_XG_OFFS_USRH = 0x13,
+ ADDR_XG_OFFS_USRL,
+ ADDR_YG_OFFS_USRH,
+ ADDR_YG_OFFS_USRL,
+ ADDR_ZG_OFFS_USRH,
+ ADDR_ZG_OFFS_USRL,
+
+ ADDR_SMPLRT_DIV,
+ ADDR_CONFIG,
+
+ ADDR_GYRO_CONFIG,
+
+ ADDR_ACCEL_CONFIG,
+ ADDR_ACCEL_CONFIG2,
+
+ ADDR_LP_MODE_CFG,
+
+ ADDR_ACCEL_WOM_X_THR = 0x20,
+ ADDR_ACCEL_WOM_Y_THR,
+ ADDR_ACCEL_WOM_Z_THR,
+ ADDR_FIFO_EN,
+
+ ADDR_FSYNC_INT = 0x36,
+ ADDR_INT_PIN_CFG,
+ ADDR_INT_ENABLE,
+ ADDR_FIFO_WM_INT_STATUS,
+ ADDR_INT_STATUS,
+
+ ADDR_ACCEL_XOUT_H,
+ ADDR_ACCEL_XOUT_L,
+ ADDR_ACCEL_YOUT_H,
+ ADDR_ACCEL_YOUT_L,
+ ADDR_ACCEL_ZOUT_H,
+ ADDR_ACCEL_ZOUT_L,
+
+ ADDR_TEMP_OUT_H,
+ ADDR_TEMP_OUT_L,
+
+ ADDR_GYRO_XOUT_H,
+ ADDR_GYRO_XOUT_L,
+ ADDR_GYRO_YOUT_H,
+ ADDR_GYRO_YOUT_L,
+ ADDR_GYRO_ZOUT_H,
+ ADDR_GYRO_ZOUT_L,
+
+ ADDR_SELF_TEST_X_GYRO = 0x50,
+ ADDR_SELF_TEST_Y_GYRO,
+ ADDR_SELF_TEST_Z_GYRO,
+
+ ADDR_FIFO_WM_TH1 = 0x60,
+ ADDR_FIFO_WM_TH2,
+
+ ADDR_SIGNAL_PATH_RESET = 0x68,
+ ADDR_ACCEL_INTEL_CTRL,
+ ADDR_USER_CTRL,
+
+ ADDR_PWR_MGMT_1,
+ ADDR_PWR_MGMT_2,
+
+ ADDR_I2C_IF = 0x70,
+
+ ADDR_FIFO_COUNTH = 0x72,
+ ADDR_FIFO_COUNTL,
+ ADDR_FIFO_R_W,
+
+ ADDR_WHO_AM_I,
+
+ ADDR_XA_OFFSET_H,
+ ADDR_XA_OFFSET_L,
+ ADDR_YA_OFFSET_H = 0x7A,
+ ADDR_YA_OFFSET_L,
+ ADDR_ZA_OFFSET_H = 0x7D,
+ ADDR_ZA_OFFSET_L
+};
+
+struct struct_XG_OFFS_TC_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 REG_XG_OFFS_TC_H :2;
+ u8 REG_XG_OFFS_LP :6;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_XG_OFFS_TC_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 REG_XG_OFFS_TC_L :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_YG_OFFS_TC_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 REG_YG_OFFS_TC_H :2;
+ u8 REG_YG_OFFS_LP :6;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_YG_OFFS_TC_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 REG_YG_OFFS_TC_L :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ZG_OFFS_TC_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 REG_ZG_OFFS_TC_H :2;
+ u8 REG_ZG_OFFS_LP :6;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ZG_OFFS_TC_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 REG_ZG_OFFS_TC_L :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SELF_TEST_X_ACCEL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 XA_ST_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SELF_TEST_Y_ACCEL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 YA_ST_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SELF_TEST_Z_ACCEL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ZA_ST_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_XG_OFFS_USRH {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 X_OFFS_USR :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_XG_OFFS_USRL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 X_OFFS_USR :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_YG_OFFS_USRH {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 Y_OFFS_USR :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_YG_OFFS_USRL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 Y_OFFS_USR :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ZG_OFFS_USRH {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 Z_OFFS_USR :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ZG_OFFS_USRL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 Z_OFFS_USR :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SMPLRT_DIV {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 SMPLRT_DIV :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_CONFIG {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 DLFP_CFG :3;
+ u8 EXT_SYNC_SET :3;
+ u8 FIFO_MODE :1;
+ u8 USER_SET_BIT :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_CONFIG {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 FCHOICE_B :2;
+ u8 RESERVE0 :1;
+ u8 FS_SEL :2;
+ u8 ZG_ST :1;
+ u8 YG_ST :1;
+ u8 XG_ST :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_CONFIG {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE0 :3;
+ u8 ACCEL_FS_SEL :2;
+ u8 ZG_ST :1;
+ u8 YG_ST :1;
+ u8 XG_ST :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_CONFIG2 {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 A_DLPF_CFG :3;
+ u8 ACCEL_FCHOICE_B :1;
+ u8 DEC2_CFG :2;
+ u8 RESERVE0 :2;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_LP_MODE_CFG {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE0 :4;
+ u8 G_AVGCFG :3;
+ u8 GYRO_CYCLE :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_WOM_X_THR {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 WOM_X_TH :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+
+struct struct_ACCEL_WOM_Y_THR {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 WOM_Y_TH :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_WOM_Z_THR {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 WOM_Z_TH :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_EN {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE1 :3;
+ u8 ACCEL_FIFO_EN :1;
+ u8 GYRO_FIFO_EN :1;
+ u8 RESERVE0 :3;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FSYNC_INT {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE0 :7;
+ u8 FSYNC_INT :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_INT_PIN_CFG {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE0 :2;
+ u8 FSYNC_INT_MODE_EN:1;
+ u8 FSYNC_INT_LEVEL :1;
+ u8 INT_RD_CLEAR :1;
+ u8 LATCH_INT_EN :1;
+ u8 INT_OPEN :1;
+ u8 INT_LEVEL :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_INT_ENABLE {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 DATA_RDY_INT_EN :1;
+ u8 RESERVE0 :1;
+ u8 GDRIVE_INT_EN :1;
+ u8 FSYNC_INT_EN :1;
+ u8 FIFO_OFLOW_EN :1;
+ u8 WOM_Z_INT_EN :1;
+ u8 WOM_Y_INT_EN :1;
+ u8 WOM_X_INT_EN :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_WM_INT_STATUS {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE1 :6;
+ u8 FIFO_WM_INT :1;
+ u8 RESERVE0 :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_INT_STATUS {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 DATA_RDY_INT :1;
+ u8 RESERVE1 :1;
+ u8 GDRIVE_INT :1;
+ u8 RESERVE0 :1;
+ u8 FIFO_OFLOW_INT :1;
+ u8 WOM_Z_INT :1;
+ u8 WOM_Y_INT :1;
+ u8 WOM_X_INT :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_XOUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ACCEL_XOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_XOUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ACCEL_XOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_YOUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ACCEL_YOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_YOUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ACCEL_YOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_ZOUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ACCEL_ZOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_ZOUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ACCEL_ZOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_TEMP_OUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 TEMP_OUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_TEMP_OUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 TEMP_OUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_XOUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 GYRO_XOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_XOUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 GYRO_XOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_YOUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 GYRO_YOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_YOUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 GYRO_YOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_ZOUT_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 GYRO_ZOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_GYRO_ZOUT_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 GYRO_ZOUT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SELF_TEST_X_GYRO {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 XG_ST_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SELF_TEST_Y_GYRO {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 YG_ST_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SELF_TEST_Z_GYRO {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ZG_ST_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_WM_TH1 {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE0 :6;
+ u8 FIFO_WM_TH :2;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_WM_TH2 {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 FIFO_WM_TH :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_SIGNAL_PATH_RESET {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 TEMP_RST :1;
+ u8 ACCEL_RST :1;
+ u8 FIFO_WM_TH :6;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ACCEL_INTEL_CTRL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 WOM_TH_MODE :1;
+ u8 OUTPUT_LIMIT :1;
+ u8 RESERVE0 :4;
+ u8 ACCEL_INTEL_MODE :1;
+ u8 ACCEL_INTEL_EN :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_USER_CTRL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 SIG_COND_RST :1;
+ u8 RESERVE2 :1;
+ u8 FIFO_RST :1;
+ u8 RESERVE1 :3;
+ u8 FIFO_EN :1;
+ u8 RESERVE0 :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_PWR_MGMT_1 {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 CLKSEL :3;
+ u8 TEMP_DIS :1;
+ u8 GYRO_STANDBY :1;
+ u8 CYCLE :1;
+ u8 SLEEP :1;
+ u8 DEVICE_RESET :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_PWR_MGMT_2 {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 STBY_ZG :1;
+ u8 STBY_YG :1;
+ u8 STBY_XG :1;
+ u8 STBY_ZA :1;
+ u8 STBY_YA :1;
+ u8 STBY_XA :1;
+ u8 RESERVE0 :2;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_I2C_IF {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 RESERVE1 :6;
+ u8 I2C_IF_DIS :1;
+ u8 RESERVE0 :1;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_COUNTH {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 FIFO_COUNT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_COUNTL {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 FIFO_COUNT :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_FIFO_R_W {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 FIFO_DATA :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_WHO_AM_I {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 WHOAMI :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_XA_OFFSET_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 XA_OFFS :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_XA_OFFSET_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 XA_OFFS :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_YA_OFFSET_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 YA_OFFS :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_YA_OFFSET_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 YA_OFFS :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ZA_OFFSET_H {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ZA_OFFS :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+struct struct_ZA_OFFSET_L {
+ enum inv_icm20602_reg_addr address;
+ union {
+ struct {
+ u8 ZA_OFFS :8;
+ } REG;
+ u8 reg;
+ } reg_u;
+};
+
+/*
+ * struct inv_icm20602_reg_map - Notable registers.
+ * @sample_rate_div: Divider applied to gyro output rate.
+ * @lpf: Configures internal low pass filter.
+ * @user_ctrl: Enables/resets the FIFO.
+ * @fifo_en: Determines which data will appear in FIFO.
+ * @gyro_config: gyro config register.
+ * @accl_config: accel config register
+ * @fifo_count_h: Upper byte of FIFO count.
+ * @fifo_r_w: FIFO register.
+ * @raw_gyro: Address of first gyro register.
+ * @raw_accl: Address of first accel register.
+ * @temperature: temperature register
+ * @int_enable: Interrupt enable register.
+ * @pwr_mgmt_1: Controls chip's power state and clock source.
+ * @pwr_mgmt_2: Controls power state of individual sensors.
+ */
+struct inv_icm20602_reg_map {
+ struct struct_XG_OFFS_TC_H XG_OFFS_TC_H;
+ struct struct_XG_OFFS_TC_L XG_OFFS_TC_L;
+ struct struct_YG_OFFS_TC_H YG_OFFS_TC_H;
+ struct struct_YG_OFFS_TC_L YG_OFFS_TC_L;
+ struct struct_ZG_OFFS_TC_H ZG_OFFS_TC_H;
+ struct struct_ZG_OFFS_TC_L ZG_OFFS_TC_L;
+
+ struct struct_SELF_TEST_X_ACCEL SELF_TEST_X_ACCEL;
+ struct struct_SELF_TEST_Y_ACCEL SELF_TEST_Y_ACCEL;
+ struct struct_SELF_TEST_Z_ACCEL SELF_TEST_Z_ACCEL;
+
+ struct struct_XG_OFFS_USRH XG_OFFS_USRH;
+ struct struct_XG_OFFS_USRL XG_OFFS_USRL;
+ struct struct_YG_OFFS_USRH YG_OFFS_USRH;
+ struct struct_YG_OFFS_USRL YG_OFFS_USRL;
+ struct struct_ZG_OFFS_USRH ZG_OFFS_USRH;
+ struct struct_ZG_OFFS_USRL ZG_OFFS_USRL;
+
+ struct struct_SMPLRT_DIV SMPLRT_DIV;
+ struct struct_CONFIG CONFIG;
+
+ struct struct_GYRO_CONFIG GYRO_CONFIG;
+
+ struct struct_ACCEL_CONFIG ACCEL_CONFIG;
+ struct struct_ACCEL_CONFIG2 ACCEL_CONFIG2;
+
+ struct struct_LP_MODE_CFG LP_MODE_CFG;
+
+ struct struct_ACCEL_WOM_X_THR ACCEL_WOM_X_THR;
+ struct struct_ACCEL_WOM_Y_THR ACCEL_WOM_Y_THR;
+ struct struct_ACCEL_WOM_Z_THR ACCEL_WOM_Z_THR;
+
+ struct struct_FIFO_EN FIFO_EN;
+ struct struct_FSYNC_INT FSYNC_INT;
+ struct struct_INT_PIN_CFG INT_PIN_CFG;
+ struct struct_INT_ENABLE INT_ENABLE;
+ struct struct_FIFO_WM_INT_STATUS FIFO_WM_INT_STATUS;
+ struct struct_INT_STATUS INT_STATUS;
+
+ struct struct_ACCEL_XOUT_H ACCEL_XOUT_H;
+ struct struct_ACCEL_XOUT_L ACCEL_XOUT_L;
+ struct struct_ACCEL_YOUT_H ACCEL_YOUT_H;
+ struct struct_ACCEL_YOUT_L ACCEL_YOUT_L;
+ struct struct_ACCEL_ZOUT_H ACCEL_ZOUT_H;
+ struct struct_ACCEL_ZOUT_L ACCEL_ZOUT_L;
+
+ struct struct_TEMP_OUT_H TEMP_OUT_H;
+ struct struct_TEMP_OUT_L TEMP_OUT_L;
+
+ struct struct_GYRO_XOUT_H GYRO_XOUT_H;
+ struct struct_GYRO_XOUT_L GYRO_XOUT_L;
+ struct struct_GYRO_YOUT_H GYRO_YOUT_H;
+ struct struct_GYRO_YOUT_L GYRO_YOUT_L;
+ struct struct_GYRO_ZOUT_H GYRO_ZOUT_H;
+ struct struct_GYRO_ZOUT_L GYRO_ZOUT_L;
+
+ struct struct_SELF_TEST_X_GYRO SELF_TEST_X_GYRO;
+ struct struct_SELF_TEST_Y_GYRO SELF_TEST_Y_GYRO;
+ struct struct_SELF_TEST_Z_GYRO SELF_TEST_Z_GYRO;
+ struct struct_FIFO_WM_TH1 FIFO_WM_TH1;
+ struct struct_FIFO_WM_TH2 FIFO_WM_TH2;
+ struct struct_SIGNAL_PATH_RESET SIGNAL_PATH_RESET;
+ struct struct_ACCEL_INTEL_CTRL ACCEL_INTEL_CTRL;
+ struct struct_USER_CTRL USER_CTRL;
+
+ struct struct_PWR_MGMT_1 PWR_MGMT_1;
+ struct struct_PWR_MGMT_2 PWR_MGMT_2;
+
+ struct struct_I2C_IF I2C_IF;
+
+ struct struct_FIFO_COUNTH FIFO_COUNTH;
+ struct struct_FIFO_COUNTL FIFO_COUNTL;
+ struct struct_FIFO_R_W FIFO_R_W;
+
+ struct struct_WHO_AM_I WHO_AM_I;
+
+ struct struct_XA_OFFSET_H XA_OFFSET_H;
+ struct struct_XA_OFFSET_L XA_OFFSET_L;
+ struct struct_YA_OFFSET_H YA_OFFSET_H;
+ struct struct_YA_OFFSET_L YA_OFFSET_L;
+ struct struct_ZA_OFFSET_H ZA_OFFSET_H;
+ struct struct_ZA_OFFSET_L ZA_OFFSET_L;
+};
+
+
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c
new file mode 100644
index 0000000..0f7fc92
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include "inv_icm20602_iio.h"
+
+/* Attribute of icm20602 device init show */
+static ssize_t inv_icm20602_init_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static void inv_icm20602_def_config(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = st->config;
+
+ config->user_fps_in_ms = 10;
+ config->gyro_lpf = INV_ICM20602_GYRO_LFP_92HZ;
+ config->gyro_fsr = ICM20602_GYRO_FSR_1000DPS;
+ config->acc_lpf = ICM20602_ACCLFP_99;
+ config->acc_fsr = ICM20602_ACC_FSR_4G;
+ config->gyro_accel_sample_rate = ICM20602_SAMPLE_RATE_100HZ;
+ config->fifo_enabled = true;
+
+}
+
+static void inv_icm20602_load_config(struct inv_icm20602_state *st)
+{
+ struct icm20602_user_config *config = st->config;
+
+ if (config->user_fps_in_ms == 0)
+ inv_icm20602_def_config(st);
+ config->fifo_enabled = true;
+
+}
+
+static ssize_t inv_icm20602_init_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int result = MPU_SUCCESS;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+ inv_icm20602_load_config(st);
+ result |= icm20602_detect(st);
+ result |= icm20602_init_device(st);
+ icm20602_start_fifo(st);
+ if (result)
+ return result;
+
+ return count;
+}
+
+static IIO_DEVICE_ATTR(
+ inv_icm20602_init,
+ 0644,
+ inv_icm20602_init_show,
+ inv_icm20602_init_store,
+ 0);
+
+/* Attribute of gyro lpf base on the enum inv_icm20602_gyro_temp_lpf_e */
+static ssize_t inv_gyro_lpf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_gyro_lpf_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ struct icm20602_user_config *config = st->config;
+ int gyro_lpf;
+
+ if (kstrtoint(buf, 10, &gyro_lpf))
+ return -EINVAL;
+ if (gyro_lpf > INV_ICM20602_GYRO_LFP_NUM)
+ return -EINVAL;
+ config->gyro_lpf = gyro_lpf;
+ return count;
+}
+static IIO_DEVICE_ATTR(
+ inv_icm20602_gyro_lpf,
+ 0644,
+ inv_gyro_lpf_show,
+ inv_gyro_lpf_store,
+ 0);
+
+/* Attribute of gyro fsr base on enum inv_icm20602_gyro_temp_lpf_e */
+static ssize_t inv_gyro_fsr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_gyro_fsr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ struct icm20602_user_config *config = st->config;
+ int gyro_fsr;
+
+ if (kstrtoint(buf, 10, &gyro_fsr))
+ return -EINVAL;
+ if (gyro_fsr > ICM20602_GYRO_FSR_NUM)
+ return -EINVAL;
+
+ config->gyro_fsr = gyro_fsr;
+ return count;
+}
+
+static IIO_DEVICE_ATTR(
+ inv_icm20602_gyro_fsr,
+ 0644,
+ inv_gyro_fsr_show,
+ inv_gyro_fsr_store,
+ 0);
+
+/* Attribute of gyro_self_test */
+static ssize_t inv_gyro_self_test_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_gyro_self_test_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return 0;
+}
+static IIO_DEVICE_ATTR(
+ inv_icm20602_gyro_self_test,
+ 0644,
+ inv_gyro_self_test_show,
+ inv_gyro_self_test_store,
+ 0);
+
+/* Attribute of gyro fsr base on enum inv_icm20602_acc_fsr_e */
+static ssize_t inv_gyro_acc_fsr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_gyro_acc_fsr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ struct icm20602_user_config *config = st->config;
+ int acc_fsr;
+
+ if (kstrtoint(buf, 10, &acc_fsr))
+ return -EINVAL;
+ if (acc_fsr > ICM20602_ACC_FSR_NUM)
+ return -EINVAL;
+
+ config->acc_fsr = acc_fsr;
+ return count;
+}
+static IIO_DEVICE_ATTR(
+ inv_icm20602_acc_fsr,
+ 0644,
+ inv_gyro_acc_fsr_show,
+ inv_gyro_acc_fsr_store,
+ 0);
+
+/* Attribute of gyro fsr base on enum inv_icm20602_acc_lpf_e */
+static ssize_t inv_gyro_acc_lpf_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_gyro_acc_lpf_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ struct icm20602_user_config *config = st->config;
+ int acc_lpf;
+
+ if (kstrtoint(buf, 10, &acc_lpf))
+ return -EINVAL;
+ if (acc_lpf > ICM20602_ACCLPF_NUM)
+ return -EINVAL;
+
+ config->acc_fsr = acc_lpf;
+ return count;
+}
+static IIO_DEVICE_ATTR(
+ inv_icm20602_acc_lpf,
+ 0644,
+ inv_gyro_acc_lpf_show,
+ inv_gyro_acc_lpf_store,
+ 0);
+
+/* Attribute of acc_self_test */
+static ssize_t inv_acc_self_test_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_acc_self_test_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return 0;
+}
+static IIO_DEVICE_ATTR(
+ inv_icm20602_acc_self_test,
+ 0644,
+ inv_acc_self_test_show,
+ inv_acc_self_test_store,
+ 0);
+
+/* Attribute of user_fps_in_ms */
+static ssize_t inv_user_fps_in_ms_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_user_fps_in_ms_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ struct icm20602_user_config *config = st->config;
+ int user_fps_in_ms;
+
+ if (kstrtoint(buf, 10, &user_fps_in_ms))
+ return -EINVAL;
+ if (user_fps_in_ms < 10)
+ return -EINVAL;
+
+ config->user_fps_in_ms = user_fps_in_ms;
+ return count;
+}
+static IIO_DEVICE_ATTR(
+ inv_user_fps_in_ms,
+ 0644,
+ inv_user_fps_in_ms_show,
+ inv_user_fps_in_ms_store,
+ 0);
+
+/* Attribute of gyro_accel_sample_rate */
+static ssize_t inv_sampling_frequency_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return 0;
+}
+
+static ssize_t inv_sampling_frequency_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return 0;
+}
+static IIO_DEV_ATTR_SAMP_FREQ(
+ 0644,
+ inv_sampling_frequency_show,
+ inv_sampling_frequency_store);
+
+static struct attribute *inv_icm20602_attributes[] = {
+ &iio_dev_attr_inv_icm20602_init.dev_attr.attr,
+
+ &iio_dev_attr_inv_icm20602_gyro_self_test.dev_attr.attr,
+ &iio_dev_attr_inv_icm20602_gyro_fsr.dev_attr.attr,
+ &iio_dev_attr_inv_icm20602_gyro_lpf.dev_attr.attr,
+
+ &iio_dev_attr_inv_icm20602_acc_self_test.dev_attr.attr,
+ &iio_dev_attr_inv_icm20602_acc_fsr.dev_attr.attr,
+ &iio_dev_attr_inv_icm20602_acc_lpf.dev_attr.attr,
+
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+
+ &iio_dev_attr_inv_user_fps_in_ms.dev_attr.attr,
+ NULL,
+};
+
+#define INV_ICM20602_CHAN(_type, _channel2, _index) \
+{ \
+ .type = _type, \
+ .modified = 1, \
+ .channel2 = _channel2, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .shift = 0, \
+ .endianness = IIO_BE, \
+ }, \
+}
+
+static const struct iio_chan_spec inv_icm20602_channels[] = {
+ IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP),
+
+ {
+ .type = IIO_TEMP,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
+ | BIT(IIO_CHAN_INFO_OFFSET)
+ | BIT(IIO_CHAN_INFO_SCALE),
+ .scan_index = INV_ICM20602_SCAN_TEMP,
+ .channel2 = IIO_MOD_X,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .shift = 0,
+ .endianness = IIO_BE,
+ },
+ },
+ INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X),
+ INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y),
+ INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z),
+
+ INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_X, INV_ICM20602_SCAN_ACCL_X),
+ INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y),
+ INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_ICM20602_SCAN_ACCL_Z),
+};
+
+static const struct attribute_group inv_icm20602_attribute_group = {
+ .attrs = inv_icm20602_attributes,
+};
+
+static const struct iio_info icm20602_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = NULL,
+ .write_raw = NULL,
+ .attrs = &inv_icm20602_attribute_group,
+ .validate_trigger = inv_icm20602_validate_trigger,
+};
+
+static int of_populate_icm20602_dt(struct inv_icm20602_state *st)
+{
+ int result = MPU_SUCCESS;
+
+ /* use client device irq */
+ st->gpio = of_get_named_gpio(st->client->dev.of_node,
+ "invensense,icm20602-gpio", 0);
+ result = gpio_is_valid(st->gpio);
+ if (!result) {
+ pr_err("gpio_is_valid %d failed\n", st->gpio);
+ return -MPU_FAIL;
+ }
+
+ result = gpio_request(st->gpio, "icm20602-irq");
+ if (result) {
+ pr_err("gpio_request failed\n");
+ return -MPU_FAIL;
+ }
+
+ result = gpio_direction_input(st->gpio);
+ if (result) {
+ pr_err("gpio_direction_input failed\n");
+ return -MPU_FAIL;
+ }
+
+ st->client->irq = gpio_to_irq(st->gpio);
+ if (st->client->irq < 0) {
+ pr_err("gpio_to_irq failed\n");
+ return -MPU_FAIL;
+ }
+
+ return MPU_SUCCESS;
+}
+
+/*
+ * inv_icm20602_probe() - probe function.
+ * @client: i2c client.
+ * @id: i2c device id.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ * The I2C address of the ICM-20602 is 0x68 or 0x69
+ * depending upon the value driven on AD0 pin.
+ */
+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;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st));
+ if (indio_dev == NULL) {
+ result = -ENOMEM;
+ goto out_remove_trigger;
+ }
+ st = iio_priv(indio_dev);
+ st->client = client;
+ st->interface = ICM20602_I2C;
+
+ pr_debug("i2c address is %x\n", client->addr);
+ result = of_populate_icm20602_dt(st);
+ if (result)
+ return result;
+
+ st->config = kzalloc(sizeof(struct icm20602_user_config), GFP_ATOMIC);
+ if (st->config == NULL)
+ return -ENOMEM;
+
+ icm20602_init_reg_map();
+
+ i2c_set_clientdata(client, indio_dev);
+
+ dev_set_drvdata(&client->dev, indio_dev);
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = ICM20602_DEV_NAME;
+ indio_dev->channels = inv_icm20602_channels;
+ indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels);
+
+ indio_dev->info = &icm20602_info;
+ indio_dev->modes = INDIO_BUFFER_TRIGGERED;
+ result = iio_triggered_buffer_setup(indio_dev,
+ inv_icm20602_irq_handler, inv_icm20602_read_fifo_fn, NULL);
+ if (result) {
+ dev_err(&st->client->dev, " configure buffer fail %d\n",
+ result);
+ goto out_remove_trigger;
+ }
+
+ result = inv_icm20602_probe_trigger(indio_dev);
+ if (result) {
+ dev_err(&st->client->dev, "trigger probe fail %d\n", result);
+ goto out_unreg_ring;
+ }
+
+ INIT_KFIFO(st->timestamps);
+ spin_lock_init(&st->time_stamp_lock);
+ result = iio_device_register(indio_dev);
+ if (result) {
+ dev_err(&st->client->dev, "IIO register fail %d\n", result);
+ goto out_remove_trigger;
+ }
+
+ return 0;
+
+out_remove_trigger:
+ inv_icm20602_remove_trigger(st);
+out_unreg_ring:
+ iio_triggered_buffer_cleanup(indio_dev);
+out_free:
+ iio_device_free(indio_dev);
+ gpio_free(st->gpio);
+
+ return 0;
+}
+
+static int inv_icm20602_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+ gpio_free(st->gpio);
+ iio_device_unregister(indio_dev);
+ inv_icm20602_remove_trigger(st);
+ iio_triggered_buffer_cleanup(indio_dev);
+ iio_device_free(indio_dev);
+
+ return 0;
+}
+
+static int inv_icm20602_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int inv_icm20602_resume(struct device *dev)
+{
+ return 0;
+}
+
+static const struct dev_pm_ops icm20602_pm_ops = {
+ .resume = inv_icm20602_resume,
+ .suspend = inv_icm20602_suspend,
+};
+
+static const struct of_device_id icm20602_match_table[] = {
+ {.compatible = "invensense,icm20602"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, icm20602_match_table);
+
+static const struct i2c_device_id inv_icm20602_id[] = {
+ {"icm20602", 0},
+ {}
+};
+
+static struct i2c_driver icm20602_i2c_driver = {
+ .probe = inv_icm20602_probe,
+ .remove = inv_icm20602_remove,
+ .id_table = inv_icm20602_id,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "inv-icm20602",
+ .of_match_table = icm20602_match_table,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .pm = &icm20602_pm_ops,
+ },
+};
+
+static int __init inv_icm20602_init(void)
+{
+ return i2c_add_driver(&icm20602_i2c_driver);
+}
+module_init(inv_icm20602_init);
+
+static void __exit inv_icm20602_exit(void)
+{
+ i2c_del_driver(&icm20602_i2c_driver);
+}
+module_exit(inv_icm20602_exit);
+
+MODULE_DESCRIPTION("icm20602 IMU driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h
new file mode 100644
index 0000000..943fc1e
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _INV_ICM20602_IIO_H_
+#define _INV_ICM20602_IIO_H_
+
+#include <linux/i2c.h>
+#include <linux/kfifo.h>
+#include <linux/spinlock.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/platform_data/invensense_mpu6050.h>
+
+/*
+ * it uses sensor irq to trigger
+ * if set INV20602_DEVICE_IRQ_TRIGGER as 1,
+ * otherwise use SMD IRQ to trigger
+ */
+#define INV20602_DEVICE_IRQ_TRIGGER 0
+
+#if INV20602_DEVICE_IRQ_TRIGGER
+#define INV20602_SMD_IRQ_TRIGGER 0
+#else
+#define INV20602_SMD_IRQ_TRIGGER 1
+#endif
+
+#define INV_ICM20602_TIME_STAMP_TOR 5
+#define ICM20602_PACKAGE_SIZE 14
+
+/* device enum */
+enum inv_devices {
+ INV_ICM20602,
+ INV_NUM_PARTS,
+};
+
+enum _mpu_err {
+ MPU_SUCCESS = 0,
+ MPU_FAIL = 1,
+ MPU_READ_FAIL = 2,
+ MPU_WRITE_FAIL = 3,
+};
+
+/* Gyro Full Scale Range Enum */
+enum inv_icm20602_gyro_fsr_e {
+ ICM20602_GYRO_FSR_250DPS = 0,
+ ICM20602_GYRO_FSR_500DPS,
+ ICM20602_GYRO_FSR_1000DPS,
+ ICM20602_GYRO_FSR_2000DPS,
+ ICM20602_GYRO_FSR_NUM,
+};
+
+/* Accelerometor Full Scale Range Enum */
+enum inv_icm20602_acc_fsr_e {
+ ICM20602_ACC_FSR_2G = 0,
+ ICM20602_ACC_FSR_4G,
+ ICM20602_ACC_FSR_8G,
+ ICM20602_ACC_FSR_16G,
+ ICM20602_ACC_FSR_NUM,
+};
+
+/* scan element definition */
+enum inv_icm20602_scan {
+ INV_ICM20602_SCAN_ACCL_X,
+ INV_ICM20602_SCAN_ACCL_Y,
+ INV_ICM20602_SCAN_ACCL_Z,
+ INV_ICM20602_SCAN_GYRO_X,
+ INV_ICM20602_SCAN_GYRO_Y,
+ INV_ICM20602_SCAN_GYRO_Z,
+ INV_ICM20602_SCAN_TEMP,
+ INV_ICM20602_SCAN_TIMESTAMP,
+};
+
+/* this is for CONFIGURATION reg bit[2:0] DLFP_CFG */
+enum inv_icm20602_gyro_temp_lpf_e {
+ INV_ICM20602_GLFP_250HZ = 0, /* 8KHz */
+ INV_ICM20602_GYRO_LFP_176HZ, /* 1KHz */
+ INV_ICM20602_GYRO_LFP_92HZ,
+ INV_ICM20602_GYRO_LFP_41HZ,
+ INV_ICM20602_GYRO_LFP_20HZ,
+ INV_ICM20602_GYRO_LFP_10HZ,
+ INV_ICM20602_GYRO_LFP_5HZ,
+ INV_ICM20602_GYRO_LFP_NUM,
+};
+
+enum inv_icm20602_gyro_sample_rate_e {
+ ICM20602_SAMPLE_RATE_100HZ = 100,
+ ICM20602_SAMPLE_RATE_200HZ = 200,
+ ICM20602_SAMPLE_RATE_500HZ = 500,
+ ICM20602_SAMPLE_RATE_1000HZ = 1000,
+};
+
+/* this is for ACCEL CONFIGURATION 2 reg */
+enum inv_icm20602_acc_lpf_e {
+ ICM20602_ACCLFP_218 = 1,
+ ICM20602_ACCLFP_99,
+ ICM20602_ACCLFP_44,
+ ICM20602_ACCLFP_21,
+ ICM20602_ACCLFP_10,
+ ICM20602_ACCLFP_5,
+ ICM20602_ACCLFP_420_NOLPF,
+ ICM20602_ACCLPF_NUM = 7,
+};
+
+/* IIO attribute address */
+enum INV_ICM20602_IIO_ATTR_ADDR {
+ ATTR_ICM20602_GYRO_MATRIX,
+ ATTR_ICM20602_ACCL_MATRIX,
+};
+
+/* this is for GYRO CONFIGURATION reg */
+enum inv_icm20602_fs_e {
+ INV_ICM20602_FS_250DPS = 0,
+ INV_ICM20602_FS_500DPS,
+ INV_ICM20602_FS_1000DPS,
+ INV_ICM20602_FS_2000DPS,
+ NUM_ICM20602_FS,
+};
+
+enum inv_icm20602_clock_sel_e {
+ INV_ICM20602_CLK_INTERNAL = 0,
+ INV_ICM20602_CLK_PLL,
+ INV_NUM_CLK,
+};
+
+enum inv_icm20602_spi_freq {
+ MPU_SPI_FREQUENCY_1MHZ = 960000UL,
+ MPU_SPI_FREQUENCY_5MHZ = 4800000UL,
+ MPU_SPI_FREQUENCY_8MHZ = 8000000UL,
+ MPU_SPI_FREQUENCY_10MHZ = 10000000UL,
+ MPU_SPI_FREQUENCY_15MHZ = 15000000UL,
+ MPU_SPI_FREQUENCY_20MHZ = 20000000UL,
+};
+
+#define MPU_SPI_BUF_LEN 512
+#define ICM20602_DEV_NAME "icm20602_iio"
+
+struct inv_icm20602_platform_data {
+ __s8 orientation[9];
+};
+
+struct X_Y_Z {
+ u8 X;
+ u8 Y;
+ u8 Z;
+};
+
+enum RAW_TYPE {
+ ACCEL = 1,
+ GYRO = 2,
+ TEMP = 4,
+};
+
+struct icm20602_user_config {
+ enum inv_icm20602_gyro_temp_lpf_e gyro_lpf;
+ enum inv_icm20602_gyro_fsr_e gyro_fsr;
+ struct X_Y_Z gyro_self_test;
+
+ enum inv_icm20602_acc_lpf_e acc_lpf;
+ enum inv_icm20602_acc_fsr_e acc_fsr;
+ struct X_Y_Z acc_self_test;
+
+ uint32_t gyro_accel_sample_rate;
+ uint32_t user_fps_in_ms;
+
+ bool fifo_enabled;
+ uint32_t fifo_waterlevel;
+ struct X_Y_Z wake_on_motion;
+};
+
+enum inv_icm20602_interface {
+ ICM20602_I2C = 0,
+ ICM20602_SPI
+};
+
+/*
+ * struct inv_icm20602_state - Driver state variables.
+ * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp.
+ * @trig: IIO trigger.
+ * @chip_config: Cached attribute information.
+ * @reg: Map of important registers.
+ * @hw: Other hardware-specific information.
+ * @chip_type: chip type.
+ * @time_stamp_lock: spin lock to time stamp.
+ * @spi: spi devices
+ * @plat_data: platform data.
+ * @timestamps: kfifo queue to store time stamp.
+ */
+struct inv_icm20602_state {
+#define TIMESTAMP_FIFO_SIZE 32
+ enum inv_icm20602_interface interface;
+ struct iio_trigger *trig;
+ const struct inv_icm20602_reg_map *reg;
+ struct icm20602_user_config *config;
+ spinlock_t time_stamp_lock;
+ struct spi_device *spi;
+ struct i2c_client *client;
+ u8 fifo_packet_size;
+ int fifo_cnt_threshold;
+ char *buf;
+ struct struct_icm20602_data *data_push;
+ enum inv_devices chip_type;
+ int gpio;
+ DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
+};
+
+struct struct_icm20602_raw_data {
+ u8 ACCEL_XOUT_H;
+ u8 ACCEL_XOUT_L;
+
+ u8 ACCEL_YOUT_H;
+ u8 ACCEL_YOUT_L;
+
+ u8 ACCEL_ZOUT_H;
+ u8 ACCEL_ZOUT_L;
+
+ u8 TEMP_OUT_H;
+ u8 TEMP_OUT_L;
+
+ u8 GYRO_XOUT_H;
+ u8 GYRO_XOUT_L;
+
+ u8 GYRO_YOUT_H;
+ u8 GYRO_YOUT_L;
+
+ u8 GYRO_ZOUT_H;
+ u8 GYRO_ZOUT_L;
+};
+
+struct struct_icm20602_real_data {
+ u16 ACCEL_XOUT;
+ u16 ACCEL_YOUT;
+ u16 ACCEL_ZOUT;
+
+ u16 GYRO_XOUT;
+ u16 GYRO_YOUT;
+ u16 GYRO_ZOUT;
+
+ u16 TEMP_OUT;
+};
+
+struct struct_icm20602_data {
+ s64 timestamps;
+ struct struct_icm20602_raw_data raw_data;
+ struct struct_icm20602_real_data real_data;
+};
+
+extern struct iio_trigger *inv_trig;
+irqreturn_t inv_icm20602_irq_handler(int irq, void *p);
+irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p);
+int inv_icm20602_reset_fifo(struct iio_dev *indio_dev);
+
+int inv_icm20602_probe_trigger(struct iio_dev *indio_dev);
+void inv_icm20602_remove_trigger(struct inv_icm20602_state *st);
+int inv_icm20602_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig);
+
+int icm20602_read_raw(struct inv_icm20602_state *st,
+ struct struct_icm20602_real_data *real_data, uint32_t type);
+int icm20602_init_reg_map(void);
+int icm20602_init_device(struct inv_icm20602_state *st);
+int icm20602_detect(struct inv_icm20602_state *st);
+int icm20602_read_fifo(struct inv_icm20602_state *st,
+ void *buf, const int size);
+int icm20602_start_fifo(struct inv_icm20602_state *st);
+#endif
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c
new file mode 100644
index 0000000..b0f93be
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kfifo.h>
+#include <linux/poll.h>
+#include <linux/spi/spi.h>
+#include "inv_icm20602_iio.h"
+#include <linux/i2c.h>
+
+#define combine_8_to_16(upper, lower) ((_upper << 8) | _lower)
+
+static void inv_clear_kfifo(struct inv_icm20602_state *st)
+{
+ unsigned long flags;
+
+ /* Take the spin lock sem to avoid interrupt kick in */
+ spin_lock_irqsave(&st->time_stamp_lock, flags);
+ kfifo_reset(&st->timestamps);
+ spin_unlock_irqrestore(&st->time_stamp_lock, flags);
+}
+
+int inv_icm20602_reset_fifo(struct iio_dev *indio_dev)
+{
+ int result;
+ //u8 d;
+ //struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+ return result;
+}
+
+/*
+ * inv_icm20602_irq_handler() - Cache a timestamp at each data ready interrupt.
+ */
+irqreturn_t inv_icm20602_irq_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ s64 timestamp;
+
+ timestamp = iio_get_time_ns(indio_dev);
+
+ kfifo_in_spinlocked(&st->timestamps, ×tamp, 1,
+ &st->time_stamp_lock);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static int inv_icm20602_read_data(struct iio_dev *indio_dev)
+{
+ int result = MPU_SUCCESS;
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+ struct icm20602_user_config *config = st->config;
+ int package_count;
+ //char *buf = st->buf;
+ //struct struct_icm20602_data *data_push = st->data_push;
+ s64 timestamp;
+ int i;
+
+ if (!st)
+ return -MPU_FAIL;
+ package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE;
+ mutex_lock(&indio_dev->mlock);
+ if (config->fifo_enabled) {
+ result = icm20602_read_fifo(st,
+ st->buf, config->fifo_waterlevel);
+ if (result != config->fifo_waterlevel) {
+ pr_err("icm20602 read fifo failed, result = %d\n",
+ result);
+ goto flush_fifo;
+ }
+
+ for (i = 0; i < package_count; i++) {
+ memcpy((char *)(&st->data_push[i].raw_data),
+ st->buf, ICM20602_PACKAGE_SIZE);
+ result = kfifo_out(&st->timestamps,
+ ×tamp, 1);
+ /* when there is no timestamp, put it as 0 */
+ if (result == 0)
+ timestamp = 0;
+ st->data_push[i].timestamps = timestamp;
+ iio_push_to_buffers(indio_dev, st->data_push+i);
+ st->buf += ICM20602_PACKAGE_SIZE;
+ }
+ }
+//end_session:
+ mutex_unlock(&indio_dev->mlock);
+ iio_trigger_notify_done(indio_dev->trig);
+ return MPU_SUCCESS;
+
+flush_fifo:
+ /* Flush HW and SW FIFOs. */
+ inv_clear_kfifo(st);
+ inv_icm20602_reset_fifo(indio_dev);
+ mutex_unlock(&indio_dev->mlock);
+ iio_trigger_notify_done(indio_dev->trig);
+ return MPU_SUCCESS;
+}
+
+/*
+ * inv_icm20602_read_fifo() - Transfer data from hardware FIFO to KFIFO.
+ */
+irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+
+ inv_icm20602_read_data(indio_dev);
+ return IRQ_HANDLED;
+}
diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c
new file mode 100644
index 0000000..f05a631
--- /dev/null
+++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Copyright (C) 2012 Invensense, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/spi/spi.h>
+#include <linux/sched/rt.h>
+#include <linux/delay.h>
+#include "inv_icm20602_iio.h"
+#include <linux/i2c.h>
+
+static const struct iio_trigger_ops inv_icm20602_trigger_ops = {
+ .owner = THIS_MODULE,
+};
+
+int inv_icm20602_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+ if (st->trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+int inv_icm20602_probe_trigger(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct inv_icm20602_state *st = iio_priv(indio_dev);
+
+ st->trig = iio_trigger_alloc("%s-dev%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (st->trig == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING,
+ "inv_icm20602",
+ st->trig);
+ if (ret) {
+ pr_err("request_irq failed\n");
+ goto error_free_trig;
+ }
+ st->trig->dev.parent = &st->client->dev;
+ st->trig->ops = &inv_icm20602_trigger_ops;
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = iio_trigger_register(st->trig);
+ if (ret) {
+ pr_err("iio_trigger_register failed\n");
+ goto error_free_irq;
+ }
+ indio_dev->trig = st->trig;
+
+ return 0;
+
+error_free_irq:
+ free_irq(st->client->irq, st->trig);
+error_free_trig:
+ iio_trigger_free(st->trig);
+error_ret:
+ return ret;
+}
+
+void inv_icm20602_remove_trigger(struct inv_icm20602_state *st)
+{
+ iio_trigger_unregister(st->trig);
+ free_irq(st->client->irq, st->trig);
+ iio_trigger_free(st->trig);
+}
diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c
index 7de0f39..d23cf77 100644
--- a/drivers/iio/light/rpr0521.c
+++ b/drivers/iio/light/rpr0521.c
@@ -510,13 +510,26 @@
ret = pm_runtime_set_active(&client->dev);
if (ret < 0)
- return ret;
+ goto err_poweroff;
pm_runtime_enable(&client->dev);
pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS);
pm_runtime_use_autosuspend(&client->dev);
- return iio_device_register(indio_dev);
+ ret = iio_device_register(indio_dev);
+ if (ret)
+ goto err_pm_disable;
+
+ return 0;
+
+err_pm_disable:
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+err_poweroff:
+ rpr0521_poweroff(data);
+
+ return ret;
}
static int rpr0521_remove(struct i2c_client *client)
diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c
index 6325e7d..f3cb4dc 100644
--- a/drivers/iio/magnetometer/st_magn_spi.c
+++ b/drivers/iio/magnetometer/st_magn_spi.c
@@ -48,8 +48,6 @@
}
static const struct spi_device_id st_magn_id_table[] = {
- { LSM303DLHC_MAGN_DEV_NAME },
- { LSM303DLM_MAGN_DEV_NAME },
{ LIS3MDL_MAGN_DEV_NAME },
{ LSM303AGR_MAGN_DEV_NAME },
{},
diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c
index 19d2eb4..2a4a62e 100644
--- a/drivers/iio/pressure/zpa2326.c
+++ b/drivers/iio/pressure/zpa2326.c
@@ -871,12 +871,13 @@
{
int ret;
unsigned int val;
+ long timeout;
zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt");
- ret = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_interruptible_timeout(
&private->data_ready, ZPA2326_CONVERSION_JIFFIES);
- if (ret > 0)
+ if (timeout > 0)
/*
* Interrupt handler completed before timeout: return operation
* status.
@@ -886,13 +887,16 @@
/* Clear all interrupts just to be sure. */
regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val);
- if (!ret)
+ if (!timeout) {
/* Timed out. */
+ zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)",
+ timeout);
ret = -ETIME;
-
- if (ret != -ERESTARTSYS)
- zpa2326_warn(indio_dev, "no one shot interrupt occurred (%d)",
- ret);
+ } else if (timeout < 0) {
+ zpa2326_warn(indio_dev,
+ "wait for one shot interrupt cancelled");
+ ret = -ERESTARTSYS;
+ }
return ret;
}
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index fb4ce03..978b8d9 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -209,6 +209,22 @@
}
EXPORT_SYMBOL(rdma_addr_size);
+int rdma_addr_size_in6(struct sockaddr_in6 *addr)
+{
+ int ret = rdma_addr_size((struct sockaddr *) addr);
+
+ return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_in6);
+
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
+{
+ int ret = rdma_addr_size((struct sockaddr *) addr);
+
+ return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_kss);
+
static struct rdma_addr_client self;
void rdma_addr_register_client(struct rdma_addr_client *client)
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 017a09c..cb79d17 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -132,7 +132,7 @@
ctx = idr_find(&ctx_idr, id);
if (!ctx)
ctx = ERR_PTR(-ENOENT);
- else if (ctx->file != file)
+ else if (ctx->file != file || !ctx->cm_id)
ctx = ERR_PTR(-EINVAL);
return ctx;
}
@@ -454,6 +454,7 @@
struct rdma_ucm_create_id cmd;
struct rdma_ucm_create_id_resp resp;
struct ucma_context *ctx;
+ struct rdma_cm_id *cm_id;
enum ib_qp_type qp_type;
int ret;
@@ -474,10 +475,10 @@
return -ENOMEM;
ctx->uid = cmd.uid;
- ctx->cm_id = rdma_create_id(current->nsproxy->net_ns,
- ucma_event_handler, ctx, cmd.ps, qp_type);
- if (IS_ERR(ctx->cm_id)) {
- ret = PTR_ERR(ctx->cm_id);
+ cm_id = rdma_create_id(current->nsproxy->net_ns,
+ ucma_event_handler, ctx, cmd.ps, qp_type);
+ if (IS_ERR(cm_id)) {
+ ret = PTR_ERR(cm_id);
goto err1;
}
@@ -487,14 +488,19 @@
ret = -EFAULT;
goto err2;
}
+
+ ctx->cm_id = cm_id;
return 0;
err2:
- rdma_destroy_id(ctx->cm_id);
+ rdma_destroy_id(cm_id);
err1:
mutex_lock(&mut);
idr_remove(&ctx_idr, ctx->id);
mutex_unlock(&mut);
+ mutex_lock(&file->mut);
+ list_del(&ctx->list);
+ mutex_unlock(&file->mut);
kfree(ctx);
return ret;
}
@@ -624,6 +630,9 @@
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
+ if (!rdma_addr_size_in6(&cmd.addr))
+ return -EINVAL;
+
ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
@@ -637,22 +646,21 @@
int in_len, int out_len)
{
struct rdma_ucm_bind cmd;
- struct sockaddr *addr;
struct ucma_context *ctx;
int ret;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- addr = (struct sockaddr *) &cmd.addr;
- if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+ if (cmd.reserved || !cmd.addr_size ||
+ cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
return -EINVAL;
ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ret = rdma_bind_addr(ctx->cm_id, addr);
+ ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
ucma_put_ctx(ctx);
return ret;
}
@@ -668,13 +676,16 @@
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
+ if (!rdma_addr_size_in6(&cmd.src_addr) ||
+ !rdma_addr_size_in6(&cmd.dst_addr))
+ return -EINVAL;
+
ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
- (struct sockaddr *) &cmd.dst_addr,
- cmd.timeout_ms);
+ (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
ucma_put_ctx(ctx);
return ret;
}
@@ -684,24 +695,23 @@
int in_len, int out_len)
{
struct rdma_ucm_resolve_addr cmd;
- struct sockaddr *src, *dst;
struct ucma_context *ctx;
int ret;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- src = (struct sockaddr *) &cmd.src_addr;
- dst = (struct sockaddr *) &cmd.dst_addr;
- if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
- !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+ if (cmd.reserved ||
+ (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
+ !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
return -EINVAL;
ctx = ucma_get_ctx(file, cmd.id);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
+ ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+ (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
ucma_put_ctx(ctx);
return ret;
}
@@ -1146,6 +1156,11 @@
if (IS_ERR(ctx))
return PTR_ERR(ctx);
+ if (!ctx->cm_id->device) {
+ ret = -EINVAL;
+ goto out;
+ }
+
resp.qp_attr_mask = 0;
memset(&qp_attr, 0, sizeof qp_attr);
qp_attr.qp_state = cmd.qp_state;
@@ -1216,6 +1231,9 @@
if (!optlen)
return -EINVAL;
+ if (!ctx->cm_id->device)
+ return -EINVAL;
+
memset(&sa_path, 0, sizeof(sa_path));
ib_sa_unpack_path(path_data->path_rec, &sa_path);
@@ -1302,7 +1320,7 @@
{
struct rdma_ucm_notify cmd;
struct ucma_context *ctx;
- int ret;
+ int ret = -EINVAL;
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
@@ -1311,7 +1329,9 @@
if (IS_ERR(ctx))
return PTR_ERR(ctx);
- ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
+ if (ctx->cm_id->device)
+ ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event);
+
ucma_put_ctx(ctx);
return ret;
}
@@ -1397,7 +1417,7 @@
join_cmd.response = cmd.response;
join_cmd.uid = cmd.uid;
join_cmd.id = cmd.id;
- join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+ join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
if (!join_cmd.addr_size)
return -EINVAL;
@@ -1416,7 +1436,7 @@
if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
return -EFAULT;
- if (!rdma_addr_size((struct sockaddr *)&cmd.addr))
+ if (!rdma_addr_size_kss(&cmd.addr))
return -EINVAL;
return ucma_process_join(file, &cmd, out_len);
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 6512a55..dd18b74 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -488,6 +488,7 @@
ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *)));
release_ep_resources(ep);
+ kfree_skb(skb);
return 0;
}
@@ -498,6 +499,7 @@
ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *)));
c4iw_put_ep(&ep->parent_ep->com);
release_ep_resources(ep);
+ kfree_skb(skb);
return 0;
}
@@ -569,11 +571,13 @@
PDBG("%s rdev %p\n", __func__, rdev);
req->cmd = CPL_ABORT_NO_RST;
+ skb_get(skb);
ret = c4iw_ofld_send(rdev, skb);
if (ret) {
__state_set(&ep->com, DEAD);
queue_arp_failure_cpl(ep, skb, FAKE_CPL_PUT_EP_SAFE);
- }
+ } else
+ kfree_skb(skb);
}
static int send_flowc(struct c4iw_ep *ep)
diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c
index 919a547..621b60a 100644
--- a/drivers/infiniband/hw/hfi1/sysfs.c
+++ b/drivers/infiniband/hw/hfi1/sysfs.c
@@ -196,7 +196,8 @@
};
static struct attribute *port_cc_default_attributes[] = {
- &cc_prescan_attr.attr
+ &cc_prescan_attr.attr,
+ NULL
};
static struct kobj_type port_cc_ktype = {
diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
index 2c4b4d0..3b973cb 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c
@@ -3644,8 +3644,10 @@
hmc_info->hmc_obj[I40IW_HMC_IW_APBVT_ENTRY].cnt = 1;
hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt = mrwanted;
- hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt = I40IW_MAX_WQ_ENTRIES * qpwanted;
- hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt = 4 * I40IW_MAX_IRD_SIZE * qpwanted;
+ hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt =
+ roundup_pow_of_two(I40IW_MAX_WQ_ENTRIES * qpwanted);
+ hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt =
+ roundup_pow_of_two(2 * I40IW_MAX_IRD_SIZE * qpwanted);
hmc_info->hmc_obj[I40IW_HMC_IW_XFFL].cnt =
hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt / hmc_fpm_misc->xf_block_size;
hmc_info->hmc_obj[I40IW_HMC_IW_Q1FL].cnt =
diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h
index d1328a6..8ce599e 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_d.h
+++ b/drivers/infiniband/hw/i40iw/i40iw_d.h
@@ -86,6 +86,7 @@
#define RDMA_OPCODE_MASK 0x0f
#define RDMA_READ_REQ_OPCODE 1
#define Q2_BAD_FRAME_OFFSET 72
+#define Q2_FPSN_OFFSET 64
#define CQE_MAJOR_DRV 0x8000
#define I40IW_TERM_SENT 0x01
diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c
index c62d354..3ed4914 100644
--- a/drivers/infiniband/hw/i40iw/i40iw_puda.c
+++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c
@@ -1320,7 +1320,7 @@
u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx;
u32 rcv_wnd = hw_host_ctx[23];
/* first partial seq # in q2 */
- u32 fps = qp->q2_buf[16];
+ u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET);
struct list_head *rxlist = &pfpdu->rxlist;
struct list_head *plist;
diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c
index 6d9904a..29dc527 100644
--- a/drivers/infiniband/sw/rdmavt/cq.c
+++ b/drivers/infiniband/sw/rdmavt/cq.c
@@ -197,7 +197,7 @@
return ERR_PTR(-EINVAL);
/* Allocate the completion queue structure. */
- cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+ cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, rdi->dparms.node);
if (!cq)
return ERR_PTR(-ENOMEM);
@@ -213,7 +213,9 @@
sz += sizeof(struct ib_uverbs_wc) * (entries + 1);
else
sz += sizeof(struct ib_wc) * (entries + 1);
- wc = vmalloc_user(sz);
+ wc = udata ?
+ vmalloc_user(sz) :
+ vzalloc_node(sz, rdi->dparms.node);
if (!wc) {
ret = ERR_PTR(-ENOMEM);
goto bail_cq;
@@ -368,7 +370,9 @@
sz += sizeof(struct ib_uverbs_wc) * (cqe + 1);
else
sz += sizeof(struct ib_wc) * (cqe + 1);
- wc = vmalloc_user(sz);
+ wc = udata ?
+ vmalloc_user(sz) :
+ vzalloc_node(sz, rdi->dparms.node);
if (!wc)
return -ENOMEM;
diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c
index 59f37f4..ced416f 100644
--- a/drivers/infiniband/sw/rxe/rxe_verbs.c
+++ b/drivers/infiniband/sw/rxe/rxe_verbs.c
@@ -747,9 +747,8 @@
memcpy(wqe->dma.sge, ibwr->sg_list,
num_sge * sizeof(struct ib_sge));
- wqe->iova = (mask & WR_ATOMIC_MASK) ?
- atomic_wr(ibwr)->remote_addr :
- rdma_wr(ibwr)->remote_addr;
+ wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr :
+ mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0;
wqe->mask = mask;
wqe->dma.length = length;
wqe->dma.resid = length;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 84f9185..463ea59 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -2626,9 +2626,11 @@
ret = FAST_IO_FAIL;
else
ret = FAILED;
- srp_free_req(ch, req, scmnd, 0);
- scmnd->result = DID_ABORT << 16;
- scmnd->scsi_done(scmnd);
+ if (ret == SUCCESS) {
+ srp_free_req(ch, req, scmnd, 0);
+ scmnd->result = DID_ABORT << 16;
+ scmnd->scsi_done(scmnd);
+ }
return ret;
}
@@ -3395,12 +3397,10 @@
num_online_nodes());
const int ch_end = ((node_idx + 1) * target->ch_count /
num_online_nodes());
- const int cv_start = (node_idx * ibdev->num_comp_vectors /
- num_online_nodes() + target->comp_vector)
- % ibdev->num_comp_vectors;
- const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors /
- num_online_nodes() + target->comp_vector)
- % ibdev->num_comp_vectors;
+ const int cv_start = node_idx * ibdev->num_comp_vectors /
+ num_online_nodes();
+ const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors /
+ num_online_nodes();
int cpu_idx = 0;
for_each_online_cpu(cpu) {
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 7cf468a..9888c9b 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -2292,12 +2292,8 @@
}
spin_unlock_irqrestore(&ioctx->spinlock, flags);
- if (unlikely(transport_check_aborted_status(&ioctx->cmd, false)
- || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) {
- atomic_inc(&ch->req_lim_delta);
- srpt_abort_cmd(ioctx);
+ if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT)))
return;
- }
/* For read commands, transfer the data to the initiator. */
if (ioctx->cmd.data_direction == DMA_FROM_DEVICE &&
@@ -2670,7 +2666,8 @@
struct srpt_rdma_ch *ch = ioctx->ch;
unsigned long flags;
- WARN_ON(ioctx->state != SRPT_STATE_DONE);
+ WARN_ON_ONCE(ioctx->state != SRPT_STATE_DONE &&
+ !(ioctx->cmd.transport_state & CMD_T_ABORTED));
if (ioctx->n_rw_ctx) {
srpt_free_rw_ctxs(ch, ioctx);
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 3026c06..f8a987a 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -398,6 +398,18 @@
To compile this driver as a module, choose M here: the
module will be called keychord.
+
+config STMVL53L0X
+ tristate "STM VL53L0X Ranging Sensor"
+ depends on I2C
+ help
+ Say Y here if you want to enable the key chord driver
+ This is a Time-of-Flight (ToF) laser-ranging sensor, provide
+ the distance from obstacle.
+
+ To compile this driver as a module, choose M here: the module will
+ be called vl5310x.
+
config INPUT_KEYSPAN_REMOTE
tristate "Keyspan DMR USB remote control"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index c3af7c2..149273c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -82,3 +82,5 @@
obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o
+obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/
+obj-$(CONFIG_STMVL53L0X) += vl53l0x/
diff --git a/drivers/input/misc/vl53l0x/Makefile b/drivers/input/misc/vl53l0x/Makefile
new file mode 100644
index 0000000..af00414
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/Makefile
@@ -0,0 +1,20 @@
+#
+# Makefile for the vl53L0X drivers.
+#
+
+# Each configuration option enables a list of files.
+FEATURE_USE_CCI := false
+#FEATURE_USE_CCI := true
+
+ifeq ($(FEATURE_USE_CCI), true)
+ccflags-y += -Idrivers/input/misc/vl53l0x/inc -DCAMERA_CCI
+else
+ccflags-y += -Idrivers/input/misc/vl53l0x/inc -DSTM_TEST
+endif
+
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io
+ccflags-y += -Idrivers/media/platform/msm/camera_v2
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/common
+ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci
+obj-$(CONFIG_STMVL53L0X) += stmvl53l0x.o
+stmvl53l0x-objs := stmvl53l0x_module.o stmvl53l0x_module-i2c.o stmvl53l0x_module-cci.o src/vl53l0x_api_calibration.o src/vl53l0x_api_core.o src/vl53l0x_api_ranging.o src/vl53l0x_api_strings.o src/vl53l0x_api.o src/vl53l0x_platform.o src/vl53l0x_i2c_platform.o src/vl53l0x_port_i2c.o
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h
new file mode 100644
index 0000000..a0e0e79
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h
@@ -0,0 +1,1943 @@
+/*
+ * vl53l0x_api.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_API_H_
+#define _VL_API_H_
+
+#include "vl53l0x_api_strings.h"
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#ifdef _MSC_VER
+# ifdef VL_API_EXPORTS
+# define VL_API __declspec(dllexport)
+# else
+# define VL_API
+# endif
+#else
+# define VL_API
+#endif
+
+/** @defgroup VL_cut11_group VL53L0X cut1.1 Function Definition
+ * @brief VL53L0X cut1.1 Function Definition
+ * @{
+ */
+
+/** @defgroup VL_general_group VL53L0X General Functions
+ * @brief General functions and definitions
+ * @{
+ */
+
+/**
+ * @brief Return the VL53L0X PAL Implementation Version
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param pVersion Pointer to current PAL Implementation Version
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetVersion(struct VL_Version_t *pVersion);
+
+/**
+ * @brief Return the PAL Specification Version used for the current
+ * implementation.
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param pPalSpecVersion Pointer to current PAL Specification Version
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetPalSpecVersion(
+ struct VL_Version_t *pPalSpecVersion);
+
+/**
+ * @brief Reads the Product Revision for a for given Device
+ * This function can be used to distinguish cut1.0 from cut1.1.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pProductRevisionMajor Pointer to Product Revision Major
+ * for a given Device
+ * @param pProductRevisionMinor Pointer to Product Revision Minor
+ * for a given Device
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetProductRevision(struct vl_data *Dev,
+ uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor);
+
+/**
+ * @brief Reads the Device information for given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pVL_DeviceInfo Pointer to current device info for a given
+ * Device
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceInfo(struct vl_data *Dev,
+ struct VL_DeviceInfo_t *pVL_DeviceInfo);
+
+/**
+ * @brief Read current status of the error register for the selected device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceErrorStatus Pointer to current error code of the device
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev,
+ uint8_t *pDeviceErrorStatus);
+
+/**
+ * @brief Human readable Range Status string for a given RangeStatus
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param RangeStatus The RangeStatus code as stored on
+ * @a struct VL_RangingMeasurementData_t
+ * @param pRangeStatusString The returned RangeStatus string.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetRangeStatusString(uint8_t RangeStatus,
+ char *pRangeStatusString);
+
+/**
+ * @brief Human readable error string for a given Error Code
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param ErrorCode The error code as stored on ::uint8_t
+ * @param pDeviceErrorString The error string corresponding to the ErrorCode
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceErrorString(
+ uint8_t ErrorCode, char *pDeviceErrorString);
+
+/**
+ * @brief Human readable error string for current PAL error status
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param PalErrorCode The error code as stored on @a int8_t
+ * @param pPalErrorString The error string corresponding to the
+ * PalErrorCode
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetPalErrorString(int8_t PalErrorCode,
+ char *pPalErrorString);
+
+/**
+ * @brief Human readable PAL State string
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param PalStateCode The State code as stored on @a uint8_t
+ * @param pPalStateString The State string corresponding to the
+ * PalStateCode
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetPalStateString(uint8_t PalStateCode,
+ char *pPalStateString);
+
+/**
+ * @brief Reads the internal state of the PAL for a given Device
+ *
+ * @note This function doesn't access to the device
+ *
+ * @param Dev Device Handle
+ * @param pPalState Pointer to current state of the PAL for a
+ * given Device
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetPalState(struct vl_data *Dev,
+ uint8_t *pPalState);
+
+/**
+ * @brief Set the power mode for a given Device
+ * The power mode can be Standby or Idle. Different level of both Standby and
+ * Idle can exists.
+ * This function should not be used when device is in Ranging state.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param PowerMode The value of the power mode to set.
+ * see ::uint8_t
+ * Valid values are:
+ * VL_POWERMODE_STANDBY_LEVEL1,
+ * VL_POWERMODE_IDLE_LEVEL1
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when PowerMode
+ * is not in the supported list
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetPowerMode(struct vl_data *Dev,
+ uint8_t PowerMode);
+
+/**
+ * @brief Get the power mode for a given Device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pPowerMode Pointer to the current value of the power
+ * mode. see ::uint8_t
+ * Valid values are:
+ * VL_POWERMODE_STANDBY_LEVEL1,
+ * VL_POWERMODE_IDLE_LEVEL1
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetPowerMode(struct vl_data *Dev,
+ uint8_t *pPowerMode);
+
+/**
+ * Set or over-hide part to part calibration offset
+ * \sa VL_DataInit() VL_GetOffsetCalibrationDataMicroMeter()
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param OffsetCalibrationDataMicroMeter Offset (microns)
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetOffsetCalibrationDataMicroMeter(
+ struct vl_data *Dev, int32_t OffsetCalibrationDataMicroMeter);
+
+/**
+ * @brief Get part to part calibration offset
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pOffsetCalibrationDataMicroMeter Return part to part
+ * calibration offset from device (microns)
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetOffsetCalibrationDataMicroMeter(
+ struct vl_data *Dev, int32_t *pOffsetCalibrationDataMicroMeter);
+
+/**
+ * Set the linearity corrective gain
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LinearityCorrectiveGain Linearity corrective
+ * gain in x1000
+ * if value is 1000 then no modification is applied.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev,
+ int16_t LinearityCorrectiveGain);
+
+/**
+ * @brief Get the linearity corrective gain
+ *
+ * @par Function Description
+ * Should only be used after a successful call to @a VL_DataInit to backup
+ * device NVM value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pLinearityCorrectiveGain Pointer to the linearity
+ * corrective gain in x1000
+ * if value is 1000 then no modification is applied.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev,
+ uint16_t *pLinearityCorrectiveGain);
+
+/**
+ * Set Group parameter Hold state
+ *
+ * @par Function Description
+ * Set or remove device internal group parameter hold
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param GroupParamHold Group parameter Hold state to be set (on/off)
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_SetGroupParamHold(struct vl_data *Dev,
+ uint8_t GroupParamHold);
+
+/**
+ * @brief Get the maximal distance for actual setup
+ * @par Function Description
+ * Device must be initialized through @a VL_SetParameters() prior calling
+ * this function.
+ *
+ * Any range value more than the value returned is to be considered as
+ * "no target detected" or
+ * "no target in detectable range"\n
+ * @warning The maximal distance depends on the setup
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pUpperLimitMilliMeter The maximal range limit for actual setup
+ * (in millimeter)
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev,
+ uint16_t *pUpperLimitMilliMeter);
+
+
+/**
+ * @brief Get the Total Signal Rate
+ * @par Function Description
+ * This function will return the Total Signal Rate after a good ranging is done.
+ *
+ * @note This function access to Device
+ *
+ * @param Dev Device Handle
+ * @param pTotalSignalRate Total Signal Rate value in Mega count per second
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_GetTotalSignalRate(struct vl_data *Dev,
+ unsigned int *pTotalSignalRate);
+
+/** @} VL_general_group */
+
+/** @defgroup VL_init_group VL53L0X Init Functions
+ * @brief VL53L0X Init Functions
+ * @{
+ */
+
+/**
+ * @brief Set new device address
+ *
+ * After completion the device will answer to the new address programmed.
+ * This function should be called when several devices are used in parallel
+ * before start programming the sensor.
+ * When a single device us used, there is no need to call this function.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param DeviceAddress The new Device address
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetDeviceAddress(struct vl_data *Dev,
+ uint8_t DeviceAddress);
+
+/**
+ *
+ * @brief One time device initialization
+ *
+ * To be called once and only once after device is brought out of reset
+ * (Chip enable) and booted see @a VL_WaitDeviceBooted()
+ *
+ * @par Function Description
+ * When not used after a fresh device "power up" or reset, it may return
+ * @a #VL_ERROR_CALIBRATION_WARNING meaning wrong calibration data
+ * may have been fetched from device that can result in ranging offset error\n
+ * If application cannot execute device reset or need to run VL_DataInit
+ * multiple time then it must ensure proper offset calibration saving and
+ * restore on its own by using @a VL_GetOffsetCalibrationData() on first
+ * power up and then @a VL_SetOffsetCalibrationData() in all subsequent
+ * init.
+ * This function will change the uint8_t from VL_STATE_POWERDOWN to
+ * VL_STATE_WAIT_STATICINIT.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_DataInit(struct vl_data *Dev);
+
+/**
+ * @brief Set the tuning settings pointer
+ *
+ * This function is used to specify the Tuning settings buffer to be used
+ * for a given device. The buffer contains all the necessary data to permit
+ * the API to write tuning settings.
+ * This function permit to force the usage of either external or internal
+ * tuning settings.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pTuningSettingBuffer Pointer to tuning settings buffer.
+ * @param UseInternalTuningSettings Use internal tuning settings value.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev,
+ uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings);
+
+/**
+ * @brief Get the tuning settings pointer and the internal external switch
+ * value.
+ *
+ * This function is used to get the Tuning settings buffer pointer and the
+ * value.
+ * of the switch to select either external or internal tuning settings.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param ppTuningSettingBuffer Pointer to tuning settings buffer.
+ * @param pUseInternalTuningSettings Pointer to store Use internal tuning
+ * settings value.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev,
+ uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings);
+
+/**
+ * @brief Do basic device init (and eventually patch loading)
+ * This function will change the uint8_t from
+ * VL_STATE_WAIT_STATICINIT to VL_STATE_IDLE.
+ * In this stage all default setting will be applied.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_StaticInit(struct vl_data *Dev);
+
+/**
+ * @brief Wait for device booted after chip enable (hardware standby)
+ * This function can be run only when uint8_t is VL_STATE_POWERDOWN.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ *
+ */
+VL_API int8_t VL_WaitDeviceBooted(struct vl_data *Dev);
+
+/**
+ * @brief Do an hard reset or soft reset (depending on implementation) of the
+ * device \nAfter call of this function, device must be in same state as right
+ * after a power-up sequence.This function will change the uint8_t to
+ * VL_STATE_POWERDOWN.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_ResetDevice(struct vl_data *Dev);
+
+/** @} VL_init_group */
+
+/** @defgroup VL_parameters_group VL53L0X Parameters Functions
+ * @brief Functions used to prepare and setup the device
+ * @{
+ */
+
+/**
+ * @brief Prepare device for operation
+ * @par Function Description
+ * Update device with provided parameters
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceParameters Pointer to store current device parameters.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetDeviceParameters(struct vl_data *Dev,
+ const struct VL_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief Retrieve current device parameters
+ * @par Function Description
+ * Get actual parameters of the device
+ * @li Then start ranging operation.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceParameters Pointer to store current device parameters.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetDeviceParameters(struct vl_data *Dev,
+ struct VL_DeviceParameters_t *pDeviceParameters);
+
+/**
+ * @brief Set a new device mode
+ * @par Function Description
+ * Set device to a new mode (ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode New device mode to apply
+ * Valid values are:
+ * VL_DEVICEMODE_SINGLE_RANGING
+ * VL_DEVICEMODE_CONTINUOUS_RANGING
+ * VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * VL_DEVICEMODE_SINGLE_HISTOGRAM
+ * VL_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL_HISTOGRAMMODE_RETURN_ONLY
+ * VL_HISTOGRAMMODE_BOTH
+ *
+ *
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when DeviceMode is
+ * not in the supported list
+ */
+VL_API int8_t VL_SetDeviceMode(struct vl_data *Dev,
+ uint8_t DeviceMode);
+
+/**
+ * @brief Get current new device mode
+ * @par Function Description
+ * Get actual mode of the device(ranging, histogram ...)
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pDeviceMode Pointer to current apply mode value
+ * Valid values are:
+ * VL_DEVICEMODE_SINGLE_RANGING
+ * VL_DEVICEMODE_CONTINUOUS_RANGING
+ * VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING
+ * VL_DEVICEMODE_SINGLE_HISTOGRAM
+ * VL_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL_HISTOGRAMMODE_RETURN_ONLY
+ * VL_HISTOGRAMMODE_BOTH
+ *
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode is not in the supported list
+ */
+VL_API int8_t VL_GetDeviceMode(struct vl_data *Dev,
+ uint8_t *pDeviceMode);
+
+/**
+ * @brief Sets the resolution of range measurements.
+ * @par Function Description
+ * Set resolution of range measurements to either 0.25mm if
+ * fraction enabled or 1mm if not enabled.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param Enable Enable high resolution
+ *
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetRangeFractionEnable(struct vl_data *Dev,
+ uint8_t Enable);
+
+/**
+ * @brief Gets the fraction enable parameter indicating the resolution of
+ * range measurements.
+ *
+ * @par Function Description
+ * Gets the fraction enable state, which translates to the resolution of
+ * range measurements as follows :Enabled:=0.25mm resolution,
+ * Not Enabled:=1mm resolution.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param pEnable Output Parameter reporting the fraction enable state.
+ *
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetFractionEnable(struct vl_data *Dev,
+ uint8_t *pEnable);
+
+/**
+ * @brief Set a new Histogram mode
+ * @par Function Description
+ * Set device to a new Histogram mode
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param HistogramMode New device mode to apply
+ * Valid values are:
+ * VL_HISTOGRAMMODE_DISABLED
+ * struct vl_data *ICEMODE_SINGLE_HISTOGRAM
+ * VL_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL_HISTOGRAMMODE_RETURN_ONLY
+ * VL_HISTOGRAMMODE_BOTH
+ *
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * HistogramMode is not in the supported list
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetHistogramMode(struct vl_data *Dev,
+ uint8_t HistogramMode);
+
+/**
+ * @brief Get current new device mode
+ * @par Function Description
+ * Get current Histogram mode of a Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMode Pointer to current Histogram Mode value
+ * Valid values are:
+ * VL_HISTOGRAMMODE_DISABLED
+ * struct vl_data *ICEMODE_SINGLE_HISTOGRAM
+ * VL_HISTOGRAMMODE_REFERENCE_ONLY
+ * VL_HISTOGRAMMODE_RETURN_ONLY
+ * VL_HISTOGRAMMODE_BOTH
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetHistogramMode(struct vl_data *Dev,
+ uint8_t *pHistogramMode);
+
+/**
+ * @brief Set Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Defines the maximum time allowed by the user to the device to run a
+ * full ranging sequence for the current mode (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param MeasurementTimingBudgetMicroSeconds Max measurement time in
+ * microseconds.
+ * Valid values are:
+ * >= 17000 microsecs when wraparound enabled
+ * >= 12000 microsecs when wraparound disabled
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned if
+ MeasurementTimingBudgetMicroSeconds out of range
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetMeasurementTimingBudgetMicroSeconds(
+ struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Get Ranging Timing Budget in microseconds
+ *
+ * @par Function Description
+ * Returns the programmed the maximum time allowed by the user to the
+ * device to run a full ranging sequence for the current mode
+ * (ranging, histogram, ASL ...)
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in
+ * microseconds.
+ * Valid values are:
+ * >= 17000 microsecs when wraparound enabled
+ * >= 12000 microsecs when wraparound disabled
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetMeasurementTimingBudgetMicroSeconds(
+ struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+/**
+ * @brief Gets the VCSEL pulse period.
+ *
+ * @par Function Description
+ * This function retrieves the VCSEL pulse period for the given period type.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param VcselPeriodType VCSEL period identifier (pre-range|final).
+ * @param pVCSELPulsePeriod Pointer to VCSEL period value.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not
+ * supported.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriod);
+
+/**
+ * @brief Sets the VCSEL pulse period.
+ *
+ * @par Function Description
+ * This function retrieves the VCSEL pulse period for the given period type.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param VcselPeriodType VCSEL period identifier (pre-range|final).
+ * @param VCSELPulsePeriod VCSEL period value
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not
+ * supported.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t VCSELPulsePeriod);
+
+/**
+ * @brief Sets the (on/off) state of a requested sequence step.
+ *
+ * @par Function Description
+ * This function enables/disables a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param SequenceStepEnabled Demanded state {0=Off,1=On}
+ * is enabled.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetSequenceStepEnable(struct vl_data *Dev,
+ uint8_t SequenceStepId, uint8_t SequenceStepEnabled);
+
+/**
+ * @brief Gets the (on/off) state of a requested sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the state of a requested sequence step, i.e. on/off.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param pSequenceStepEnabled Out parameter reporting if the sequence step
+ * is enabled {0=Off,1=On}.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepEnable(struct vl_data *Dev,
+ uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled);
+
+/**
+ * @brief Gets the (on/off) state of all sequence steps.
+ *
+ * @par Function Description
+ * This function retrieves the state of all sequence step in the scheduler.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param pSchedulerSequenceSteps Pointer to struct containing result.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepEnables(struct vl_data *Dev,
+ struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps);
+
+/**
+ * @brief Sets the timeout of a requested sequence step.
+ *
+ * @par Function Description
+ * This function sets the timeout of a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param TimeOutMilliSecs Demanded timeout
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev,
+ uint8_t SequenceStepId, unsigned int TimeOutMilliSecs);
+
+/**
+ * @brief Gets the timeout of a requested sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the timeout of a requested sequence step.
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param SequenceStepId Sequence step identifier.
+ * @param pTimeOutMilliSecs Timeout value.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not
+ * supported.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ unsigned int *pTimeOutMilliSecs);
+
+/**
+ * @brief Gets number of sequence steps managed by the API.
+ *
+ * @par Function Description
+ * This function retrieves the number of sequence steps currently managed
+ * by the API
+ *
+ * @note This function Accesses the device
+ *
+ * @param Dev Device Handle
+ * @param pNumberOfSequenceSteps Out parameter reporting the number of
+ * sequence steps.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev,
+ uint8_t *pNumberOfSequenceSteps);
+
+/**
+ * @brief Gets the name of a given sequence step.
+ *
+ * @par Function Description
+ * This function retrieves the name of sequence steps corresponding to
+ * SequenceStepId.
+ *
+ * @note This function doesn't Accesses the device
+ *
+ * @param SequenceStepId Sequence step identifier.
+ * @param pSequenceStepsString Pointer to Info string
+ *
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetSequenceStepsInfo(
+ uint8_t SequenceStepId, char *pSequenceStepsString);
+
+/**
+ * Program continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetInterMeasurementPeriodMilliSeconds(
+ struct vl_data *Dev, uint32_t InterMeasurementPeriodMilliSeconds);
+
+/**
+ * Get continuous mode Inter-Measurement period in milliseconds
+ *
+ * @par Function Description
+ * When trying to set too short time return INVALID_PARAMS minimal value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed
+ * Inter-Measurement Period in milliseconds.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetInterMeasurementPeriodMilliSeconds(
+ struct vl_data *Dev, uint32_t *pInterMeasurementPeriodMilliSeconds);
+
+/**
+ * @brief Enable/Disable Cross talk compensation feature
+ *
+ * @note This function is not Implemented.
+ * Enable/Disable Cross Talk by set to zero the Cross Talk value
+ * by using @a VL_SetXTalkCompensationRateMegaCps().
+ *
+ * @param Dev Device Handle
+ * @param XTalkCompensationEnable Cross talk compensation
+ * to be set 0=disabled else = enabled
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev,
+ uint8_t XTalkCompensationEnable);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @note This function is not Implemented.
+ * Enable/Disable Cross Talk by set to zero the Cross Talk value by
+ * using @a VL_SetXTalkCompensationRateMegaCps().
+ *
+ * @param Dev Device Handle
+ * @param pXTalkCompensationEnable Pointer to the Cross talk compensation
+ * state 0=disabled or 1 = enabled
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev,
+ uint8_t *pXTalkCompensationEnable);
+
+/**
+ * @brief Set Cross talk compensation rate
+ *
+ * @par Function Description
+ * Set Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param XTalkCompensationRateMegaCps Compensation rate in
+ * Mega counts per second (16.16 fix point) see datasheet for details
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetXTalkCompensationRateMegaCps(
+ struct vl_data *Dev, unsigned int XTalkCompensationRateMegaCps);
+
+/**
+ * @brief Get Cross talk compensation rate
+ *
+ * @par Function Description
+ * Get Cross talk compensation rate.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pXTalkCompensationRateMegaCps Pointer to Compensation rate
+ in Mega counts per second (16.16 fix point) see datasheet for details
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetXTalkCompensationRateMegaCps(
+ struct vl_data *Dev, unsigned int *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Set Reference Calibration Parameters
+ *
+ * @par Function Description
+ * Set Reference Calibration Parameters.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param VhvSettings Parameter for VHV
+ * @param PhaseCal Parameter for PhaseCal
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetRefCalibration(struct vl_data *Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal);
+
+/**
+ * @brief Get Reference Calibration Parameters
+ *
+ * @par Function Description
+ * Get Reference Calibration Parameters.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pVhvSettings Pointer to VHV parameter
+ * @param pPhaseCal Pointer to PhaseCal Parameter
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetRefCalibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+/**
+ * @brief Get the number of the check limit managed by a given Device
+ *
+ * @par Function Description
+ * This function give the number of the check limit managed by the Device
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param pNumberOfLimitCheck Pointer to the number of check limit.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetNumberOfLimitCheck(
+ uint16_t *pNumberOfLimitCheck);
+
+/**
+ * @brief Return a description string for a given limit check number
+ *
+ * @par Function Description
+ * This function returns a description string for a given limit check number.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckString Pointer to the
+ description string of the given check limit.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is
+ returned when LimitCheckId value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckInfo(struct vl_data *Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString);
+
+/**
+ * @brief Return a the Status of the specified check limit
+ *
+ * @par Function Description
+ * This function returns the Status of the specified check limit.
+ * The value indicate if the check is fail or not.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckStatus Pointer to the
+ Limit Check Status of the given check limit.
+ * LimitCheckStatus :
+ * 0 the check is not fail
+ * 1 the check if fail or not enabled
+ *
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is
+ returned when LimitCheckId value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckStatus(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckStatus);
+
+/**
+ * @brief Enable/Disable a specific limit check
+ *
+ * @par Function Description
+ * This function Enable/Disable a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param LimitCheckEnable if 1 the check limit
+ * corresponding to LimitCheckId is Enabled
+ * if 0 the check limit
+ * corresponding to LimitCheckId is disabled
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned
+ * when LimitCheckId value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetLimitCheckEnable(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t LimitCheckEnable);
+
+/**
+ * @brief Get specific limit check enable state
+ *
+ * @par Function Description
+ * This function get the enable state of a specific limit check.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckEnable Pointer to the check limit enable
+ * value.
+ * if 1 the check limit
+ * corresponding to LimitCheckId is Enabled
+ * if 0 the check limit
+ * corresponding to LimitCheckId is disabled
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned
+ * when LimitCheckId value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckEnable(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+
+/**
+ * @brief Set a specific limit check value
+ *
+ * @par Function Description
+ * This function set a specific limit check value.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param LimitCheckValue Limit check Value for a given
+ * LimitCheckId
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned when either
+ * LimitCheckId or LimitCheckValue value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetLimitCheckValue(struct vl_data *Dev,
+ uint16_t LimitCheckId, unsigned int LimitCheckValue);
+
+/**
+ * @brief Get a specific limit check value
+ *
+ * @par Function Description
+ * This function get a specific limit check value from device then it updates
+ * internal values and check enables.
+ * The limit check is identified with the LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckValue Pointer to Limit
+ * check Value for a given LimitCheckId.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned
+ * when LimitCheckId value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckValue(struct vl_data *Dev,
+ uint16_t LimitCheckId, unsigned int *pLimitCheckValue);
+
+/**
+ * @brief Get the current value of the signal used for the limit check
+ *
+ * @par Function Description
+ * This function get a the current value of the signal used for the limit check.
+ * To obtain the latest value you should run a ranging before.
+ * The value reported is linked to the limit check identified with the
+ * LimitCheckId.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param LimitCheckId Limit Check ID
+ * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ).
+ * @param pLimitCheckCurrent Pointer to current Value for a
+ * given LimitCheckId.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned when
+ * LimitCheckId value is out of range.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev,
+ uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent);
+
+/**
+ * @brief Enable (or disable) Wrap around Check
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param WrapAroundCheckEnable Wrap around Check to be set
+ * 0=disabled, other = enabled
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev,
+ uint8_t WrapAroundCheckEnable);
+
+/**
+ * @brief Get setup of Wrap around Check
+ *
+ * @par Function Description
+ * This function get the wrapAround check enable parameters
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pWrapAroundCheckEnable Pointer to the Wrap around Check state
+ * 0=disabled or 1 = enabled
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev,
+ uint8_t *pWrapAroundCheckEnable);
+
+/**
+ * @brief Set Dmax Calibration Parameters for a given device
+ * When one of the parameter is zero, this function will get parameter
+ * from NVM.
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param RangeMilliMeter Calibration Distance
+ * @param SignalRateRtnMegaCps Signal rate return read at CalDistance
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetDmaxCalParameters(struct vl_data *Dev,
+ uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps);
+
+/**
+ * @brief Get Dmax Calibration Parameters for a given device
+ *
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pRangeMilliMeter Pointer to Calibration Distance
+ * @param pSignalRateRtnMegaCps Pointer to Signal rate return
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetDmaxCalParameters(struct vl_data *Dev,
+ uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps);
+
+/** @} VL_parameters_group */
+
+/** @defgroup VL_measurement_group VL53L0X Measurement Functions
+ * @brief Functions used for the measurements
+ * @{
+ */
+
+/**
+ * @brief Single shot measurement.
+ *
+ * @par Function Description
+ * Perform simple measurement sequence (Start measure, Wait measure to end,
+ * and returns when measurement is done).
+ * Once function returns, user can get valid data by calling
+ * VL_GetRangingMeasurement or VL_GetHistogramMeasurement
+ * depending on defined measurement mode
+ * User should Clear the interrupt in case this are enabled by using the
+ * function VL_ClearInterruptMask().
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformSingleMeasurement(struct vl_data *Dev);
+
+/**
+ * @brief Perform Reference Calibration
+ *
+ * @details Perform a reference calibration of the Device.
+ * This function should be run from time to time before doing
+ * a ranging measurement.
+ * This function will launch a special ranging measurement, so
+ * if interrupt are enable an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pVhvSettings Pointer to vhv settings parameter.
+ * @param pPhaseCal Pointer to PhaseCal parameter.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformRefCalibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+/**
+ * @brief Perform XTalk Measurement
+ *
+ * @details Measures the current cross talk from glass in front
+ * of the sensor.
+ * This functions performs a histogram measurement and uses the results
+ * to measure the crosstalk. For the function to be successful, there
+ * must be no target in front of the sensor.
+ *
+ * @warning This function is a blocking function
+ *
+ * @warning This function is not supported when the final range
+ * vcsel clock period is set below 10 PCLKS.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param TimeoutMs Histogram measurement duration.
+ * @param pXtalkPerSpad Output parameter containing the crosstalk
+ * measurement result, in MCPS/Spad. Format fixpoint 16:16.
+ * @param pAmbientTooHigh Output parameter which indicate that
+ * pXtalkPerSpad is not good if the Ambient is too high.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS vcsel clock period not supported
+ * for this operation. Must not be less than 10PCLKS.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev,
+ uint32_t TimeoutMs, unsigned int *pXtalkPerSpad,
+ uint8_t *pAmbientTooHigh);
+
+/**
+ * @brief Perform XTalk Calibration
+ *
+ * @details Perform a XTalk calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts
+ * are enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the XTalk compensation
+ * and it will enable the cross talk before exit.
+ * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param XTalkCalDistance XTalkCalDistance value used for the XTalk
+ * computation.
+ * @param pXTalkCompensationRateMegaCps Pointer to new
+ * XTalkCompensation value.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformXTalkCalibration(struct vl_data *Dev,
+ unsigned int XTalkCalDistance,
+ unsigned int *pXTalkCompensationRateMegaCps);
+
+/**
+ * @brief Perform Offset Calibration
+ *
+ * @details Perform a Offset calibration of the Device.
+ * This function will launch a ranging measurement, if interrupts are
+ * enabled an interrupt will be done.
+ * This function will clear the interrupt generated automatically.
+ * This function will program a new value for the Offset calibration value
+ * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD.
+ *
+ * @warning This function is a blocking function
+ *
+ * @note This function Access to the device
+ *
+ * @note This function does not change the device mode.
+ *
+ * @param Dev Device Handle
+ * @param CalDistanceMilliMeter Calibration distance value used for the
+ * offset compensation.
+ * @param pOffsetMicroMeter Pointer to new Offset value computed by the
+ * function.
+ *
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformOffsetCalibration(struct vl_data *Dev,
+ unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter);
+
+/**
+ * @brief Start device measurement
+ *
+ * @details Started measurement will depend on device parameters set through
+ * @a VL_SetParameters()
+ * This is a non-blocking function.
+ * This function will change the uint8_t from VL_STATE_IDLE to
+ * VL_STATE_RUNNING.
+ *
+ * @note This function Access to the device
+ *
+
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when
+ * DeviceMode programmed with @a VL_SetDeviceMode is not in the supported
+ * list:
+ * Supported mode are:
+ * struct vl_data *ICEMODE_SINGLE_RANGING,
+ * struct vl_data *ICEMODE_CONTINUOUS_RANGING,
+ * struct vl_data *ICEMODE_CONTINUOUS_TIMED_RANGING
+ * @return VL_ERROR_TIME_OUT Time out on start measurement
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_StartMeasurement(struct vl_data *Dev);
+
+/**
+ * @brief Stop device measurement
+ *
+ * @details Will set the device in standby mode at end of current measurement\n
+ * Not necessary in single mode as device shall return automatically
+ * in standby mode at end of measurement.
+ * This function will change the uint8_t from
+ * VL_STATE_RUNNING to VL_STATE_IDLE.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_StopMeasurement(struct vl_data *Dev);
+
+/**
+ * @brief Return Measurement Data Ready
+ *
+ * @par Function Description
+ * This function indicate that a measurement data is ready.
+ * This function check if interrupt mode is used then check is done accordingly.
+ * If perform function clear the interrupt, this function will not work,
+ * like in case of @a VL_PerformSingleRangingMeasurement().
+ * The previous function is blocking function, VL_GetMeasurementDataReady
+ * is used for non-blocking capture.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementDataReady Pointer to Measurement Data Ready.
+ * 0=data not ready, 1 = data ready
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetMeasurementDataReady(struct vl_data *Dev,
+ uint8_t *pMeasurementDataReady);
+
+/**
+ * @brief Wait for device ready for a new measurement command.
+ * Blocking function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param MaxLoop Max Number of polling loop (timeout).
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_WaitDeviceReadyForNewMeasurement(
+ struct vl_data *Dev, uint32_t MaxLoop);
+
+/**
+ * @brief Retrieve the Reference Signal after a measurements
+ *
+ * @par Function Description
+ * Get Reference Signal from last successful Ranging measurement
+ * This function return a valid value after that you call the
+ * @a VL_GetRangingMeasurementData().
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMeasurementRefSignal Pointer to the Ref Signal to fill up.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev,
+ unsigned int *pMeasurementRefSignal);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement
+ * @warning USER should take care about @a VL_GetNumberOfROIZones()
+ * before get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data
+ * structure used in the measurement function.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pRangingMeasurementData Pointer to the data structure to fill up.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetRangingMeasurementData(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Retrieve the measurements from device for a given setup
+ *
+ * @par Function Description
+ * Get data from last successful Histogram measurement
+ * @warning USER should take care about @a VL_GetNumberOfROIZones()
+ * before get data.
+ * PAL will fill a NumberOfROIZones times the corresponding data structure
+ * used in the measurement function.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMeasurementData Pointer to the histogram data structure.
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev,
+ struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Performs a single ranging measurement and retrieve the ranging
+ * measurement data
+ *
+ * @par Function Description
+ * This function will change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING with @a VL_SetDeviceMode(),
+ * It performs measurement with @a VL_PerformSingleMeasurement()
+ * It get data from last successful Ranging measurement with
+ * @a VL_GetRangingMeasurementData.
+ * Finally it clear the interrupt with @a VL_ClearInterruptMask().
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param pRangingMeasurementData Pointer to the data structure to fill up.
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformSingleRangingMeasurement(
+ struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+
+/**
+ * @brief Performs a single histogram measurement and retrieve the histogram
+ * measurement data
+ * Is equivalent to VL_PerformSingleMeasurement +
+ * VL_GetHistogramMeasurementData
+ *
+ * @par Function Description
+ * Get data from last successful Ranging measurement.
+ * This function will clear the interrupt in case of these are enabled.
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param pHistogramMeasurementData Pointer to the data structure to fill up.
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_PerformSingleHistogramMeasurement(
+ struct vl_data *Dev,
+ struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+
+/**
+ * @brief Set the number of ROI Zones to be used for a specific Device
+ *
+ * @par Function Description
+ * Set the number of ROI Zones to be used for a specific Device.
+ * The programmed value should be less than the max number of ROI Zones given
+ * with @a VL_GetMaxNumberOfROIZones().
+ * This version of API manage only one zone.
+ *
+ * @param Dev Device Handle
+ * @param NumberOfROIZones Number of ROI Zones to be used for a
+ * specific Device.
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INVALID_PARAMS This error is returned if
+ * NumberOfROIZones != 1
+ */
+VL_API int8_t VL_SetNumberOfROIZones(struct vl_data *Dev,
+ uint8_t NumberOfROIZones);
+
+/**
+ * @brief Get the number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get number of ROI Zones managed by the Device
+ * USER should take care about @a VL_GetNumberOfROIZones()
+ * before get data after a perform measurement.
+ * PAL will fill a NumberOfROIZones times the corresponding data
+ * structure used in the measurement function.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pNumberOfROIZones Pointer to the Number of ROI Zones value.
+ * @return VL_ERROR_NONE Success
+ */
+VL_API int8_t VL_GetNumberOfROIZones(struct vl_data *Dev,
+ uint8_t *pNumberOfROIZones);
+
+/**
+ * @brief Get the Maximum number of ROI Zones managed by the Device
+ *
+ * @par Function Description
+ * Get Maximum number of ROI Zones managed by the Device.
+ *
+ * @note This function doesn't Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pMaxNumberOfROIZones Pointer to the Maximum Number
+ * of ROI Zones value.
+ * @return VL_ERROR_NONE Success
+ */
+VL_API int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev,
+ uint8_t *pMaxNumberOfROIZones);
+
+/** @} VL_measurement_group */
+
+/** @defgroup VL_interrupt_group VL53L0X Interrupt Functions
+ * @brief Functions used for interrupt managements
+ * @{
+ */
+
+/**
+ * @brief Set the configuration of GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param Pin ID of the GPIO Pin
+ * @param Functionality Select Pin functionality.
+ * Refer to ::uint8_t
+ * @param DeviceMode Device Mode associated to the Gpio.
+ * @param Polarity Set interrupt polarity. Active high
+ * or active low see ::uint8_t
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted.
+ * @return VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs
+ * when Functionality programmed is not in the supported list:
+ * Supported value are:
+ * VL_GPIOFUNCTIONALITY_OFF,
+ * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ * VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+ uint8_t DeviceMode, uint8_t Functionality,
+ uint8_t Polarity);
+
+/**
+ * @brief Get current configuration for GPIO pin for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param Pin ID of the GPIO Pin
+ * @param pDeviceMode Pointer to Device Mode associated to the Gpio.
+ * @param pFunctionality Pointer to Pin functionality.
+ * Refer to ::uint8_t
+ * @param pPolarity Pointer to interrupt polarity.
+ * Active high or active low see ::uint8_t
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted.
+ * @return VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs
+ * when Functionality programmed is not in the supported list:
+ * Supported value are:
+ * VL_GPIOFUNCTIONALITY_OFF,
+ * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW,
+ * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH,
+ * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT,
+ * VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+ uint8_t *pDeviceMode,
+ uint8_t *pFunctionality,
+ uint8_t *pPolarity);
+
+/**
+ * @brief Set low and high Interrupt thresholds for a given mode
+ * (ranging, ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Set low and high Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode Device Mode for which change thresholds
+ * @param ThresholdLow Low threshold (mm, lux ..., depending on the mode)
+ * @param ThresholdHigh High threshold (mm, lux ..., depending on the mode)
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetInterruptThresholds(struct vl_data *Dev,
+ uint8_t DeviceMode, unsigned int ThresholdLow,
+ unsigned int ThresholdHigh);
+
+/**
+ * @brief Get high and low Interrupt thresholds for a given mode
+ * (ranging, ALS, ...) for a given device
+ *
+ * @par Function Description
+ * Get high and low Interrupt thresholds for a given mode (ranging, ALS, ...)
+ * for a given device
+ *
+ * @note This function Access to the device
+ *
+ * @note DeviceMode is ignored for the current device
+ *
+ * @param Dev Device Handle
+ * @param DeviceMode Device Mode from which read thresholds
+ * @param pThresholdLow Low threshold (mm, lux ..., depending on the mode)
+ * @param pThresholdHigh High threshold (mm, lux ..., depending on the mode)
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetInterruptThresholds(struct vl_data *Dev,
+ uint8_t DeviceMode, unsigned int *pThresholdLow,
+ unsigned int *pThresholdHigh);
+
+/**
+ * @brief Return device stop completion status
+ *
+ * @par Function Description
+ * Returns stop completiob status.
+ * User shall call this function after a stop command
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pStopStatus Pointer to status variable to update
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetStopCompletedStatus(struct vl_data *Dev,
+ uint32_t *pStopStatus);
+
+
+/**
+ * @brief Clear given system interrupt condition
+ *
+ * @par Function Description
+ * Clear given interrupt(s).
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param InterruptMask Mask of interrupts to clear
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_INTERRUPT_NOT_CLEARED Cannot clear interrupts
+ *
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_ClearInterruptMask(struct vl_data *Dev,
+ uint32_t InterruptMask);
+
+/**
+ * @brief Return device interrupt status
+ *
+ * @par Function Description
+ * Returns currently raised interrupts by the device.
+ * User shall be able to activate/deactivate interrupts through
+ * @a VL_SetGpioConfig()
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pInterruptMaskStatus Pointer to status variable to update
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev,
+ uint32_t *pInterruptMaskStatus);
+
+/**
+ * @brief Configure ranging interrupt reported to system
+ *
+ * @note This function is not Implemented
+ *
+ * @param Dev Device Handle
+ * @param InterruptMask Mask of interrupt to Enable/disable
+ * (0:interrupt disabled or 1: interrupt enabled)
+ * @return VL_ERROR_NOT_IMPLEMENTED Not implemented
+ */
+VL_API int8_t VL_EnableInterruptMask(struct vl_data *Dev,
+ uint32_t InterruptMask);
+
+/** @} VL_interrupt_group */
+
+/** @defgroup VL_SPADfunctions_group VL53L0X SPAD Functions
+ * @brief Functions used for SPAD managements
+ * @{
+ */
+
+/**
+ * @brief Set the SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param SpadAmbientDamperThreshold SPAD Ambient Damper Threshold value
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev,
+ uint16_t SpadAmbientDamperThreshold);
+
+/**
+ * @brief Get the current SPAD Ambient Damper Threshold value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Threshold value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pSpadAmbientDamperThreshold Pointer to programmed
+ * SPAD Ambient Damper Threshold value
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev,
+ uint16_t *pSpadAmbientDamperThreshold);
+
+/**
+ * @brief Set the SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function set the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param SpadAmbientDamperFactor SPAD Ambient Damper Factor value
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev,
+ uint16_t SpadAmbientDamperFactor);
+
+/**
+ * @brief Get the current SPAD Ambient Damper Factor value
+ *
+ * @par Function Description
+ * This function get the SPAD Ambient Damper Factor value
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param pSpadAmbientDamperFactor Pointer to programmed SPAD Ambient
+ * Damper Factor value
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev,
+ uint16_t *pSpadAmbientDamperFactor);
+
+/**
+ * @brief Performs Reference Spad Management
+ *
+ * @par Function Description
+ * The reference SPAD initialization procedure determines the minimum amount
+ * of reference spads to be enables to achieve a target reference signal rate
+ * and should be performed once during initialization.
+ *
+ * @note This function Access to the device
+ *
+ * @note This function change the device mode to
+ * struct vl_data *ICEMODE_SINGLE_RANGING
+ *
+ * @param Dev Device Handle
+ * @param refSpadCount Reports ref Spad Count
+ * @param isApertureSpads Reports if spads are of type
+ * aperture or non-aperture.
+ * 1:=aperture, 0:=Non-Aperture
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_REF_SPAD_INIT Error in the Ref Spad procedure.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_PerformRefSpadManagement(struct vl_data *Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+/**
+ * @brief Applies Reference SPAD configuration
+ *
+ * @par Function Description
+ * This function applies a given number of reference spads, identified as
+ * either Aperture or Non-Aperture.
+ * The requested spad count and type are stored within the device specific
+ * parameters data for access by the host.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param refSpadCount Number of ref spads.
+ * @param isApertureSpads Defines if spads are of type
+ * aperture or non-aperture.
+ * 1:=aperture, 0:=Non-Aperture
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_REF_SPAD_INIT Error in the in the reference
+ * spad configuration.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_SetReferenceSpads(struct vl_data *Dev,
+ uint32_t refSpadCount, uint8_t isApertureSpads);
+
+/**
+ * @brief Retrieves SPAD configuration
+ *
+ * @par Function Description
+ * This function retrieves the current number of applied reference spads
+ * and also their type : Aperture or Non-Aperture.
+ *
+ * @note This function Access to the device
+ *
+ * @param Dev Device Handle
+ * @param refSpadCount Number ref Spad Count
+ * @param isApertureSpads Reports if spads are of type
+ * aperture or non-aperture.
+ * 1:=aperture, 0:=Non-Aperture
+ * @return VL_ERROR_NONE Success
+ * @return VL_ERROR_REF_SPAD_INIT Error in the in the reference
+ * spad configuration.
+ * @return "Other error code" See ::int8_t
+ */
+VL_API int8_t VL_GetReferenceSpads(struct vl_data *Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+/** @} VL_SPADfunctions_group */
+
+/** @} VL_cut11_group */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h
new file mode 100644
index 0000000..5964e0b
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h
@@ -0,0 +1,75 @@
+/*
+ * vl53l0x_api_calibration.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_API_CALIBRATION_H_
+#define _VL_API_CALIBRATION_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int8_t VL_perform_xtalk_calibration(struct vl_data *Dev,
+ unsigned int XTalkCalDistance,
+ unsigned int *pXTalkCompensationRateMegaCps);
+
+int8_t VL_perform_offset_calibration(struct vl_data *Dev,
+ unsigned int CalDistanceMilliMeter,
+ int32_t *pOffsetMicroMeter);
+
+int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev,
+ int32_t OffsetCalibrationDataMicroMeter);
+
+int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter);
+
+int8_t VL_apply_offset_adjustment(struct vl_data *Dev);
+
+int8_t VL_perform_ref_spad_management(struct vl_data *Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+
+int8_t VL_set_reference_spads(struct vl_data *Dev,
+ uint32_t count, uint8_t isApertureSpads);
+
+int8_t VL_get_reference_spads(struct vl_data *Dev,
+ uint32_t *pSpadCount, uint8_t *pIsApertureSpads);
+
+int8_t VL_perform_phase_calibration(struct vl_data *Dev,
+ uint8_t *pPhaseCal, const uint8_t get_data_enable,
+ const uint8_t restore_config);
+
+int8_t VL_perform_ref_calibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable);
+
+int8_t VL_set_ref_calibration(struct vl_data *Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal);
+
+int8_t VL_get_ref_calibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_CALIBRATION_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h
new file mode 100644
index 0000000..ac368cf
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h
@@ -0,0 +1,98 @@
+/*
+ * vl53l0x_api_core.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_API_CORE_H_
+#define _VL_API_CORE_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int8_t VL_reverse_bytes(uint8_t *data, uint32_t size);
+
+int8_t VL_measurement_poll_for_completion(struct vl_data *Dev);
+
+uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks);
+
+uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg);
+
+uint32_t VL_isqrt(uint32_t num);
+
+uint32_t VL_quadrature_sum(uint32_t a, uint32_t b);
+
+int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option);
+
+int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK);
+
+int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK);
+
+uint32_t VL_decode_timeout(uint16_t encoded_timeout);
+
+int8_t get_sequence_step_timeout(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ uint32_t *pTimeOutMicroSecs);
+
+int8_t set_sequence_step_timeout(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ uint32_t TimeOutMicroSecs);
+
+int8_t VL_set_measurement_timing_budget_micro_seconds(
+ struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds);
+
+int8_t VL_get_measurement_timing_budget_micro_seconds(
+ struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds);
+
+int8_t VL_load_tuning_settings(struct vl_data *Dev,
+ uint8_t *pTuningSettingBuffer);
+
+int8_t VL_calc_sigma_estimate(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ unsigned int *pSigmaEstimate, uint32_t *pDmax_mm);
+
+int8_t VL_get_total_xtalk_rate(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ unsigned int *ptotal_xtalk_rate_mcps);
+
+int8_t VL_get_total_signal_rate(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ unsigned int *ptotal_signal_rate_mcps);
+
+int8_t VL_get_pal_range_status(struct vl_data *Dev,
+ uint8_t DeviceRangeStatus,
+ unsigned int SignalRate,
+ uint16_t EffectiveSpadRtnCount,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ uint8_t *pPalRangeStatus);
+
+uint32_t VL_calc_timeout_mclks(struct vl_data *Dev,
+ uint32_t timeout_period_us, uint8_t vcsel_period_pclks);
+
+uint16_t VL_encode_timeout(uint32_t timeout_macro_clks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_CORE_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h
new file mode 100644
index 0000000..e6b48fc
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h
@@ -0,0 +1,37 @@
+/*
+ * vl53l0x_api_ranging.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_API_RANGING_H_
+#define _VL_API_RANGING_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_API_RANGING_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h
new file mode 100644
index 0000000..78a2dcd
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h
@@ -0,0 +1,268 @@
+/*
+ * vl53l0x_api_strings.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#ifndef VL_API_STRINGS_H_
+#define VL_API_STRINGS_H_
+
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int8_t VL_get_device_info(struct vl_data *Dev,
+ struct VL_DeviceInfo_t *pVL_DeviceInfo);
+
+int8_t VL_get_device_error_string(uint8_t ErrorCode,
+ char *pDeviceErrorString);
+
+int8_t VL_get_range_status_string(uint8_t RangeStatus,
+ char *pRangeStatusString);
+
+int8_t VL_get_pal_error_string(int8_t PalErrorCode,
+ char *pPalErrorString);
+
+int8_t VL_get_pal_state_string(uint8_t PalStateCode,
+ char *pPalStateString);
+
+int8_t VL_get_sequence_steps_info(
+ uint8_t SequenceStepId,
+ char *pSequenceStepsString);
+
+int8_t VL_get_limit_check_info(struct vl_data *Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString);
+
+
+#ifdef USE_EMPTY_STRING
+ #define VL_STRING_DEVICE_INFO_NAME ""
+ #define VL_STRING_DEVICE_INFO_NAME_TS0 ""
+ #define VL_STRING_DEVICE_INFO_NAME_TS1 ""
+ #define VL_STRING_DEVICE_INFO_NAME_TS2 ""
+ #define VL_STRING_DEVICE_INFO_NAME_ES1 ""
+ #define VL_STRING_DEVICE_INFO_TYPE ""
+
+ /* PAL ERROR strings */
+ #define VL_STRING_ERROR_NONE ""
+ #define VL_STRING_ERROR_CALIBRATION_WARNING ""
+ #define VL_STRING_ERROR_MIN_CLIPPED ""
+ #define VL_STRING_ERROR_UNDEFINED ""
+ #define VL_STRING_ERROR_INVALID_PARAMS ""
+ #define VL_STRING_ERROR_NOT_SUPPORTED ""
+ #define VL_STRING_ERROR_RANGE_ERROR ""
+ #define VL_STRING_ERROR_TIME_OUT ""
+ #define VL_STRING_ERROR_MODE_NOT_SUPPORTED ""
+ #define VL_STRING_ERROR_BUFFER_TOO_SMALL ""
+ #define VL_STRING_ERROR_GPIO_NOT_EXISTING ""
+ #define VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ""
+ #define VL_STRING_ERROR_CONTROL_INTERFACE ""
+ #define VL_STRING_ERROR_INVALID_COMMAND ""
+ #define VL_STRING_ERROR_DIVISION_BY_ZERO ""
+ #define VL_STRING_ERROR_REF_SPAD_INIT ""
+ #define VL_STRING_ERROR_NOT_IMPLEMENTED ""
+
+ #define VL_STRING_UNKNOWN_ERROR_CODE ""
+
+
+
+ /* Range Status */
+ #define VL_STRING_RANGESTATUS_NONE ""
+ #define VL_STRING_RANGESTATUS_RANGEVALID ""
+ #define VL_STRING_RANGESTATUS_SIGMA ""
+ #define VL_STRING_RANGESTATUS_SIGNAL ""
+ #define VL_STRING_RANGESTATUS_MINRANGE ""
+ #define VL_STRING_RANGESTATUS_PHASE ""
+ #define VL_STRING_RANGESTATUS_HW ""
+
+
+ /* Range Status */
+ #define VL_STRING_STATE_POWERDOWN ""
+ #define VL_STRING_STATE_WAIT_STATICINIT ""
+ #define VL_STRING_STATE_STANDBY ""
+ #define VL_STRING_STATE_IDLE ""
+ #define VL_STRING_STATE_RUNNING ""
+ #define VL_STRING_STATE_UNKNOWN ""
+ #define VL_STRING_STATE_ERROR ""
+
+
+ /* Device Specific */
+ #define VL_STRING_DEVICEERROR_NONE ""
+ #define VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ""
+ #define VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ""
+ #define VL_STRING_DEVICEERROR_NOVHVVALUEFOUND ""
+ #define VL_STRING_DEVICEERROR_MSRCNOTARGET ""
+ #define VL_STRING_DEVICEERROR_SNRCHECK ""
+ #define VL_STRING_DEVICEERROR_RANGEPHASECHECK ""
+ #define VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK ""
+ #define VL_STRING_DEVICEERROR_TCC ""
+ #define VL_STRING_DEVICEERROR_PHASECONSISTENCY ""
+ #define VL_STRING_DEVICEERROR_MINCLIP ""
+ #define VL_STRING_DEVICEERROR_RANGECOMPLETE ""
+ #define VL_STRING_DEVICEERROR_ALGOUNDERFLOW ""
+ #define VL_STRING_DEVICEERROR_ALGOOVERFLOW ""
+ #define VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD ""
+ #define VL_STRING_DEVICEERROR_UNKNOWN ""
+
+ /* Check Enable */
+ #define VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE ""
+ #define VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE ""
+ #define VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP ""
+ #define VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD ""
+
+ /* Sequence Step */
+ #define VL_STRING_SEQUENCESTEP_TCC ""
+ #define VL_STRING_SEQUENCESTEP_DSS ""
+ #define VL_STRING_SEQUENCESTEP_MSRC ""
+ #define VL_STRING_SEQUENCESTEP_PRE_RANGE ""
+ #define VL_STRING_SEQUENCESTEP_FINAL_RANGE ""
+#else
+ #define VL_STRING_DEVICE_INFO_NAME "VL53L0X cut1.0"
+ #define VL_STRING_DEVICE_INFO_NAME_TS0 "VL53L0X TS0"
+ #define VL_STRING_DEVICE_INFO_NAME_TS1 "VL53L0X TS1"
+ #define VL_STRING_DEVICE_INFO_NAME_TS2 "VL53L0X TS2"
+ #define VL_STRING_DEVICE_INFO_NAME_ES1 "VL53L0X ES1 or later"
+ #define VL_STRING_DEVICE_INFO_TYPE "VL53L0X"
+
+ /* PAL ERROR strings */
+ #define VL_STRING_ERROR_NONE \
+ "No Error"
+ #define VL_STRING_ERROR_CALIBRATION_WARNING \
+ "Calibration Warning Error"
+ #define VL_STRING_ERROR_MIN_CLIPPED \
+ "Min clipped error"
+ #define VL_STRING_ERROR_UNDEFINED \
+ "Undefined error"
+ #define VL_STRING_ERROR_INVALID_PARAMS \
+ "Invalid parameters error"
+ #define VL_STRING_ERROR_NOT_SUPPORTED \
+ "Not supported error"
+ #define VL_STRING_ERROR_RANGE_ERROR \
+ "Range error"
+ #define VL_STRING_ERROR_TIME_OUT \
+ "Time out error"
+ #define VL_STRING_ERROR_MODE_NOT_SUPPORTED \
+ "Mode not supported error"
+ #define VL_STRING_ERROR_BUFFER_TOO_SMALL \
+ "Buffer too small"
+ #define VL_STRING_ERROR_GPIO_NOT_EXISTING \
+ "GPIO not existing"
+ #define VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \
+ "GPIO funct not supported"
+ #define VL_STRING_ERROR_INTERRUPT_NOT_CLEARED \
+ "Interrupt not Cleared"
+ #define VL_STRING_ERROR_CONTROL_INTERFACE \
+ "Control Interface Error"
+ #define VL_STRING_ERROR_INVALID_COMMAND \
+ "Invalid Command Error"
+ #define VL_STRING_ERROR_DIVISION_BY_ZERO \
+ "Division by zero Error"
+ #define VL_STRING_ERROR_REF_SPAD_INIT \
+ "Reference Spad Init Error"
+ #define VL_STRING_ERROR_NOT_IMPLEMENTED \
+ "Not implemented error"
+
+ #define VL_STRING_UNKNOWN_ERROR_CODE \
+ "Unknown Error Code"
+
+
+
+ /* Range Status */
+ #define VL_STRING_RANGESTATUS_NONE "No Update"
+ #define VL_STRING_RANGESTATUS_RANGEVALID "Range Valid"
+ #define VL_STRING_RANGESTATUS_SIGMA "Sigma Fail"
+ #define VL_STRING_RANGESTATUS_SIGNAL "Signal Fail"
+ #define VL_STRING_RANGESTATUS_MINRANGE "Min Range Fail"
+ #define VL_STRING_RANGESTATUS_PHASE "Phase Fail"
+ #define VL_STRING_RANGESTATUS_HW "Hardware Fail"
+
+
+ /* Range Status */
+ #define VL_STRING_STATE_POWERDOWN "POWERDOWN State"
+ #define VL_STRING_STATE_WAIT_STATICINIT \
+ "Wait for staticinit State"
+ #define VL_STRING_STATE_STANDBY "STANDBY State"
+ #define VL_STRING_STATE_IDLE "IDLE State"
+ #define VL_STRING_STATE_RUNNING "RUNNING State"
+ #define VL_STRING_STATE_UNKNOWN "UNKNOWN State"
+ #define VL_STRING_STATE_ERROR "ERROR State"
+
+
+ /* Device Specific */
+ #define VL_STRING_DEVICEERROR_NONE "No Update"
+ #define VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \
+ "VCSEL Continuity Test Failure"
+ #define VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \
+ "VCSEL Watchdog Test Failure"
+ #define VL_STRING_DEVICEERROR_NOVHVVALUEFOUND \
+ "No VHV Value found"
+ #define VL_STRING_DEVICEERROR_MSRCNOTARGET \
+ "MSRC No Target Error"
+ #define VL_STRING_DEVICEERROR_SNRCHECK \
+ "SNR Check Exit"
+ #define VL_STRING_DEVICEERROR_RANGEPHASECHECK \
+ "Range Phase Check Error"
+ #define VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK \
+ "Sigma Threshold Check Error"
+ #define VL_STRING_DEVICEERROR_TCC \
+ "TCC Error"
+ #define VL_STRING_DEVICEERROR_PHASECONSISTENCY \
+ "Phase Consistency Error"
+ #define VL_STRING_DEVICEERROR_MINCLIP \
+ "Min Clip Error"
+ #define VL_STRING_DEVICEERROR_RANGECOMPLETE \
+ "Range Complete"
+ #define VL_STRING_DEVICEERROR_ALGOUNDERFLOW \
+ "Range Algo Underflow Error"
+ #define VL_STRING_DEVICEERROR_ALGOOVERFLOW \
+ "Range Algo Overlow Error"
+ #define VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD \
+ "Range Ignore Threshold Error"
+ #define VL_STRING_DEVICEERROR_UNKNOWN \
+ "Unknown error code"
+
+ /* Check Enable */
+ #define VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \
+ "SIGMA FINAL RANGE"
+ #define VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \
+ "SIGNAL RATE FINAL RANGE"
+ #define VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP \
+ "SIGNAL REF CLIP"
+ #define VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \
+ "RANGE IGNORE THRESHOLD"
+ #define VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC \
+ "SIGNAL RATE MSRC"
+ #define VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE \
+ "SIGNAL RATE PRE RANGE"
+
+ /* Sequence Step */
+ #define VL_STRING_SEQUENCESTEP_TCC "TCC"
+ #define VL_STRING_SEQUENCESTEP_DSS "DSS"
+ #define VL_STRING_SEQUENCESTEP_MSRC "MSRC"
+ #define VL_STRING_SEQUENCESTEP_PRE_RANGE "PRE RANGE"
+ #define VL_STRING_SEQUENCESTEP_FINAL_RANGE "FINAL RANGE"
+#endif /* USE_EMPTY_STRING */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h
new file mode 100644
index 0000000..50495a0
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h
@@ -0,0 +1,619 @@
+/*
+ * vl53l0x_def.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * @file VL_def.h
+ *
+ * @brief Type definitions for VL53L0X API.
+ *
+ */
+
+
+#ifndef _VL_DEF_H_
+#define _VL_DEF_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup VL_globaldefine_group VL53L0X Defines
+ * @brief VL53L0X Defines
+ * @{
+ */
+
+
+/** PAL SPECIFICATION major version */
+#define VL53L0X10_SPECIFICATION_VER_MAJOR 1
+/** PAL SPECIFICATION minor version */
+#define VL53L0X10_SPECIFICATION_VER_MINOR 2
+/** PAL SPECIFICATION sub version */
+#define VL53L0X10_SPECIFICATION_VER_SUB 7
+/** PAL SPECIFICATION sub version */
+#define VL53L0X10_SPECIFICATION_VER_REVISION 1440
+
+/** VL53L0X PAL IMPLEMENTATION major version */
+#define VL53L0X10_IMPLEMENTATION_VER_MAJOR 1
+/** VL53L0X PAL IMPLEMENTATION minor version */
+#define VL53L0X10_IMPLEMENTATION_VER_MINOR 0
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL53L0X10_IMPLEMENTATION_VER_SUB 9
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL53L0X10_IMPLEMENTATION_VER_REVISION 3673
+
+/** PAL SPECIFICATION major version */
+#define VL_SPECIFICATION_VER_MAJOR 1
+/** PAL SPECIFICATION minor version */
+#define VL_SPECIFICATION_VER_MINOR 2
+/** PAL SPECIFICATION sub version */
+#define VL_SPECIFICATION_VER_SUB 7
+/** PAL SPECIFICATION sub version */
+#define VL_SPECIFICATION_VER_REVISION 1440
+
+/** VL53L0X PAL IMPLEMENTATION major version */
+#define VL_IMPLEMENTATION_VER_MAJOR 1
+/** VL53L0X PAL IMPLEMENTATION minor version */
+#define VL_IMPLEMENTATION_VER_MINOR 0
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL_IMPLEMENTATION_VER_SUB 2
+/** VL53L0X PAL IMPLEMENTATION sub version */
+#define VL_IMPLEMENTATION_VER_REVISION 4823
+#define VL_DEFAULT_MAX_LOOP 2000
+#define VL_MAX_STRING_LENGTH 32
+
+
+#include "vl53l0x_device.h"
+#include "vl53l0x_types.h"
+
+
+/****************************************
+ * PRIVATE define do not edit
+ ****************************************/
+
+/** @brief Defines the parameters of the Get Version Functions
+ */
+struct VL_Version_t {
+ uint32_t revision; /*!< revision number */
+ uint8_t major; /*!< major number */
+ uint8_t minor; /*!< minor number */
+ uint8_t build; /*!< build number */
+};
+
+
+/** @brief Defines the parameters of the Get Device Info Functions
+ */
+struct VL_DeviceInfo_t {
+ char Name[VL_MAX_STRING_LENGTH];
+ /*!< Name of the Device e.g. Left_Distance */
+ char Type[VL_MAX_STRING_LENGTH];
+ /*!< Type of the Device e.g VL53L0X */
+ char ProductId[VL_MAX_STRING_LENGTH];
+ /*!< Product Identifier String */
+ uint8_t ProductType;
+ /*!< Product Type, VL53L0X = 1, VL53L1 = 2 */
+ uint8_t ProductRevisionMajor;
+ /*!< Product revision major */
+ uint8_t ProductRevisionMinor;
+ /*!< Product revision minor */
+};
+
+
+/** @defgroup VL_define_Error_group Error and Warning code returned by API
+ * The following DEFINE are used to identify the PAL ERROR
+ * @{
+ */
+
+#define VL_ERROR_NONE ((int8_t) 0)
+#define VL_ERROR_CALIBRATION_WARNING ((int8_t) -1)
+ /*!< Warning invalid calibration data may be in used*/
+ /*\a VL_InitData()*/
+ /*\a VL_GetOffsetCalibrationData*/
+ /*\a VL_SetOffsetCalibrationData */
+#define VL_ERROR_MIN_CLIPPED ((int8_t) -2)
+ /*!< Warning parameter passed was clipped to min before to be applied */
+
+#define VL_ERROR_UNDEFINED ((int8_t) -3)
+ /*!< Unqualified error */
+#define VL_ERROR_INVALID_PARAMS ((int8_t) -4)
+ /*!< Parameter passed is invalid or out of range */
+#define VL_ERROR_NOT_SUPPORTED ((int8_t) -5)
+ /*!< Function is not supported in current mode or configuration */
+#define VL_ERROR_RANGE_ERROR ((int8_t) -6)
+ /*!< Device report a ranging error interrupt status */
+#define VL_ERROR_TIME_OUT ((int8_t) -7)
+ /*!< Aborted due to time out */
+#define VL_ERROR_MODE_NOT_SUPPORTED ((int8_t) -8)
+ /*!< Asked mode is not supported by the device */
+#define VL_ERROR_BUFFER_TOO_SMALL ((int8_t) -9)
+ /*!< ... */
+#define VL_ERROR_GPIO_NOT_EXISTING ((int8_t) -10)
+ /*!< User tried to setup a non-existing GPIO pin */
+#define VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((int8_t) -11)
+ /*!< unsupported GPIO functionality */
+#define VL_ERROR_INTERRUPT_NOT_CLEARED ((int8_t) -12)
+ /*!< Error during interrupt clear */
+#define VL_ERROR_CONTROL_INTERFACE ((int8_t) -20)
+ /*!< error reported from IO functions */
+#define VL_ERROR_INVALID_COMMAND ((int8_t) -30)
+ /*!< The command is not allowed in the current device state*/
+ /* * (power down) */
+#define VL_ERROR_DIVISION_BY_ZERO ((int8_t) -40)
+ /*!< In the function a division by zero occurs */
+#define VL_ERROR_REF_SPAD_INIT ((int8_t) -50)
+ /*!< Error during reference SPAD initialization */
+#define VL_ERROR_NOT_IMPLEMENTED ((int8_t) -99)
+ /*!< Tells requested functionality has not been implemented yet or*/
+ /* * not compatible with the device */
+/** @} VL_define_Error_group */
+
+
+/** @defgroup VL_define_DeviceModes_group Defines Device modes
+ * Defines all possible modes for the device
+ * @{
+ */
+
+#define VL_DEVICEMODE_SINGLE_RANGING ((uint8_t) 0)
+#define VL_DEVICEMODE_CONTINUOUS_RANGING ((uint8_t) 1)
+#define VL_DEVICEMODE_SINGLE_HISTOGRAM ((uint8_t) 2)
+#define VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING ((uint8_t) 3)
+#define VL_DEVICEMODE_SINGLE_ALS ((uint8_t) 10)
+#define VL_DEVICEMODE_GPIO_DRIVE ((uint8_t) 20)
+#define VL_DEVICEMODE_GPIO_OSC ((uint8_t) 21)
+ /* ... Modes to be added depending on device */
+/** @} VL_define_DeviceModes_group */
+
+
+
+/** @defgroup VL_define_HistogramModes_group Defines Histogram modes
+ * Defines all possible Histogram modes for the device
+ * @{
+ */
+
+#define VL_HISTOGRAMMODE_DISABLED ((uint8_t) 0)
+ /*!< Histogram Disabled */
+#define VL_HISTOGRAMMODE_REFERENCE_ONLY ((uint8_t) 1)
+ /*!< Histogram Reference array only */
+#define VL_HISTOGRAMMODE_RETURN_ONLY ((uint8_t) 2)
+ /*!< Histogram Return array only */
+#define VL_HISTOGRAMMODE_BOTH ((uint8_t) 3)
+ /*!< Histogram both Reference and Return Arrays */
+ /* ... Modes to be added depending on device */
+/** @} VL_define_HistogramModes_group */
+
+
+/** @defgroup VL_define_PowerModes_group List of available Power Modes
+ * List of available Power Modes
+ * @{
+ */
+
+#define VL_POWERMODE_STANDBY_LEVEL1 ((uint8_t) 0)
+ /*!< Standby level 1 */
+#define VL_POWERMODE_STANDBY_LEVEL2 ((uint8_t) 1)
+ /*!< Standby level 2 */
+#define VL_POWERMODE_IDLE_LEVEL1 ((uint8_t) 2)
+ /*!< Idle level 1 */
+#define VL_POWERMODE_IDLE_LEVEL2 ((uint8_t) 3)
+ /*!< Idle level 2 */
+
+/** @} VL_define_PowerModes_group */
+
+
+/** @brief Defines all parameters for the device
+ */
+struct VL_DeviceParameters_t {
+ uint8_t DeviceMode;
+ /*!< Defines type of measurement to be done for the next measure */
+ uint8_t HistogramMode;
+ /*!< Defines type of histogram measurement to be done for the next*/
+ /* * measure */
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+ /*!< Defines the allowed total time for a single measurement */
+ uint32_t InterMeasurementPeriodMilliSeconds;
+ /*!< Defines time between two consecutive measurements (between two*/
+ /* * measurement starts). If set to 0 means back-to-back mode */
+ uint8_t XTalkCompensationEnable;
+ /*!< Tells if Crosstalk compensation shall be enable or not */
+ uint16_t XTalkCompensationRangeMilliMeter;
+ /*!< CrossTalk compensation range in millimeter */
+ unsigned int XTalkCompensationRateMegaCps;
+ /*!< CrossTalk compensation rate in Mega counts per seconds.*/
+ /* * Expressed in 16.16 fixed point format. */
+ int32_t RangeOffsetMicroMeters;
+ /*!< Range offset adjustment (mm). */
+
+ uint8_t LimitChecksEnable[VL_CHECKENABLE_NUMBER_OF_CHECKS];
+ /*!< This Array store all the Limit Check enable for this device. */
+ uint8_t LimitChecksStatus[VL_CHECKENABLE_NUMBER_OF_CHECKS];
+ /*!< This Array store all the Status of the check linked to last*/
+ /** measurement. */
+ unsigned int LimitChecksValue[VL_CHECKENABLE_NUMBER_OF_CHECKS];
+ /*!< This Array store all the Limit Check value for this device */
+
+ uint8_t WrapAroundCheckEnable;
+ /*!< Tells if Wrap Around Check shall be enable or not */
+};
+
+
+/** @defgroup VL_define_State_group Defines the current status
+ * of the device Defines the current status of the device
+ * @{
+ */
+
+#define VL_STATE_POWERDOWN ((uint8_t) 0)
+ /*!< Device is in HW reset */
+#define VL_STATE_WAIT_STATICINIT ((uint8_t) 1)
+ /*!< Device is initialized and wait for static initialization */
+#define VL_STATE_STANDBY ((uint8_t) 2)
+ /*!< Device is in Low power Standby mode */
+#define VL_STATE_IDLE ((uint8_t) 3)
+ /*!< Device has been initialized and ready to do measurements */
+#define VL_STATE_RUNNING ((uint8_t) 4)
+ /*!< Device is performing measurement */
+#define VL_STATE_UNKNOWN ((uint8_t) 98)
+ /*!< Device is in unknown state and need to be rebooted */
+#define VL_STATE_ERROR ((uint8_t) 99)
+ /*!< Device is in error state and need to be rebooted */
+
+/** @} VL_define_State_group */
+
+
+/** @brief Structure containing the Dmax computation parameters and data
+ */
+struct VL_DMaxData_t {
+ int32_t AmbTuningWindowFactor_K;
+ /*!< internal algo tuning (*1000) */
+ int32_t RetSignalAt0mm;
+ /*!< intermediate dmax computation value caching */
+};
+
+/**
+ * @struct VL_RangeData_t
+ * @brief Range measurement data.
+ */
+struct VL_RangingMeasurementData_t {
+ uint32_t TimeStamp; /*!< 32-bit time stamp. */
+ uint32_t MeasurementTimeUsec;
+ /*!< Give the Measurement time needed by the device to do the */
+ /** measurement.*/
+
+
+ uint16_t RangeMilliMeter; /*!< range distance in millimeter. */
+
+ uint16_t RangeDMaxMilliMeter;
+ /*!< Tells what is the maximum detection distance of */
+ /* the device */
+ /* * in current setup and environment conditions (Filled when */
+ /* * applicable) */
+
+ unsigned int SignalRateRtnMegaCps;
+ /*!< Return signal rate (MCPS)\n these is a 16.16 fix point */
+ /* * value, which is effectively a measure of target */
+ /* * reflectance.*/
+ unsigned int AmbientRateRtnMegaCps;
+ /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point */
+ /* * value, which is effectively a measure of the ambien */
+ /* * t light.*/
+
+ uint16_t EffectiveSpadRtnCount;
+ /*!< Return the effective SPAD count for the return signal. */
+ /* * To obtain Real value it should be divided by 256 */
+
+ uint8_t ZoneId;
+ /*!< Denotes which zone and range scheduler stage the range */
+ /* * data relates to. */
+ uint8_t RangeFractionalPart;
+ /*!< Fractional part of range distance. Final value is a */
+ /* * FixPoint168 value. */
+ uint8_t RangeStatus;
+ /*!< Range Status for the current measurement. This is device */
+ /* * dependent. Value = 0 means value is valid. */
+ /* * See \ref RangeStatusPage */
+};
+
+
+#define VL_HISTOGRAM_BUFFER_SIZE 24
+
+/**
+ * @struct VL_HistogramData_t
+ * @brief Histogram measurement data.
+ */
+struct VL_HistogramMeasurementData_t {
+ /* Histogram Measurement data */
+ uint32_t HistogramData[VL_HISTOGRAM_BUFFER_SIZE];
+ /*!< Histogram data */
+ uint8_t HistogramType; /*!< Indicate the types of histogram data : */
+ /*Return only, Reference only, both Return and Reference */
+ uint8_t FirstBin; /*!< First Bin value */
+ uint8_t BufferSize; /*!< Buffer Size - Set by the user.*/
+ uint8_t NumberOfBins;
+ /*!< Number of bins filled by the histogram measurement */
+
+ uint8_t ErrorStatus;
+ /*!< Error status of the current measurement. \n */
+ /* see @a ::uint8_t @a VL_GetStatusErrorString() */
+};
+
+#define VL_REF_SPAD_BUFFER_SIZE 6
+
+/**
+ * @struct VL_SpadData_t
+ * @brief Spad Configuration Data.
+ */
+struct VL_SpadData_t {
+ uint8_t RefSpadEnables[VL_REF_SPAD_BUFFER_SIZE];
+ /*!< Reference Spad Enables */
+ uint8_t RefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE];
+ /*!< Reference Spad Good Spad Map */
+};
+
+struct VL_DeviceSpecificParameters_t {
+ unsigned int OscFrequencyMHz; /* Frequency used */
+
+ uint16_t LastEncodedTimeout;
+ /* last encoded Time out used for timing budget*/
+
+ uint8_t Pin0GpioFunctionality;
+ /* store the functionality of the GPIO: pin0 */
+
+ uint32_t FinalRangeTimeoutMicroSecs;
+ /*!< Execution time of the final range*/
+ uint8_t FinalRangeVcselPulsePeriod;
+ /*!< Vcsel pulse period (pll clocks) for the final range measurement*/
+ uint32_t PreRangeTimeoutMicroSecs;
+ /*!< Execution time of the final range*/
+ uint8_t PreRangeVcselPulsePeriod;
+ /*!< Vcsel pulse period (pll clocks) for the pre-range measurement*/
+
+ uint16_t SigmaEstRefArray;
+ /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */
+ uint16_t SigmaEstEffPulseWidth;
+ /*!< Effective Pulse width for sigma estimate in 1/100th */
+ /* * of ns e.g. 900 = 9.0ns */
+ uint16_t SigmaEstEffAmbWidth;
+ /*!< Effective Ambient width for sigma estimate in 1/100th of ns */
+ /* * e.g. 500 = 5.0ns */
+
+
+ uint8_t ReadDataFromDeviceDone; /* Indicate if read from device has */
+ /*been done (==1) or not (==0) */
+ uint8_t ModuleId; /* Module ID */
+ uint8_t Revision; /* test Revision */
+ char ProductId[VL_MAX_STRING_LENGTH];
+ /* Product Identifier String */
+ uint8_t ReferenceSpadCount; /* used for ref spad management */
+ uint8_t ReferenceSpadType; /* used for ref spad management */
+ uint8_t RefSpadsInitialised; /* reports if ref spads are initialised. */
+ uint32_t PartUIDUpper; /*!< Unique Part ID Upper */
+ uint32_t PartUIDLower; /*!< Unique Part ID Lower */
+ unsigned int SignalRateMeasFixed400mm; /*!< Peek Signal rate at 400 mm*/
+
+};
+
+/**
+ * @struct VL_DevData_t
+ *
+ * @brief VL53L0X PAL device ST private data structure \n
+ * End user should never access any of these field directly
+ *
+ * These must never access directly but only via macro
+ */
+struct VL_DevData_t {
+ struct VL_DMaxData_t DMaxData;
+ /*!< Dmax Data */
+ int32_t Part2PartOffsetNVMMicroMeter;
+ /*!< backed up NVM value */
+ int32_t Part2PartOffsetAdjustmentNVMMicroMeter;
+ /*!< backed up NVM value representing additional offset adjustment */
+ struct VL_DeviceParameters_t CurrentParameters;
+ /*!< Current Device Parameter */
+ struct VL_RangingMeasurementData_t LastRangeMeasure;
+ /*!< Ranging Data */
+ struct VL_HistogramMeasurementData_t LastHistogramMeasure;
+ /*!< Histogram Data */
+ struct VL_DeviceSpecificParameters_t DeviceSpecificParameters;
+ /*!< Parameters specific to the device */
+ struct VL_SpadData_t SpadData;
+ /*!< Spad Data */
+ uint8_t SequenceConfig;
+ /*!< Internal value for the sequence config */
+ uint8_t RangeFractionalEnable;
+ /*!< Enable/Disable fractional part of ranging data */
+ uint8_t PalState;
+ /*!< Current state of the PAL for this device */
+ uint8_t PowerMode;
+ /*!< Current Power Mode */
+ uint16_t SigmaEstRefArray;
+ /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */
+ uint16_t SigmaEstEffPulseWidth;
+ /*!< Effective Pulse width for sigma estimate in 1/100th */
+ /* of ns e.g. 900 = 9.0ns */
+ uint16_t SigmaEstEffAmbWidth;
+ /*!< Effective Ambient width for sigma estimate in 1/100th of ns */
+ /* * e.g. 500 = 5.0ns */
+ uint8_t StopVariable;
+ /*!< StopVariable used during the stop sequence */
+ uint16_t targetRefRate;
+ /*!< Target Ambient Rate for Ref spad management */
+ unsigned int SigmaEstimate;
+ /*!< Sigma Estimate - based on ambient & VCSEL rates and */
+ /** signal_total_events */
+ unsigned int SignalEstimate;
+ /*!< Signal Estimate - based on ambient & VCSEL rates and cross talk */
+ unsigned int LastSignalRefMcps;
+ /*!< Latest Signal ref in Mcps */
+ uint8_t *pTuningSettingsPointer;
+ /*!< Pointer for Tuning Settings table */
+ uint8_t UseInternalTuningSettings;
+ /*!< Indicate if we use Tuning Settings table */
+ uint16_t LinearityCorrectiveGain;
+ /*!< Linearity Corrective Gain value in x1000 */
+ uint16_t DmaxCalRangeMilliMeter;
+ /*!< Dmax Calibration Range millimeter */
+ unsigned int DmaxCalSignalRateRtnMegaCps;
+ /*!< Dmax Calibration Signal Rate Return MegaCps */
+
+};
+
+
+/** @defgroup VL_define_InterruptPolarity_group Defines the Polarity
+ * of the Interrupt
+ * Defines the Polarity of the Interrupt
+ * @{
+ */
+
+#define VL_INTERRUPTPOLARITY_LOW ((uint8_t) 0)
+/*!< Set active low polarity best setup for falling edge. */
+#define VL_INTERRUPTPOLARITY_HIGH ((uint8_t) 1)
+/*!< Set active high polarity best setup for rising edge. */
+
+/** @} VL_define_InterruptPolarity_group */
+
+
+/** @defgroup VL_define_VcselPeriod_group Vcsel Period Defines
+ * Defines the range measurement for which to access the vcsel period.
+ * @{
+ */
+
+#define VL_VCSEL_PERIOD_PRE_RANGE ((uint8_t) 0)
+/*!<Identifies the pre-range vcsel period. */
+#define VL_VCSEL_PERIOD_FINAL_RANGE ((uint8_t) 1)
+/*!<Identifies the final range vcsel period. */
+
+/** @} VL_define_VcselPeriod_group */
+
+/** @defgroup VL_define_SchedulerSequence_group Defines the steps
+ * carried out by the scheduler during a range measurement.
+ * @{
+ * Defines the states of all the steps in the scheduler
+ * i.e. enabled/disabled.
+ */
+struct VL_SchedulerSequenceSteps_t {
+ uint8_t TccOn; /*!<Reports if Target Centre Check On */
+ uint8_t MsrcOn; /*!<Reports if MSRC On */
+ uint8_t DssOn; /*!<Reports if DSS On */
+ uint8_t PreRangeOn; /*!<Reports if Pre-Range On */
+ uint8_t FinalRangeOn; /*!<Reports if Final-Range On */
+};
+
+/** @} VL_define_SchedulerSequence_group */
+
+/** @defgroup VL_define_SequenceStepId_group Defines the Polarity
+ * of the Interrupt
+ * Defines the the sequence steps performed during ranging..
+ * @{
+ */
+
+#define VL_SEQUENCESTEP_TCC ((uint8_t) 0)
+/*!<Target CentreCheck identifier. */
+#define VL_SEQUENCESTEP_DSS ((uint8_t) 1)
+/*!<Dynamic Spad Selection function Identifier. */
+#define VL_SEQUENCESTEP_MSRC ((uint8_t) 2)
+/*!<Minimum Signal Rate Check function Identifier. */
+#define VL_SEQUENCESTEP_PRE_RANGE ((uint8_t) 3)
+/*!<Pre-Range check Identifier. */
+#define VL_SEQUENCESTEP_FINAL_RANGE ((uint8_t) 4)
+/*!<Final Range Check Identifier. */
+
+#define VL_SEQUENCESTEP_NUMBER_OF_CHECKS 5
+/*!<Number of Sequence Step Managed by the API. */
+
+/** @} VL_define_SequenceStepId_group */
+
+
+/* MACRO Definitions */
+/** @defgroup VL_define_GeneralMacro_group General Macro Defines
+ * General Macro Defines
+ * @{
+ */
+
+/* Defines */
+#define VL_SETPARAMETERFIELD(Dev, field, value) \
+ PALDevDataSet(Dev, CurrentParameters.field, value)
+
+#define VL_GETPARAMETERFIELD(Dev, field, variable) \
+ (variable = PALDevDataGet(Dev, CurrentParameters).field)
+
+
+#define VL_SETARRAYPARAMETERFIELD(Dev, field, index, value) \
+ PALDevDataSet(Dev, CurrentParameters.field[index], value)
+
+#define VL_GETARRAYPARAMETERFIELD(Dev, field, index, variable) \
+ (variable = PALDevDataGet(Dev, CurrentParameters).field[index])
+
+
+#define VL_SETDEVICESPECIFICPARAMETER(Dev, field, value) \
+ PALDevDataSet(Dev, DeviceSpecificParameters.field, value)
+
+#define VL_GETDEVICESPECIFICPARAMETER(Dev, field) \
+ PALDevDataGet(Dev, DeviceSpecificParameters).field
+
+
+#define VL_FIXPOINT1616TOFIXPOINT97(Value) \
+ (uint16_t)((Value>>9)&0xFFFF)
+#define VL_FIXPOINT97TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<9)
+
+#define VL_FIXPOINT1616TOFIXPOINT88(Value) \
+ (uint16_t)((Value>>8)&0xFFFF)
+#define VL_FIXPOINT88TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<8)
+
+#define VL_FIXPOINT1616TOFIXPOINT412(Value) \
+ (uint16_t)((Value>>4)&0xFFFF)
+#define VL_FIXPOINT412TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<4)
+
+#define VL_FIXPOINT1616TOFIXPOINT313(Value) \
+ (uint16_t)((Value>>3)&0xFFFF)
+#define VL_FIXPOINT313TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<3)
+
+#define VL_FIXPOINT1616TOFIXPOINT08(Value) \
+ (uint8_t)((Value>>8)&0x00FF)
+#define VL_FIXPOINT08TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<8)
+
+#define VL_FIXPOINT1616TOFIXPOINT53(Value) \
+ (uint8_t)((Value>>13)&0x00FF)
+#define VL_FIXPOINT53TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<13)
+
+#define VL_FIXPOINT1616TOFIXPOINT102(Value) \
+ (uint16_t)((Value>>14)&0x0FFF)
+#define VL_FIXPOINT102TOFIXPOINT1616(Value) \
+ (unsigned int)(Value<<12)
+
+#define VL_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \
+ (uint16_t)lsb)
+
+/** @} VL_define_GeneralMacro_group */
+
+/** @} VL_globaldefine_group */
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _VL_DEF_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h
new file mode 100644
index 0000000..b296ff8
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h
@@ -0,0 +1,246 @@
+/*
+ * vl53l0x_device.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * Device specific defines. To be adapted by implementer for the targeted
+ * device.
+ */
+
+#ifndef _VL_DEVICE_H_
+#define _VL_DEVICE_H_
+
+#include "vl53l0x_types.h"
+
+
+/** @defgroup VL_DevSpecDefines_group VL53L0X cut1.1
+ * Device Specific Defines
+ * @brief VL53L0X cut1.1 Device Specific Defines
+ * @{
+ */
+
+
+/** @defgroup uint8_t_group Device Error
+ * @brief Device Error code
+ *
+ * This enum is Device specific it should be updated in the implementation
+ * Use @a VL_GetStatusErrorString() to get the string.
+ * It is related to Status Register of the Device.
+ * @{
+ */
+
+#define VL_DEVICEERROR_NONE ((uint8_t) 0)
+ /*!< 0 NoError */
+#define VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ((uint8_t) 1)
+#define VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ((uint8_t) 2)
+#define VL_DEVICEERROR_NOVHVVALUEFOUND ((uint8_t) 3)
+#define VL_DEVICEERROR_MSRCNOTARGET ((uint8_t) 4)
+#define VL_DEVICEERROR_SNRCHECK ((uint8_t) 5)
+#define VL_DEVICEERROR_RANGEPHASECHECK ((uint8_t) 6)
+#define VL_DEVICEERROR_SIGMATHRESHOLDCHECK ((uint8_t) 7)
+#define VL_DEVICEERROR_TCC ((uint8_t) 8)
+#define VL_DEVICEERROR_PHASECONSISTENCY ((uint8_t) 9)
+#define VL_DEVICEERROR_MINCLIP ((uint8_t) 10)
+#define VL_DEVICEERROR_RANGECOMPLETE ((uint8_t) 11)
+#define VL_DEVICEERROR_ALGOUNDERFLOW ((uint8_t) 12)
+#define VL_DEVICEERROR_ALGOOVERFLOW ((uint8_t) 13)
+#define VL_DEVICEERROR_RANGEIGNORETHRESHOLD ((uint8_t) 14)
+
+/** @} end of uint8_t_group */
+
+
+/** @defgroup VL_CheckEnable_group Check Enable list
+ * @brief Check Enable code
+ *
+ * Define used to specify the LimitCheckId.
+ * Use @a VL_GetLimitCheckInfo() to get the string.
+ * @{
+ */
+
+#define VL_CHECKENABLE_SIGMA_FINAL_RANGE 0
+#define VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1
+#define VL_CHECKENABLE_SIGNAL_REF_CLIP 2
+#define VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD 3
+#define VL_CHECKENABLE_SIGNAL_RATE_MSRC 4
+#define VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE 5
+
+#define VL_CHECKENABLE_NUMBER_OF_CHECKS 6
+
+/** @} end of VL_CheckEnable_group */
+
+
+/** @defgroup uint8_t_group Gpio Functionality
+ * @brief Defines the different functionalities for the device GPIO(s)
+ * @{
+ */
+
+#define VL_GPIOFUNCTIONALITY_OFF \
+ ((uint8_t) 0) /*!< NO Interrupt */
+#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW \
+ ((uint8_t) 1) /*!< Level Low (value < thresh_low) */
+#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH \
+ ((uint8_t) 2)/*!< Level High (value > thresh_high)*/
+#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT \
+ ((uint8_t) 3)
+ /*!< Out Of Window (value < thresh_low OR value > thresh_high) */
+#define VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY \
+ ((uint8_t) 4) /*!< New Sample Ready */
+
+/** @} end of uint8_t_group */
+
+
+/* Device register map */
+
+/** @defgroup VL_DefineRegisters_group Define Registers
+ * @brief List of all the defined registers
+ * @{
+ */
+#define VL_REG_SYSRANGE_START 0x000
+ /** mask existing bit in #VL_REG_SYSRANGE_START*/
+ #define VL_REG_SYSRANGE_MODE_MASK 0x0F
+ /** bit 0 in #VL_REG_SYSRANGE_START write 1 toggle state in */
+ /* continuous mode and arm next shot in single shot mode */
+ #define VL_REG_SYSRANGE_MODE_START_STOP 0x01
+ /** bit 1 write 0 in #VL_REG_SYSRANGE_START set single shot mode */
+ #define VL_REG_SYSRANGE_MODE_SINGLESHOT 0x00
+ /** bit 1 write 1 in #VL_REG_SYSRANGE_START set back-to-back */
+ /* operation mode */
+ #define VL_REG_SYSRANGE_MODE_BACKTOBACK 0x02
+ /** bit 2 write 1 in #VL_REG_SYSRANGE_START set timed operation */
+ /* * mode */
+ #define VL_REG_SYSRANGE_MODE_TIMED 0x04
+ /** bit 3 write 1 in #VL_REG_SYSRANGE_START set histogram operation */
+ /* * mode */
+ #define VL_REG_SYSRANGE_MODE_HISTOGRAM 0x08
+
+
+#define VL_REG_SYSTEM_THRESH_HIGH 0x000C
+#define VL_REG_SYSTEM_THRESH_LOW 0x000E
+
+
+#define VL_REG_SYSTEM_SEQUENCE_CONFIG 0x0001
+#define VL_REG_SYSTEM_RANGE_CONFIG 0x0009
+#define VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x0004
+
+
+#define VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x000A
+ #define VL_REG_SYSTEM_INTERRUPT_GPIO_DISABLED 0x00
+ #define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_LOW 0x01
+ #define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_HIGH 0x02
+ #define VL_REG_SYSTEM_INTERRUPT_GPIO_OUT_OF_WINDOW 0x03
+ #define VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY 0x04
+
+#define VL_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x0084
+
+
+#define VL_REG_SYSTEM_INTERRUPT_CLEAR 0x000B
+
+/* Result registers */
+#define VL_REG_RESULT_INTERRUPT_STATUS 0x0013
+#define VL_REG_RESULT_RANGE_STATUS 0x0014
+
+#define VL_REG_RESULT_CORE_PAGE 1
+#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN 0x00BC
+#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN 0x00C0
+#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF 0x00D0
+#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF 0x00D4
+#define VL_REG_RESULT_PEAK_SIGNAL_RATE_REF 0x00B6
+
+/* Algo register */
+
+#define VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM 0x0028
+
+#define VL_REG_I2C_SLAVE_DEVICE_ADDRESS 0x008a
+
+/* Check Limit registers */
+#define VL_REG_MSRC_CONFIG_CONTROL 0x0060
+
+#define VL_REG_PRE_RANGE_CONFIG_MIN_SNR 0X0027
+#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW 0x0056
+#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH 0x0057
+#define VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT 0x0064
+
+#define VL_REG_FINAL_RANGE_CONFIG_MIN_SNR 0X0067
+#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW 0x0047
+#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH 0x0048
+#define VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x0044
+
+
+#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI 0X0061
+#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO 0X0062
+
+/* PRE RANGE registers */
+#define VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x0050
+#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0051
+#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0052
+
+#define VL_REG_SYSTEM_HISTOGRAM_BIN 0x0081
+#define VL_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT 0x0033
+#define VL_REG_HISTOGRAM_CONFIG_READOUT_CTRL 0x0055
+
+#define VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x0070
+#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0071
+#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0072
+#define VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS 0x0020
+
+#define VL_REG_MSRC_CONFIG_TIMEOUT_MACROP 0x0046
+
+
+#define VL_REG_SOFT_RESET_GO2_SOFT_RESET_N 0x00bf
+#define VL_REG_IDENTIFICATION_MODEL_ID 0x00c0
+#define VL_REG_IDENTIFICATION_REVISION_ID 0x00c2
+
+#define VL_REG_OSC_CALIBRATE_VAL 0x00f8
+
+
+#define VL_SIGMA_ESTIMATE_MAX_VALUE 65535
+/* equivalent to a range sigma of 655.35mm */
+
+#define VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH 0x032
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 0x0B0
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 0x0B1
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 0x0B2
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 0x0B3
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 0x0B4
+#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 0x0B5
+
+#define VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT 0xB6
+#define VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E /* 0x14E */
+#define VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET 0x4F /* 0x14F */
+#define VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE 0x80
+
+/*
+ * Speed of light in um per 1E-10 Seconds
+ */
+
+#define VL_SPEED_OF_LIGHT_IN_AIR 2997
+
+#define VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV 0x0089
+
+#define VL_REG_ALGO_PHASECAL_LIM 0x0030 /* 0x130 */
+#define VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT 0x0030
+
+/** @} VL_DefineRegisters_group */
+
+/** @} VL_DevSpecDefines_group */
+
+
+#endif
+
+/* _VL_DEVICE_H_ */
+
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h
new file mode 100644
index 0000000..3cd5d69
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h
@@ -0,0 +1,397 @@
+/*
+ * vl53l0x_i2c_platform.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * @file VL_i2c_platform.h
+ * @brief Function prototype definitions for EWOK Platform layer.
+ *
+ */
+
+
+#ifndef _VL_I2C_PLATFORM_H_
+#define _VL_I2C_PLATFORM_H_
+
+#include "vl53l0x_def.h"
+
+
+/** Maximum buffer size to be used in i2c */
+#define VL_MAX_I2C_XFER_SIZE 64
+
+/**
+ * @brief Typedef defining .\n
+ * The developer should modify this to suit the platform being deployed.
+ *
+ */
+
+/**
+ * @brief Typedef defining 8 bit unsigned char type.\n
+ * The developer should modify this to suit the platform being deployed.
+ *
+ */
+#define I2C 0x01
+#define SPI 0x00
+
+#define COMMS_BUFFER_SIZE 64
+/*MUST be the same size as the SV task buffer */
+
+#define BYTES_PER_WORD 2
+#define BYTES_PER_DWORD 4
+
+#define VL_MAX_STRING_LENGTH_PLT 256
+
+/**
+ * @brief Initialise platform comms.
+ *
+ * @param comms_type - selects between I2C and SPI
+ * @param comms_speed_khz - unsigned short containing the I2C speed in kHz
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_comms_initialise(uint8_t comms_type,
+ uint16_t comms_speed_khz);
+
+/**
+ * @brief Close platform comms.
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_comms_close(void);
+
+/**
+ * @brief Cycle Power to Device
+ *
+ * @return status - status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_cycle_power(void);
+
+int32_t VL_set_page(struct vl_data *dev, uint8_t page_data);
+
+/**
+ * @brief Writes the supplied byte buffer to the device
+ *
+ * Wrapper for SystemVerilog Write Multi task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t *spad_enables;
+ *
+ * int status = VL_write_multi(RET_SPAD_EN_0, spad_enables, 36);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint8_t buffer containing the data to be written
+ * @param count - number of bytes in the supplied byte buffer
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata,
+ int32_t count);
+
+
+/**
+ * @brief Reads the requested number of bytes from the device
+ *
+ * Wrapper for SystemVerilog Read Multi task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t buffer[COMMS_BUFFER_SIZE];
+ *
+ * int status = status = VL_read_multi(DEVICE_ID, buffer, 2)
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to the uint8_t buffer to store read data
+ * @param count - number of uint8_t's to read
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata,
+ int32_t count);
+
+
+/**
+ * @brief Writes a single byte to the device
+ *
+ * Wrapper for SystemVerilog Write Byte task
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t page_number = MAIN_SELECT_PAGE;
+ *
+ * int status = VL_write_byte(PAGE_SELECT, page_number);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param data - uint8_t data value to write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data);
+
+
+/**
+ * @brief Writes a single word (16-bit unsigned) to the device
+ *
+ * Manages the big-endian nature of the device (first byte written is the
+ * MS byte).
+ * Uses SystemVerilog Write Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint16_t nvm_ctrl_pulse_width = 0x0004;
+ *
+ * int status = VL_write_word(NVM_CTRL__PULSE_WIDTH_MSB,
+ * nvm_ctrl_pulse_width);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param data - uin16_t data value write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data);
+
+
+/**
+ * @brief Writes a single dword (32-bit unsigned) to the device
+ *
+ * Manages the big-endian nature of the device (first byte written is the
+ * MS byte).
+ * Uses SystemVerilog Write Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint32_t nvm_data = 0x0004;
+ *
+ * int status = VL_write_dword(NVM_CTRL__DATAIN_MMM, nvm_data);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param data - uint32_t data value to write
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data);
+
+
+
+/**
+ * @brief Reads a single byte from the device
+ *
+ * Uses SystemVerilog Read Byte task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint8_t device_status = 0;
+ *
+ * int status = VL_read_byte(STATUS, &device_status);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint8_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata);
+
+
+/**
+ * @brief Reads a single word (16-bit unsigned) from the device
+ *
+ * Manages the big-endian nature of the device (first byte read is the MS byte).
+ * Uses SystemVerilog Read Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint16_t timeout = 0;
+ *
+ * int status = VL_read_word(TIMEOUT_OVERALL_PERIODS_MSB, &timeout);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint16_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata);
+
+
+/**
+ * @brief Reads a single dword (32-bit unsigned) from the device
+ *
+ * Manages the big-endian nature of the device (first byte read is the MS byte).
+ * Uses SystemVerilog Read Multi task.
+ *
+ * @code
+ *
+ * Example:
+ *
+ * uint32_t range_1 = 0;
+ *
+ * int status = VL_read_dword(RANGE_1_MMM, &range_1);
+ *
+ * @endcode
+ *
+ * @param address - uint8_t device address value
+ * @param index - uint8_t register index value
+ * @param pdata - pointer to uint32_t data value
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata);
+
+
+/**
+ * @brief Implements a programmable wait in us
+ *
+ * Wrapper for SystemVerilog Wait in micro seconds task
+ *
+ * @param wait_us - integer wait in micro seconds
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_platform_wait_us(int32_t wait_us);
+
+
+/**
+ * @brief Implements a programmable wait in ms
+ *
+ * Wrapper for SystemVerilog Wait in milli seconds task
+ *
+ * @param wait_ms - integer wait in milli seconds
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_wait_ms(int32_t wait_ms);
+
+
+/**
+ * @brief Set GPIO value
+ *
+ * @param level - input level - either 0 or 1
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_set_gpio(uint8_t level);
+
+
+/**
+ * @brief Get GPIO value
+ *
+ * @param plevel - uint8_t pointer to store GPIO level (0 or 1)
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_get_gpio(uint8_t *plevel);
+
+/**
+ * @brief Release force on GPIO
+ *
+ * @return status - SystemVerilog status 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_release_gpio(void);
+
+
+/**
+ * @brief Get the frequency of the timer used for ranging results time stamps
+ *
+ * @param[out] ptimer_freq_hz : pointer for timer frequency
+ *
+ * @return status : 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz);
+
+/**
+ * @brief Get the timer value in units of timer_freq_hz
+ * (see VL_get_timestamp_frequency())
+ *
+ * @param[out] ptimer_count : pointer for timer count value
+ *
+ * @return status : 0 = ok, 1 = error
+ *
+ */
+
+int32_t VL_get_timer_value(int32_t *ptimer_count);
+int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len);
+int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len);
+
+#endif /* _VL_I2C_PLATFORM_H_ */
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h
new file mode 100644
index 0000000..ecfc994
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h
@@ -0,0 +1,183 @@
+/*
+ * vl53l0x_interrupt_threshold_settings.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_INTERRUPT_THRESHOLD_SETTINGS_H_
+#define _VL_INTERRUPT_THRESHOLD_SETTINGS_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint8_t InterruptThresholdSettings[] = {
+
+ /* Start of Interrupt Threshold Settings */
+ 0x1, 0xff, 0x00,
+ 0x1, 0x80, 0x01,
+ 0x1, 0xff, 0x01,
+ 0x1, 0x00, 0x00,
+ 0x1, 0xff, 0x01,
+ 0x1, 0x4f, 0x02,
+ 0x1, 0xFF, 0x0E,
+ 0x1, 0x00, 0x03,
+ 0x1, 0x01, 0x84,
+ 0x1, 0x02, 0x0A,
+ 0x1, 0x03, 0x03,
+ 0x1, 0x04, 0x08,
+ 0x1, 0x05, 0xC8,
+ 0x1, 0x06, 0x03,
+ 0x1, 0x07, 0x8D,
+ 0x1, 0x08, 0x08,
+ 0x1, 0x09, 0xC6,
+ 0x1, 0x0A, 0x01,
+ 0x1, 0x0B, 0x02,
+ 0x1, 0x0C, 0x00,
+ 0x1, 0x0D, 0xD5,
+ 0x1, 0x0E, 0x18,
+ 0x1, 0x0F, 0x12,
+ 0x1, 0x10, 0x01,
+ 0x1, 0x11, 0x82,
+ 0x1, 0x12, 0x00,
+ 0x1, 0x13, 0xD5,
+ 0x1, 0x14, 0x18,
+ 0x1, 0x15, 0x13,
+ 0x1, 0x16, 0x03,
+ 0x1, 0x17, 0x86,
+ 0x1, 0x18, 0x0A,
+ 0x1, 0x19, 0x09,
+ 0x1, 0x1A, 0x08,
+ 0x1, 0x1B, 0xC2,
+ 0x1, 0x1C, 0x03,
+ 0x1, 0x1D, 0x8F,
+ 0x1, 0x1E, 0x0A,
+ 0x1, 0x1F, 0x06,
+ 0x1, 0x20, 0x01,
+ 0x1, 0x21, 0x02,
+ 0x1, 0x22, 0x00,
+ 0x1, 0x23, 0xD5,
+ 0x1, 0x24, 0x18,
+ 0x1, 0x25, 0x22,
+ 0x1, 0x26, 0x01,
+ 0x1, 0x27, 0x82,
+ 0x1, 0x28, 0x00,
+ 0x1, 0x29, 0xD5,
+ 0x1, 0x2A, 0x18,
+ 0x1, 0x2B, 0x0B,
+ 0x1, 0x2C, 0x28,
+ 0x1, 0x2D, 0x78,
+ 0x1, 0x2E, 0x28,
+ 0x1, 0x2F, 0x91,
+ 0x1, 0x30, 0x00,
+ 0x1, 0x31, 0x0B,
+ 0x1, 0x32, 0x00,
+ 0x1, 0x33, 0x0B,
+ 0x1, 0x34, 0x00,
+ 0x1, 0x35, 0xA1,
+ 0x1, 0x36, 0x00,
+ 0x1, 0x37, 0xA0,
+ 0x1, 0x38, 0x00,
+ 0x1, 0x39, 0x04,
+ 0x1, 0x3A, 0x28,
+ 0x1, 0x3B, 0x30,
+ 0x1, 0x3C, 0x0C,
+ 0x1, 0x3D, 0x04,
+ 0x1, 0x3E, 0x0F,
+ 0x1, 0x3F, 0x79,
+ 0x1, 0x40, 0x28,
+ 0x1, 0x41, 0x1E,
+ 0x1, 0x42, 0x2F,
+ 0x1, 0x43, 0x87,
+ 0x1, 0x44, 0x00,
+ 0x1, 0x45, 0x0B,
+ 0x1, 0x46, 0x00,
+ 0x1, 0x47, 0x0B,
+ 0x1, 0x48, 0x00,
+ 0x1, 0x49, 0xA7,
+ 0x1, 0x4A, 0x00,
+ 0x1, 0x4B, 0xA6,
+ 0x1, 0x4C, 0x00,
+ 0x1, 0x4D, 0x04,
+ 0x1, 0x4E, 0x01,
+ 0x1, 0x4F, 0x00,
+ 0x1, 0x50, 0x00,
+ 0x1, 0x51, 0x80,
+ 0x1, 0x52, 0x09,
+ 0x1, 0x53, 0x08,
+ 0x1, 0x54, 0x01,
+ 0x1, 0x55, 0x00,
+ 0x1, 0x56, 0x0F,
+ 0x1, 0x57, 0x79,
+ 0x1, 0x58, 0x09,
+ 0x1, 0x59, 0x05,
+ 0x1, 0x5A, 0x00,
+ 0x1, 0x5B, 0x60,
+ 0x1, 0x5C, 0x05,
+ 0x1, 0x5D, 0xD1,
+ 0x1, 0x5E, 0x0C,
+ 0x1, 0x5F, 0x3C,
+ 0x1, 0x60, 0x00,
+ 0x1, 0x61, 0xD0,
+ 0x1, 0x62, 0x0B,
+ 0x1, 0x63, 0x03,
+ 0x1, 0x64, 0x28,
+ 0x1, 0x65, 0x10,
+ 0x1, 0x66, 0x2A,
+ 0x1, 0x67, 0x39,
+ 0x1, 0x68, 0x0B,
+ 0x1, 0x69, 0x02,
+ 0x1, 0x6A, 0x28,
+ 0x1, 0x6B, 0x10,
+ 0x1, 0x6C, 0x2A,
+ 0x1, 0x6D, 0x61,
+ 0x1, 0x6E, 0x0C,
+ 0x1, 0x6F, 0x00,
+ 0x1, 0x70, 0x0F,
+ 0x1, 0x71, 0x79,
+ 0x1, 0x72, 0x00,
+ 0x1, 0x73, 0x0B,
+ 0x1, 0x74, 0x00,
+ 0x1, 0x75, 0x0B,
+ 0x1, 0x76, 0x00,
+ 0x1, 0x77, 0xA1,
+ 0x1, 0x78, 0x00,
+ 0x1, 0x79, 0xA0,
+ 0x1, 0x7A, 0x00,
+ 0x1, 0x7B, 0x04,
+ 0x1, 0xFF, 0x04,
+ 0x1, 0x79, 0x1D,
+ 0x1, 0x7B, 0x27,
+ 0x1, 0x96, 0x0E,
+ 0x1, 0x97, 0xFE,
+ 0x1, 0x98, 0x03,
+ 0x1, 0x99, 0xEF,
+ 0x1, 0x9A, 0x02,
+ 0x1, 0x9B, 0x44,
+ 0x1, 0x73, 0x07,
+ 0x1, 0x70, 0x01,
+ 0x1, 0xff, 0x01,
+ 0x1, 0x00, 0x01,
+ 0x1, 0xff, 0x00,
+ 0x00, 0x00, 0x00
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h
new file mode 100644
index 0000000..d896fe8
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h
@@ -0,0 +1,213 @@
+/*
+ * vl53l0x_platform.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_PLATFORM_H_
+#define _VL_PLATFORM_H_
+
+#include <linux/delay.h>
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform_log.h"
+
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+#include "stmvl53l0x.h"
+
+/**
+ * @file vl53l0x_platform.h
+ *
+ * @brief All end user OS/platform/application porting
+ */
+
+/**
+ * @defgroup VL_platform_group VL53L0 Platform Functions
+ * @brief VL53L0 Platform Functions
+ * @{
+ */
+
+/**
+ * @def PALDevDataGet
+ * @brief Get ST private structure @a struct VL_DevData_t data access
+ *
+ * @param Dev Device Handle
+ * @param field ST structure field name
+ * It maybe used and as real data "ref" not just as "get" for sub-structure item
+ * like PALDevDataGet(FilterData.field)[i] or
+ * PALDevDataGet(FilterData.MeasurementIndex)++
+ */
+#define PALDevDataGet(Dev, field) (Dev->Data.field)
+
+/**
+ * @def PALDevDataSet(Dev, field, data)
+ * @brief Set ST private structure @a struct VL_DevData_t data field
+ * @param Dev Device Handle
+ * @param field ST structure field na*me
+ * @param data Data to be set
+ */
+#define PALDevDataSet(Dev, field, data) ((Dev->Data.field) = (data))
+
+
+/**
+ * @defgroup VL_registerAccess_group PAL Register Access Functions
+ * @brief PAL Register Access Functions
+ * @{
+ */
+
+/**
+ * Lock comms interface to serialize all commands to a shared I2C interface
+ * for a specific device
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_LockSequenceAccess(struct vl_data *Dev);
+
+/**
+ * Unlock comms interface to serialize all commands to a shared I2C interface
+ * for a specific device
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_UnlockSequenceAccess(struct vl_data *Dev);
+
+
+/**
+ * Writes the supplied byte buffer to the device
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param pdata Pointer to uint8_t buffer containing the data
+ * to be written
+ * @param count Number of bytes in the supplied byte buffer
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count);
+
+/**
+ * Reads the requested number of bytes from the device
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param pdata Pointer to the uint8_t buffer to store read data
+ * @param count Number of uint8_t's to read
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count);
+
+/**
+ * Write single byte register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data 8 bit register data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data);
+
+/**
+ * Write word register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data 16 bit register data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data);
+
+/**
+ * Write double word (4 byte) register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data 32 bit register data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data);
+
+/**
+ * Read single byte register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data pointer to 8 bit data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data);
+
+/**
+ * Read word (2byte) register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data pointer to 16 bit data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data);
+
+/**
+ * Read dword (4byte) register
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param data pointer to 32 bit data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data);
+
+/**
+ * Threat safe Update (read/modify/write) single byte register
+ *
+ * Final_reg = (Initial_reg & and_data) |or_data
+ *
+ * @param Dev Device Handle
+ * @param index The register index
+ * @param AndData 8 bit and data
+ * @param OrData 8 bit or data
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index,
+ uint8_t AndData, uint8_t OrData);
+
+/** @} end of VL_registerAccess_group */
+
+
+/**
+ * @brief execute delay in all polling API call
+ *
+ * A typical multi-thread or RTOs implementation is to sleep the task for
+ * some 5ms (with 100Hz max rate faster polling is not needed)
+ * if nothing specific is need you can define it as an empty/void macro
+ * @code
+ * #define VL_PollingDelay(...) (void)0
+ * @endcode
+ * @param Dev Device Handle
+ * @return VL_ERROR_NONE Success
+ * @return "Other error code" See ::int8_t
+ */
+int8_t VL_PollingDelay(struct vl_data *Dev);
+/* usually best implemented as a real function */
+
+/** @} end of VL_platform_group */
+
+#endif /* _VL_PLATFORM_H_ */
+
+
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h
new file mode 100644
index 0000000..a8f22c5
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h
@@ -0,0 +1,99 @@
+/*
+ * vl53l0x_platform_log.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_PLATFORM_LOG_H_
+#define _VL_PLATFORM_LOG_H_
+
+#include <linux/string.h>
+/* LOG Functions */
+
+
+/**
+ * @file vl53l0x_platform_log.h
+ *
+ * @brief platform log function definition
+ */
+
+/* #define VL_LOG_ENABLE */
+
+enum {
+ TRACE_LEVEL_NONE,
+ TRACE_LEVEL_ERRORS,
+ TRACE_LEVEL_WARNING,
+ TRACE_LEVEL_INFO,
+ TRACE_LEVEL_DEBUG,
+ TRACE_LEVEL_ALL,
+ TRACE_LEVEL_IGNORE
+};
+
+enum {
+ TRACE_FUNCTION_NONE = 0,
+ TRACE_FUNCTION_I2C = 1,
+ TRACE_FUNCTION_ALL = 0x7fffffff /* all bits except sign */
+};
+
+enum {
+ TRACE_MODULE_NONE = 0x0,
+ TRACE_MODULE_API = 0x1,
+ TRACE_MODULE_PLATFORM = 0x2,
+ TRACE_MODULE_ALL = 0x7fffffff /* all bits except sign */
+};
+
+
+#ifdef VL_LOG_ENABLE
+
+#include <linux/module.h>
+
+
+extern uint32_t _trace_level;
+
+
+
+int32_t VL_trace_config(char *filename, uint32_t modules,
+ uint32_t level, uint32_t functions);
+
+#define trace_print_module_function(...)
+
+#define LOG_GET_TIME() 0
+#define _LOG_FUNCTION_START(module, fmt, ...) \
+ dbg("beg %s start @%d\t" fmt "\n", \
+ __func__, LOG_GET_TIME(), ##__VA_ARGS__)
+
+#define _LOG_FUNCTION_END(module, status, ...)\
+ dbg("end %s start @%d Status %d\n", \
+ __func__, LOG_GET_TIME(), (int)status)
+
+#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\
+ dbg("End %s @%d %d\t"fmt"\n", \
+ __func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__)
+
+
+#else /* VL_LOG_ENABLE no logging */
+ #define VL_ErrLog(...) (void)0
+ #define _LOG_FUNCTION_START(module, fmt, ...) (void)0
+ #define _LOG_FUNCTION_END(module, status, ...) (void)0
+ #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) (void)0
+#endif /* else */
+
+#define VL_COPYSTRING(str, ...) strlcpy(str, ##__VA_ARGS__, sizeof(str))
+
+
+#endif /* _VL_PLATFORM_LOG_H_ */
+
+
+
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h
new file mode 100644
index 0000000..ba2998a
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h
@@ -0,0 +1,135 @@
+/*
+ * vl53l0x_tuning.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _VL_TUNING_H_
+#define _VL_TUNING_H_
+
+#include "vl53l0x_def.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+uint8_t DefaultTuningSettings[] = {
+
+ /* update 02/11/2015_v36 */
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x00, 0x00,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x09, 0x00,
+ 0x01, 0x10, 0x00,
+ 0x01, 0x11, 0x00,
+
+ 0x01, 0x24, 0x01,
+ 0x01, 0x25, 0xff,
+ 0x01, 0x75, 0x00,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x4e, 0x2c,
+ 0x01, 0x48, 0x00,
+ 0x01, 0x30, 0x20,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x30, 0x09, /* mja changed from 0x64. */
+ 0x01, 0x54, 0x00,
+ 0x01, 0x31, 0x04,
+ 0x01, 0x32, 0x03,
+ 0x01, 0x40, 0x83,
+ 0x01, 0x46, 0x25,
+ 0x01, 0x60, 0x00,
+ 0x01, 0x27, 0x00,
+ 0x01, 0x50, 0x06,
+ 0x01, 0x51, 0x00,
+ 0x01, 0x52, 0x96,
+ 0x01, 0x56, 0x08,
+ 0x01, 0x57, 0x30,
+ 0x01, 0x61, 0x00,
+ 0x01, 0x62, 0x00,
+ 0x01, 0x64, 0x00,
+ 0x01, 0x65, 0x00,
+ 0x01, 0x66, 0xa0,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x22, 0x32,
+ 0x01, 0x47, 0x14,
+ 0x01, 0x49, 0xff,
+ 0x01, 0x4a, 0x00,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x7a, 0x0a,
+ 0x01, 0x7b, 0x00,
+ 0x01, 0x78, 0x21,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x23, 0x34,
+ 0x01, 0x42, 0x00,
+ 0x01, 0x44, 0xff,
+ 0x01, 0x45, 0x26,
+ 0x01, 0x46, 0x05,
+ 0x01, 0x40, 0x40,
+ 0x01, 0x0E, 0x06,
+ 0x01, 0x20, 0x1a,
+ 0x01, 0x43, 0x40,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x34, 0x03,
+ 0x01, 0x35, 0x44,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x31, 0x04,
+ 0x01, 0x4b, 0x09,
+ 0x01, 0x4c, 0x05,
+ 0x01, 0x4d, 0x04,
+
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x44, 0x00,
+ 0x01, 0x45, 0x20,
+ 0x01, 0x47, 0x08,
+ 0x01, 0x48, 0x28,
+ 0x01, 0x67, 0x00,
+ 0x01, 0x70, 0x04,
+ 0x01, 0x71, 0x01,
+ 0x01, 0x72, 0xfe,
+ 0x01, 0x76, 0x00,
+ 0x01, 0x77, 0x00,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x0d, 0x01,
+
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x80, 0x01,
+ 0x01, 0x01, 0xF8,
+
+ 0x01, 0xFF, 0x01,
+ 0x01, 0x8e, 0x01,
+ 0x01, 0x00, 0x01,
+ 0x01, 0xFF, 0x00,
+ 0x01, 0x80, 0x00,
+
+ 0x00, 0x00, 0x00
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VL_TUNING_H_ */
diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h
new file mode 100644
index 0000000..be40e83
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h
@@ -0,0 +1,54 @@
+/*
+ * vl53l0x_types.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef VL_TYPES_H_
+#define VL_TYPES_H_
+
+#include <linux/types.h>
+
+#ifndef NULL
+#error "TODO review NULL definition or add required include "
+#define NULL 0
+#endif
+
+#if !defined(STDINT_H) && !defined(_GCC_STDINT_H) \
+ && !defined(_STDINT_H) && !defined(_LINUX_TYPES_H)
+
+#pragma message(
+"Review type definition of STDINT define for your platform and add to above")
+
+/*
+ * target platform do not provide stdint or use a different #define than above
+ * to avoid seeing the message below addapt the #define list above or implement
+ * all type and delete these pragma
+ */
+
+unsigned int uint32_t;
+int int32_t;
+
+unsigned short uint16_t;
+short int16_t;
+
+unsigned char uint8_t;
+
+signed char int8_t;
+
+
+#endif /* _STDINT_H */
+
+#endif /* VL_TYPES_H_ */
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c
new file mode 100644
index 0000000..888947f
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c
@@ -0,0 +1,3096 @@
+/*
+ * vl53l0x_api.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "vl53l0x_api.h"
+#include "vl53l0x_tuning.h"
+#include "vl53l0x_interrupt_threshold_settings.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_calibration.h"
+#include "vl53l0x_api_strings.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#ifdef VL_LOG_ENABLE
+#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \
+ level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#endif
+
+/* Group PAL General Functions */
+
+int8_t VL_GetVersion(struct VL_Version_t *pVersion)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ pVersion->major = VL_IMPLEMENTATION_VER_MAJOR;
+ pVersion->minor = VL_IMPLEMENTATION_VER_MINOR;
+ pVersion->build = VL_IMPLEMENTATION_VER_SUB;
+
+ pVersion->revision = VL_IMPLEMENTATION_VER_REVISION;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetPalSpecVersion(struct VL_Version_t *pPalSpecVersion)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ pPalSpecVersion->major = VL_SPECIFICATION_VER_MAJOR;
+ pPalSpecVersion->minor = VL_SPECIFICATION_VER_MINOR;
+ pPalSpecVersion->build = VL_SPECIFICATION_VER_SUB;
+
+ pPalSpecVersion->revision = VL_SPECIFICATION_VER_REVISION;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetProductRevision(struct vl_data *Dev,
+ uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t revision_id;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_IDENTIFICATION_REVISION_ID,
+ &revision_id);
+ *pProductRevisionMajor = 1;
+ *pProductRevisionMinor = (revision_id & 0xF0) >> 4;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+int8_t VL_GetDeviceInfo(struct vl_data *Dev,
+ struct VL_DeviceInfo_t *pVL_DeviceInfo)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_device_info(Dev, pVL_DeviceInfo);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev,
+ uint8_t *pDeviceErrorStatus)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t RangeStatus;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS,
+ &RangeStatus);
+
+ *pDeviceErrorStatus = (uint8_t)((RangeStatus & 0x78) >> 3);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+int8_t VL_GetDeviceErrorString(uint8_t ErrorCode,
+ char *pDeviceErrorString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_device_error_string(ErrorCode, pDeviceErrorString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetRangeStatusString(uint8_t RangeStatus,
+ char *pRangeStatusString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_range_status_string(RangeStatus,
+ pRangeStatusString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetPalErrorString(int8_t PalErrorCode,
+ char *pPalErrorString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_pal_error_string(PalErrorCode, pPalErrorString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetPalStateString(uint8_t PalStateCode,
+ char *pPalStateString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_pal_state_string(PalStateCode, pPalStateString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetPalState(struct vl_data *Dev, uint8_t *pPalState)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pPalState = PALDevDataGet(Dev, PalState);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetPowerMode(struct vl_data *Dev,
+ uint8_t PowerMode)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* Only level1 of Power mode exists */
+ if ((PowerMode != VL_POWERMODE_STANDBY_LEVEL1)
+ && (PowerMode != VL_POWERMODE_IDLE_LEVEL1)) {
+ Status = VL_ERROR_MODE_NOT_SUPPORTED;
+ } else if (PowerMode == VL_POWERMODE_STANDBY_LEVEL1) {
+ /* set the standby level1 of power mode */
+ Status = VL_WrByte(Dev, 0x80, 0x00);
+ if (Status == VL_ERROR_NONE) {
+ /* Set PAL State to standby */
+ PALDevDataSet(Dev, PalState, VL_STATE_STANDBY);
+ PALDevDataSet(Dev, PowerMode,
+ VL_POWERMODE_STANDBY_LEVEL1);
+ }
+
+ } else {
+ /* VL_POWERMODE_IDLE_LEVEL1 */
+ Status = VL_WrByte(Dev, 0x80, 0x00);
+ if (Status == VL_ERROR_NONE)
+ Status = VL_StaticInit(Dev);
+
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, PowerMode,
+ VL_POWERMODE_IDLE_LEVEL1);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetPowerMode(struct vl_data *Dev,
+ uint8_t *pPowerMode)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* Only level1 of Power mode exists */
+ Status = VL_RdByte(Dev, 0x80, &Byte);
+
+ if (Status == VL_ERROR_NONE) {
+ if (Byte == 1) {
+ PALDevDataSet(Dev, PowerMode,
+ VL_POWERMODE_IDLE_LEVEL1);
+ } else {
+ PALDevDataSet(Dev, PowerMode,
+ VL_POWERMODE_STANDBY_LEVEL1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetOffsetCalibrationDataMicroMeter(struct vl_data *Dev,
+ int32_t OffsetCalibrationDataMicroMeter)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_set_offset_calibration_data_micro_meter(Dev,
+ OffsetCalibrationDataMicroMeter);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetOffsetCalibrationDataMicroMeter(struct vl_data *Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_offset_calibration_data_micro_meter(Dev,
+ pOffsetCalibrationDataMicroMeter);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev,
+ int16_t LinearityCorrectiveGain)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if ((LinearityCorrectiveGain < 0) || (LinearityCorrectiveGain > 1000))
+ Status = VL_ERROR_INVALID_PARAMS;
+ else {
+ PALDevDataSet(Dev, LinearityCorrectiveGain,
+ LinearityCorrectiveGain);
+
+ if (LinearityCorrectiveGain != 1000) {
+ /* Disable FW Xtalk */
+ Status = VL_WrWord(Dev,
+ VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, 0);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev,
+ uint16_t *pLinearityCorrectiveGain)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pLinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetGroupParamHold(struct vl_data *Dev, uint8_t GroupParamHold)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev,
+ uint16_t *pUpperLimitMilliMeter)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetTotalSignalRate(struct vl_data *Dev,
+ unsigned int *pTotalSignalRate)
+{
+ int8_t Status = VL_ERROR_NONE;
+ struct VL_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+ Status = VL_get_total_signal_rate(
+ Dev, &LastRangeDataBuffer, pTotalSignalRate);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL General Functions */
+
+/* Group PAL Init Functions */
+int8_t VL_SetDeviceAddress(struct vl_data *Dev, uint8_t DeviceAddress)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_WrByte(Dev, VL_REG_I2C_SLAVE_DEVICE_ADDRESS,
+ DeviceAddress / 2);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_DataInit(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ struct VL_DeviceParameters_t CurrentParameters;
+ int i;
+ uint8_t StopVariable;
+
+ LOG_FUNCTION_START("");
+
+ /* by default the I2C is running at 1V8 if you want to change it you */
+ /* need to include this define at compilation level. */
+#ifdef USE_I2C_2V8
+ Status = VL_UpdateByte(Dev,
+ VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
+ 0xFE,
+ 0x01);
+#endif
+
+ /* Set I2C standard mode */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, 0x88, 0x00);
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, 0);
+
+#ifdef USE_IQC_STATION
+ if (Status == VL_ERROR_NONE)
+ Status = VL_apply_offset_adjustment(Dev);
+#endif
+
+ /* Default value is 1000 for Linearity Corrective Gain */
+ PALDevDataSet(Dev, LinearityCorrectiveGain, 1000);
+
+ /* Dmax default Parameter */
+ PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400);
+ PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+ (unsigned int)((0x00016B85))); /* 1.42 No Cover Glass*/
+
+ /* Set Default static parameters */
+ /* *set first temporary values 9.44MHz * 65536 = 618660 */
+ VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, 618660);
+
+ /* Set Default XTalkCompensationRateMegaCps to 0 */
+ VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, 0);
+
+ /* Get default parameters */
+ Status = VL_GetDeviceParameters(Dev, &CurrentParameters);
+ if (Status == VL_ERROR_NONE) {
+ /* initialize PAL values */
+ CurrentParameters.DeviceMode = VL_DEVICEMODE_SINGLE_RANGING;
+ CurrentParameters.HistogramMode = VL_HISTOGRAMMODE_DISABLED;
+ PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+ }
+
+ /* Sigma estimator variable */
+ PALDevDataSet(Dev, SigmaEstRefArray, 100);
+ PALDevDataSet(Dev, SigmaEstEffPulseWidth, 900);
+ PALDevDataSet(Dev, SigmaEstEffAmbWidth, 500);
+ PALDevDataSet(Dev, targetRefRate, 0x0A00); /* 20 MCPS in 9:7 format */
+
+ /* Use internal default settings */
+ PALDevDataSet(Dev, UseInternalTuningSettings, 1);
+
+ Status |= VL_WrByte(Dev, 0x80, 0x01);
+ Status |= VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x00);
+ Status |= VL_RdByte(Dev, 0x91, &StopVariable);
+ PALDevDataSet(Dev, StopVariable, StopVariable);
+ Status |= VL_WrByte(Dev, 0x00, 0x01);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL_WrByte(Dev, 0x80, 0x00);
+
+ /* Enable all check */
+ for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ if (Status == VL_ERROR_NONE)
+ Status |= VL_SetLimitCheckEnable(Dev, i, 1);
+ else
+ break;
+
+ }
+
+ /* Disable the following checks */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP, 0);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGNAL_RATE_MSRC, 0);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE, 0);
+
+ /* Limit default values */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_SetLimitCheckValue(Dev,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ (unsigned int)(18 * 65536));
+ }
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_SetLimitCheckValue(Dev,
+ VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ (unsigned int)(25 * 65536 / 100));
+ /* 0.25 * 65536 */
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_SetLimitCheckValue(Dev,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP,
+ (unsigned int)(35 * 65536));
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_SetLimitCheckValue(Dev,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ (unsigned int)(0 * 65536));
+ }
+
+ if (Status == VL_ERROR_NONE) {
+
+ PALDevDataSet(Dev, SequenceConfig, 0xFF);
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ 0xFF);
+
+ /* Set PAL state to tell that we are waiting for call to */
+ /* * VL_StaticInit */
+ PALDevDataSet(Dev, PalState, VL_STATE_WAIT_STATICINIT);
+ }
+
+ if (Status == VL_ERROR_NONE)
+ VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 0);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev,
+ uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if (UseInternalTuningSettings == 1) {
+ /* Force use internal settings */
+ PALDevDataSet(Dev, UseInternalTuningSettings, 1);
+ } else {
+
+ /* check that the first byte is not 0 */
+ if (*pTuningSettingBuffer != 0) {
+ PALDevDataSet(Dev, pTuningSettingsPointer,
+ pTuningSettingBuffer);
+ PALDevDataSet(Dev, UseInternalTuningSettings, 0);
+
+ } else {
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev,
+ uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *ppTuningSettingBuffer = PALDevDataGet(Dev, pTuningSettingsPointer);
+ *pUseInternalTuningSettings = PALDevDataGet(Dev,
+ UseInternalTuningSettings);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_StaticInit(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ struct VL_DeviceParameters_t CurrentParameters = {0};
+ uint8_t *pTuningSettingBuffer;
+ uint16_t tempword = 0;
+ uint8_t tempbyte = 0;
+ uint8_t UseInternalTuningSettings = 0;
+ uint32_t count = 0;
+ uint8_t isApertureSpads = 0;
+ uint32_t refSpadCount = 0;
+ uint8_t ApertureSpads = 0;
+ uint8_t vcselPulsePeriodPCLK;
+ uint32_t seqTimeoutMicroSecs;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_info_from_device(Dev, 1);
+
+ /* set the ref spad from NVM */
+ count = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount);
+ ApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType);
+
+ /* NVM value invalid */
+ if ((ApertureSpads > 1) ||
+ ((ApertureSpads == 1) && (count > 32)) ||
+ ((ApertureSpads == 0) && (count > 12)))
+ Status = VL_perform_ref_spad_management(Dev, &refSpadCount,
+ &isApertureSpads);
+ else
+ Status = VL_set_reference_spads(Dev, count, ApertureSpads);
+
+
+ /* Initialize tuning settings buffer to prevent compiler warning. */
+ pTuningSettingBuffer = DefaultTuningSettings;
+
+ if (Status == VL_ERROR_NONE) {
+ UseInternalTuningSettings = PALDevDataGet(Dev,
+ UseInternalTuningSettings);
+
+ if (UseInternalTuningSettings == 0)
+ pTuningSettingBuffer = PALDevDataGet(Dev,
+ pTuningSettingsPointer);
+ else
+ pTuningSettingBuffer = DefaultTuningSettings;
+
+ }
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_load_tuning_settings(Dev,
+ pTuningSettingBuffer);
+
+
+ /* Set interrupt config to new sample ready */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_SetGpioConfig(Dev, 0, 0,
+ VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
+ VL_INTERRUPTPOLARITY_LOW);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_RdWord(Dev, 0x84, &tempword);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz,
+ VL_FIXPOINT412TOFIXPOINT1616(tempword));
+ }
+
+ /* After static init, some device parameters may be changed, */
+ /* * so update them */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetDeviceParameters(Dev, &CurrentParameters);
+
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetFractionEnable(Dev, &tempbyte);
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, RangeFractionalEnable, tempbyte);
+
+ }
+
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, CurrentParameters, CurrentParameters);
+
+
+ /* read the sequence config and save it */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdByte(Dev,
+ VL_REG_SYSTEM_SEQUENCE_CONFIG, &tempbyte);
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, tempbyte);
+
+ }
+
+ /* Disable MSRC and TCC by default */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetSequenceStepEnable(Dev,
+ VL_SEQUENCESTEP_TCC, 0);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetSequenceStepEnable(Dev,
+ VL_SEQUENCESTEP_MSRC, 0);
+
+
+ /* Set PAL State to standby */
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, PalState, VL_STATE_IDLE);
+
+
+
+ /* Store pre-range vcsel period */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetVcselPulsePeriod(
+ Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &vcselPulsePeriodPCLK);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev, PreRangeVcselPulsePeriod,
+ vcselPulsePeriodPCLK);
+ }
+
+ /* Store final-range vcsel period */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetVcselPulsePeriod(
+ Dev,
+ VL_VCSEL_PERIOD_FINAL_RANGE,
+ &vcselPulsePeriodPCLK);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev, FinalRangeVcselPulsePeriod,
+ vcselPulsePeriodPCLK);
+ }
+
+ /* Store pre-range timeout */
+ if (Status == VL_ERROR_NONE) {
+ Status = get_sequence_step_timeout(
+ Dev,
+ VL_SEQUENCESTEP_PRE_RANGE,
+ &seqTimeoutMicroSecs);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeTimeoutMicroSecs,
+ seqTimeoutMicroSecs);
+ }
+
+ /* Store final-range timeout */
+ if (Status == VL_ERROR_NONE) {
+ Status = get_sequence_step_timeout(
+ Dev,
+ VL_SEQUENCESTEP_FINAL_RANGE,
+ &seqTimeoutMicroSecs);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeTimeoutMicroSecs,
+ seqTimeoutMicroSecs);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_WaitDeviceBooted(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_ResetDevice(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* Set reset bit */
+ Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+ 0x00);
+
+ /* Wait for some time */
+ if (Status == VL_ERROR_NONE) {
+ do {
+ Status = VL_RdByte(Dev,
+ VL_REG_IDENTIFICATION_MODEL_ID, &Byte);
+ } while (Byte != 0x00);
+ }
+
+ VL_PollingDelay(Dev);
+
+ /* Release reset */
+ Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N,
+ 0x01);
+
+ /* Wait until correct boot-up of the device */
+ if (Status == VL_ERROR_NONE) {
+ do {
+ Status = VL_RdByte(Dev,
+ VL_REG_IDENTIFICATION_MODEL_ID, &Byte);
+ } while (Byte == 0x00);
+ }
+
+ VL_PollingDelay(Dev);
+
+ /* Set PAL State to VL_STATE_POWERDOWN */
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, PalState, VL_STATE_POWERDOWN);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+/* End Group PAL Init Functions */
+
+/* Group PAL Parameters Functions */
+int8_t VL_SetDeviceParameters(struct vl_data *Dev,
+ const struct VL_DeviceParameters_t *pDeviceParameters)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int i;
+
+ LOG_FUNCTION_START("");
+ Status = VL_SetDeviceMode(Dev, pDeviceParameters->DeviceMode);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetInterMeasurementPeriodMilliSeconds(Dev,
+ pDeviceParameters->InterMeasurementPeriodMilliSeconds);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetXTalkCompensationRateMegaCps(Dev,
+ pDeviceParameters->XTalkCompensationRateMegaCps);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetOffsetCalibrationDataMicroMeter(Dev,
+ pDeviceParameters->RangeOffsetMicroMeters);
+
+
+ for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ if (Status == VL_ERROR_NONE)
+ Status |= VL_SetLimitCheckEnable(Dev, i,
+ pDeviceParameters->LimitChecksEnable[i]);
+ else
+ break;
+
+ if (Status == VL_ERROR_NONE)
+ Status |= VL_SetLimitCheckValue(Dev, i,
+ pDeviceParameters->LimitChecksValue[i]);
+ else
+ break;
+
+ }
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetWrapAroundCheckEnable(Dev,
+ pDeviceParameters->WrapAroundCheckEnable);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ pDeviceParameters->MeasurementTimingBudgetMicroSeconds);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetDeviceParameters(struct vl_data *Dev,
+ struct VL_DeviceParameters_t *pDeviceParameters)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int i;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_GetDeviceMode(Dev, &(pDeviceParameters->DeviceMode));
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetInterMeasurementPeriodMilliSeconds(Dev,
+ &(pDeviceParameters->InterMeasurementPeriodMilliSeconds));
+
+
+ if (Status == VL_ERROR_NONE)
+ pDeviceParameters->XTalkCompensationEnable = 0;
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetXTalkCompensationRateMegaCps(Dev,
+ &(pDeviceParameters->XTalkCompensationRateMegaCps));
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetOffsetCalibrationDataMicroMeter(Dev,
+ &(pDeviceParameters->RangeOffsetMicroMeters));
+
+
+ if (Status == VL_ERROR_NONE) {
+ for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
+ /* get first the values, then the enables.
+ * VL_GetLimitCheckValue will modify the enable
+ * flags
+ */
+ if (Status == VL_ERROR_NONE) {
+ Status |= VL_GetLimitCheckValue(Dev, i,
+ &(pDeviceParameters->LimitChecksValue[i]));
+ } else {
+ break;
+ }
+ if (Status == VL_ERROR_NONE) {
+ Status |= VL_GetLimitCheckEnable(Dev, i,
+ &(pDeviceParameters->LimitChecksEnable[i]));
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetWrapAroundCheckEnable(Dev,
+ &(pDeviceParameters->WrapAroundCheckEnable));
+ }
+
+ /* Need to be done at the end as it uses VCSELPulsePeriod */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetMeasurementTimingBudgetMicroSeconds(Dev,
+ &(pDeviceParameters->MeasurementTimingBudgetMicroSeconds));
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetDeviceMode(struct vl_data *Dev,
+ uint8_t DeviceMode)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("%d", (int)DeviceMode);
+
+ switch (DeviceMode) {
+ case VL_DEVICEMODE_SINGLE_RANGING:
+ case VL_DEVICEMODE_CONTINUOUS_RANGING:
+ case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+ case VL_DEVICEMODE_GPIO_DRIVE:
+ case VL_DEVICEMODE_GPIO_OSC:
+ /* Supported modes */
+ VL_SETPARAMETERFIELD(Dev, DeviceMode, DeviceMode);
+ break;
+ default:
+ /* Unsupported mode */
+ Status = VL_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetDeviceMode(struct vl_data *Dev,
+ uint8_t *pDeviceMode)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ VL_GETPARAMETERFIELD(Dev, DeviceMode, *pDeviceMode);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetRangeFractionEnable(struct vl_data *Dev, uint8_t Enable)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("%d", (int)Enable);
+
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, Enable);
+
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, RangeFractionalEnable, Enable);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetFractionEnable(struct vl_data *Dev, uint8_t *pEnabled)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, pEnabled);
+
+ if (Status == VL_ERROR_NONE)
+ *pEnabled = (*pEnabled & 1);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetHistogramMode(struct vl_data *Dev,
+ uint8_t HistogramMode)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetHistogramMode(struct vl_data *Dev,
+ uint8_t *pHistogramMode)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_set_measurement_timing_budget_micro_seconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_GetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_measurement_timing_budget_micro_seconds(Dev,
+ pMeasurementTimingBudgetMicroSeconds);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_set_vcsel_pulse_period(Dev, VcselPeriodType,
+ VCSELPulsePeriodPCLK);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_vcsel_pulse_period(Dev, VcselPeriodType,
+ pVCSELPulsePeriodPCLK);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetSequenceStepEnable(struct vl_data *Dev,
+ uint8_t SequenceStepId, uint8_t SequenceStepEnabled)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+ uint8_t SequenceConfigNew = 0;
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ &SequenceConfig);
+
+ SequenceConfigNew = SequenceConfig;
+
+ if (Status == VL_ERROR_NONE) {
+ if (SequenceStepEnabled == 1) {
+
+ /* Enable requested sequence step
+ */
+ switch (SequenceStepId) {
+ case VL_SEQUENCESTEP_TCC:
+ SequenceConfigNew |= 0x10;
+ break;
+ case VL_SEQUENCESTEP_DSS:
+ SequenceConfigNew |= 0x28;
+ break;
+ case VL_SEQUENCESTEP_MSRC:
+ SequenceConfigNew |= 0x04;
+ break;
+ case VL_SEQUENCESTEP_PRE_RANGE:
+ SequenceConfigNew |= 0x40;
+ break;
+ case VL_SEQUENCESTEP_FINAL_RANGE:
+ SequenceConfigNew |= 0x80;
+ break;
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ } else {
+ /* Disable requested sequence step
+ */
+ switch (SequenceStepId) {
+ case VL_SEQUENCESTEP_TCC:
+ SequenceConfigNew &= 0xef;
+ break;
+ case VL_SEQUENCESTEP_DSS:
+ SequenceConfigNew &= 0xd7;
+ break;
+ case VL_SEQUENCESTEP_MSRC:
+ SequenceConfigNew &= 0xfb;
+ break;
+ case VL_SEQUENCESTEP_PRE_RANGE:
+ SequenceConfigNew &= 0xbf;
+ break;
+ case VL_SEQUENCESTEP_FINAL_RANGE:
+ SequenceConfigNew &= 0x7f;
+ break;
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+ }
+
+ if (SequenceConfigNew != SequenceConfig) {
+ /* Apply New Setting */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_WrByte(Dev,
+ VL_REG_SYSTEM_SEQUENCE_CONFIG, SequenceConfigNew);
+ }
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfigNew);
+
+
+ /* Recalculate timing budget */
+ if (Status == VL_ERROR_NONE) {
+ VL_GETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+
+ VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t sequence_step_enabled(struct vl_data *Dev,
+ uint8_t SequenceStepId, uint8_t SequenceConfig,
+ uint8_t *pSequenceStepEnabled)
+{
+ int8_t Status = VL_ERROR_NONE;
+ *pSequenceStepEnabled = 0;
+
+ LOG_FUNCTION_START("");
+
+ switch (SequenceStepId) {
+ case VL_SEQUENCESTEP_TCC:
+ *pSequenceStepEnabled = (SequenceConfig & 0x10) >> 4;
+ break;
+ case VL_SEQUENCESTEP_DSS:
+ *pSequenceStepEnabled = (SequenceConfig & 0x08) >> 3;
+ break;
+ case VL_SEQUENCESTEP_MSRC:
+ *pSequenceStepEnabled = (SequenceConfig & 0x04) >> 2;
+ break;
+ case VL_SEQUENCESTEP_PRE_RANGE:
+ *pSequenceStepEnabled = (SequenceConfig & 0x40) >> 6;
+ break;
+ case VL_SEQUENCESTEP_FINAL_RANGE:
+ *pSequenceStepEnabled = (SequenceConfig & 0x80) >> 7;
+ break;
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetSequenceStepEnable(struct vl_data *Dev,
+ uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ &SequenceConfig);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev, SequenceStepId,
+ SequenceConfig, pSequenceStepEnabled);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetSequenceStepEnables(struct vl_data *Dev,
+ struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ &SequenceConfig);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL_SEQUENCESTEP_TCC, SequenceConfig,
+ &pSchedulerSequenceSteps->TccOn);
+ }
+ if (Status == VL_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL_SEQUENCESTEP_DSS, SequenceConfig,
+ &pSchedulerSequenceSteps->DssOn);
+ }
+ if (Status == VL_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL_SEQUENCESTEP_MSRC, SequenceConfig,
+ &pSchedulerSequenceSteps->MsrcOn);
+ }
+ if (Status == VL_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL_SEQUENCESTEP_PRE_RANGE, SequenceConfig,
+ &pSchedulerSequenceSteps->PreRangeOn);
+ }
+ if (Status == VL_ERROR_NONE) {
+ Status = sequence_step_enabled(Dev,
+ VL_SEQUENCESTEP_FINAL_RANGE, SequenceConfig,
+ &pSchedulerSequenceSteps->FinalRangeOn);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev,
+ uint8_t *pNumberOfSequenceSteps)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfSequenceSteps = VL_SEQUENCESTEP_NUMBER_OF_CHECKS;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetSequenceStepsInfo(
+ uint8_t SequenceStepId, char *pSequenceStepsString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_sequence_steps_info(
+ SequenceStepId,
+ pSequenceStepsString);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev,
+ uint8_t SequenceStepId, unsigned int TimeOutMilliSecs)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int8_t Status1 = VL_ERROR_NONE;
+ uint32_t TimeoutMicroSeconds = ((TimeOutMilliSecs * 1000) + 0x8000)
+ >> 16;
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+ unsigned int OldTimeOutMicroSeconds;
+
+ LOG_FUNCTION_START("");
+
+ /* Read back the current value in case we need to revert back to this.
+ */
+ Status = get_sequence_step_timeout(Dev, SequenceStepId,
+ &OldTimeOutMicroSeconds);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = set_sequence_step_timeout(Dev, SequenceStepId,
+ TimeoutMicroSeconds);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_GETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+
+ /* At this point we don't know if the requested */
+ /* value is valid, */
+ /* therefore proceed to update the entire timing budget and */
+ /* if this fails, revert back to the previous value. */
+ Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+
+ if (Status != VL_ERROR_NONE) {
+ Status1 = set_sequence_step_timeout(Dev, SequenceStepId,
+ OldTimeOutMicroSeconds);
+
+ if (Status1 == VL_ERROR_NONE) {
+ Status1 =
+ VL_SetMeasurementTimingBudgetMicroSeconds(
+ Dev,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+
+ Status = Status1;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ unsigned int *pTimeOutMilliSecs)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint32_t TimeoutMicroSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = get_sequence_step_timeout(Dev, SequenceStepId,
+ &TimeoutMicroSeconds);
+ if (Status == VL_ERROR_NONE) {
+ TimeoutMicroSeconds <<= 8;
+ *pTimeOutMilliSecs = (TimeoutMicroSeconds + 500)/1000;
+ *pTimeOutMilliSecs <<= 8;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev,
+ uint32_t InterMeasurementPeriodMilliSeconds)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t osc_calibrate_val;
+ uint32_t IMPeriodMilliSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+
+ if (Status == VL_ERROR_NONE) {
+ if (osc_calibrate_val != 0) {
+ IMPeriodMilliSeconds =
+ InterMeasurementPeriodMilliSeconds
+ * osc_calibrate_val;
+ } else {
+ IMPeriodMilliSeconds =
+ InterMeasurementPeriodMilliSeconds;
+ }
+ Status = VL_WrDWord(Dev,
+ VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+ IMPeriodMilliSeconds);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETPARAMETERFIELD(Dev,
+ InterMeasurementPeriodMilliSeconds,
+ InterMeasurementPeriodMilliSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev,
+ uint32_t *pInterMeasurementPeriodMilliSeconds)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t osc_calibrate_val;
+ uint32_t IMPeriodMilliSeconds;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL,
+ &osc_calibrate_val);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdDWord(Dev,
+ VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
+ &IMPeriodMilliSeconds);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ if (osc_calibrate_val != 0) {
+ *pInterMeasurementPeriodMilliSeconds =
+ IMPeriodMilliSeconds / osc_calibrate_val;
+ }
+ VL_SETPARAMETERFIELD(Dev,
+ InterMeasurementPeriodMilliSeconds,
+ *pInterMeasurementPeriodMilliSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev,
+ uint8_t XTalkCompensationEnable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ unsigned int TempFix1616;
+ uint16_t LinearityCorrectiveGain;
+
+ LOG_FUNCTION_START("");
+
+ LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+ if ((XTalkCompensationEnable == 0)
+ || (LinearityCorrectiveGain != 1000)) {
+ TempFix1616 = 0;
+ } else {
+ VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ TempFix1616);
+ }
+
+ /* the following register has a format 3.13 */
+ Status = VL_WrWord(Dev,
+ VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS,
+ VL_FIXPOINT1616TOFIXPOINT313(TempFix1616));
+
+ if (Status == VL_ERROR_NONE) {
+ if (XTalkCompensationEnable == 0) {
+ VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 0);
+ } else {
+ VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev,
+ uint8_t *pXTalkCompensationEnable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8);
+ *pXTalkCompensationEnable = Temp8;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetXTalkCompensationRateMegaCps(struct vl_data *Dev,
+ unsigned int XTalkCompensationRateMegaCps)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Temp8;
+ uint16_t LinearityCorrectiveGain;
+ uint16_t data;
+
+ LOG_FUNCTION_START("");
+
+ VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8);
+ LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain);
+
+ if (Temp8 == 0) { /* disabled write only internal value */
+ VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ } else {
+ /* the following register has a format 3.13 */
+ if (LinearityCorrectiveGain == 1000) {
+ data = VL_FIXPOINT1616TOFIXPOINT313(
+ XTalkCompensationRateMegaCps);
+ } else {
+ data = 0;
+ }
+
+ Status = VL_WrWord(Dev,
+ VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, data);
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetXTalkCompensationRateMegaCps(struct vl_data *Dev,
+ unsigned int *pXTalkCompensationRateMegaCps)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t Value;
+ unsigned int TempFix1616;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdWord(Dev,
+ VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, (uint16_t *)&Value);
+ if (Status == VL_ERROR_NONE) {
+ if (Value == 0) {
+ /* the Xtalk is disabled return value from memory */
+ VL_GETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps, TempFix1616);
+ *pXTalkCompensationRateMegaCps = TempFix1616;
+ VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 0);
+ } else {
+ TempFix1616 = VL_FIXPOINT313TOFIXPOINT1616(Value);
+ *pXTalkCompensationRateMegaCps = TempFix1616;
+ VL_SETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps, TempFix1616);
+ VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetRefCalibration(struct vl_data *Dev, uint8_t VhvSettings,
+ uint8_t PhaseCal)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_set_ref_calibration(Dev, VhvSettings, PhaseCal);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetRefCalibration(struct vl_data *Dev, uint8_t *pVhvSettings,
+ uint8_t *pPhaseCal)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_ref_calibration(Dev, pVhvSettings, pPhaseCal);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/*
+ * CHECK LIMIT FUNCTIONS
+ */
+
+int8_t VL_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfLimitCheck = VL_CHECKENABLE_NUMBER_OF_CHECKS;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetLimitCheckInfo(struct vl_data *Dev, uint16_t LimitCheckId,
+ char *pLimitCheckString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_limit_check_info(Dev, LimitCheckId,
+ pLimitCheckString);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetLimitCheckStatus(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckStatus)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL_ERROR_INVALID_PARAMS;
+ } else {
+
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ LimitCheckId, Temp8);
+
+ *pLimitCheckStatus = Temp8;
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetLimitCheckEnable(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t LimitCheckEnable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ unsigned int TempFix1616 = 0;
+ uint8_t LimitCheckEnableInt = 0;
+ uint8_t LimitCheckDisable = 0;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL_ERROR_INVALID_PARAMS;
+ } else {
+ if (LimitCheckEnable == 0) {
+ TempFix1616 = 0;
+ LimitCheckEnableInt = 0;
+ LimitCheckDisable = 1;
+
+ } else {
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, TempFix1616);
+ LimitCheckDisable = 0;
+ /* this to be sure to have either 0 or 1 */
+ LimitCheckEnableInt = 1;
+ }
+
+ switch (LimitCheckId) {
+
+ case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* internal computation: */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ LimitCheckEnableInt);
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+
+ Status = VL_WrWord(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+ VL_FIXPOINT1616TOFIXPOINT97(TempFix1616));
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+
+ /* internal computation: */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP,
+ LimitCheckEnableInt);
+
+ break;
+
+ case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+
+ /* internal computation: */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ LimitCheckEnableInt);
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+
+ Temp8 = (uint8_t)(LimitCheckDisable << 1);
+ Status = VL_UpdateByte(Dev,
+ VL_REG_MSRC_CONFIG_CONTROL,
+ 0xFE, Temp8);
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+
+ Temp8 = (uint8_t)(LimitCheckDisable << 4);
+ Status = VL_UpdateByte(Dev,
+ VL_REG_MSRC_CONFIG_CONTROL,
+ 0xEF, Temp8);
+
+ break;
+
+
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+
+ }
+
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ if (LimitCheckEnable == 0) {
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, 0);
+ } else {
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, 1);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetLimitCheckEnable(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckEnable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL_ERROR_INVALID_PARAMS;
+ *pLimitCheckEnable = 0;
+ } else {
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable,
+ LimitCheckId, Temp8);
+ *pLimitCheckEnable = Temp8;
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId,
+ unsigned int LimitCheckValue)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Temp8;
+
+ LOG_FUNCTION_START("");
+
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, LimitCheckId,
+ Temp8);
+
+ if (Temp8 == 0) { /* disabled write only internal value */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, LimitCheckValue);
+ } else {
+
+ switch (LimitCheckId) {
+
+ case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* internal computation: */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ LimitCheckValue);
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+
+ Status = VL_WrWord(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+ VL_FIXPOINT1616TOFIXPOINT97(
+ LimitCheckValue));
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+
+ /* internal computation: */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP,
+ LimitCheckValue);
+
+ break;
+
+ case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+
+ /* internal computation: */
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ LimitCheckValue);
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+ case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+
+ Status = VL_WrWord(Dev,
+ VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
+ VL_FIXPOINT1616TOFIXPOINT97(
+ LimitCheckValue));
+
+ break;
+
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ LimitCheckId, LimitCheckValue);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId,
+ unsigned int *pLimitCheckValue)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t EnableZeroValue = 0;
+ uint16_t Temp16;
+ unsigned int TempFix1616;
+
+ LOG_FUNCTION_START("");
+
+ switch (LimitCheckId) {
+
+ case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* internal computation: */
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE, TempFix1616);
+ EnableZeroValue = 0;
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ Status = VL_RdWord(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
+ &Temp16);
+ if (Status == VL_ERROR_NONE)
+ TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16);
+
+
+ EnableZeroValue = 1;
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+ /* internal computation: */
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP, TempFix1616);
+ EnableZeroValue = 0;
+ break;
+
+ case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+ /* internal computation: */
+ VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, TempFix1616);
+ EnableZeroValue = 0;
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+ case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+ Status = VL_RdWord(Dev,
+ VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
+ &Temp16);
+ if (Status == VL_ERROR_NONE)
+ TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16);
+
+
+ EnableZeroValue = 0;
+ break;
+
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+
+ }
+
+ if (Status == VL_ERROR_NONE) {
+
+ if (EnableZeroValue == 1) {
+
+ if (TempFix1616 == 0) {
+ /* disabled: return value from memory */
+ VL_GETARRAYPARAMETERFIELD(Dev,
+ LimitChecksValue, LimitCheckId,
+ TempFix1616);
+ *pLimitCheckValue = TempFix1616;
+ VL_SETARRAYPARAMETERFIELD(Dev,
+ LimitChecksEnable, LimitCheckId, 0);
+ } else {
+ *pLimitCheckValue = TempFix1616;
+ VL_SETARRAYPARAMETERFIELD(Dev,
+ LimitChecksValue, LimitCheckId,
+ TempFix1616);
+ VL_SETARRAYPARAMETERFIELD(Dev,
+ LimitChecksEnable, LimitCheckId, 1);
+ }
+ } else {
+ *pLimitCheckValue = TempFix1616;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev,
+ uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent)
+{
+ int8_t Status = VL_ERROR_NONE;
+ struct VL_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) {
+ Status = VL_ERROR_INVALID_PARAMS;
+ } else {
+ switch (LimitCheckId) {
+ case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+ /* Need to run a ranging to have the latest values */
+ *pLimitCheckCurrent = PALDevDataGet(Dev, SigmaEstimate);
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+ /* Need to run a ranging to have the latest values */
+ *pLimitCheckCurrent = PALDevDataGet(Dev,
+ LastSignalRefMcps);
+
+ break;
+
+ case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+ /* Need to run a ranging to have the latest values */
+ LastRangeDataBuffer = PALDevDataGet(Dev,
+ LastRangeMeasure);
+ *pLimitCheckCurrent =
+ LastRangeDataBuffer.SignalRateRtnMegaCps;
+
+ break;
+
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+/*
+ * WRAPAROUND Check
+ */
+int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev,
+ uint8_t WrapAroundCheckEnable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte;
+ uint8_t WrapAroundCheckEnableInt;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &Byte);
+ if (WrapAroundCheckEnable == 0) {
+ /* Disable wraparound */
+ Byte = Byte & 0x7F;
+ WrapAroundCheckEnableInt = 0;
+ } else {
+ /*Enable wraparound */
+ Byte = Byte | 0x80;
+ WrapAroundCheckEnableInt = 1;
+ }
+
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, Byte);
+
+ if (Status == VL_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, Byte);
+ VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+ WrapAroundCheckEnableInt);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev,
+ uint8_t *pWrapAroundCheckEnable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &data);
+ if (Status == VL_ERROR_NONE) {
+ PALDevDataSet(Dev, SequenceConfig, data);
+ if (data & (0x01 << 7))
+ *pWrapAroundCheckEnable = 0x01;
+ else
+ *pWrapAroundCheckEnable = 0x00;
+ }
+ if (Status == VL_ERROR_NONE) {
+ VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable,
+ *pWrapAroundCheckEnable);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetDmaxCalParameters(struct vl_data *Dev,
+ uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps)
+{
+ int8_t Status = VL_ERROR_NONE;
+ unsigned int SignalRateRtnMegaCpsTemp = 0;
+
+ LOG_FUNCTION_START("");
+
+ /* Check if one of input parameter is zero, in that case the */
+ /* value are get from NVM */
+ if ((RangeMilliMeter == 0) || (SignalRateRtnMegaCps == 0)) {
+ /* NVM parameters */
+ /* Run VL_get_info_from_device wit option 4 to get */
+ /* signal rate at 400 mm if the value have been already */
+ /* get this function will return with no access to device */
+ VL_get_info_from_device(Dev, 4);
+
+ SignalRateRtnMegaCpsTemp = VL_GETDEVICESPECIFICPARAMETER(
+ Dev, SignalRateMeasFixed400mm);
+
+ PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400);
+ PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+ SignalRateRtnMegaCpsTemp);
+ } else {
+ /* User parameters */
+ PALDevDataSet(Dev, DmaxCalRangeMilliMeter, RangeMilliMeter);
+ PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps,
+ SignalRateRtnMegaCps);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetDmaxCalParameters(struct vl_data *Dev,
+ uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pRangeMilliMeter = PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
+ *pSignalRateRtnMegaCps = PALDevDataGet(Dev,
+ DmaxCalSignalRateRtnMegaCps);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Parameters Functions */
+
+/* Group PAL Measurement Functions */
+int8_t VL_PerformSingleMeasurement(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t DeviceMode;
+
+ LOG_FUNCTION_START("");
+
+ /* Get Current DeviceMode */
+ Status = VL_GetDeviceMode(Dev, &DeviceMode);
+
+ /* Start immediately to run a single ranging measurement in case of */
+ /* single ranging or single histogram */
+ if (Status == VL_ERROR_NONE
+ && DeviceMode == VL_DEVICEMODE_SINGLE_RANGING)
+ Status = VL_StartMeasurement(Dev);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_measurement_poll_for_completion(Dev);
+
+
+ /* Change PAL State in case of single ranging or single histogram */
+ if (Status == VL_ERROR_NONE
+ && DeviceMode == VL_DEVICEMODE_SINGLE_RANGING)
+ PALDevDataSet(Dev, PalState, VL_STATE_IDLE);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_PerformSingleHistogramMeasurement(struct vl_data *Dev,
+ struct VL_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_PerformRefCalibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_perform_ref_calibration(Dev, pVhvSettings,
+ pPhaseCal, 1);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev,
+ uint32_t TimeoutMs, unsigned int *pXtalkPerSpad,
+ uint8_t *pAmbientTooHigh)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented on VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_PerformXTalkCalibration(struct vl_data *Dev,
+ unsigned int XTalkCalDistance,
+ unsigned int *pXTalkCompensationRateMegaCps)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_perform_xtalk_calibration(Dev, XTalkCalDistance,
+ pXTalkCompensationRateMegaCps);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_PerformOffsetCalibration(struct vl_data *Dev,
+ unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_perform_offset_calibration(Dev, CalDistanceMilliMeter,
+ pOffsetMicroMeter);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_CheckAndLoadInterruptSettings(struct vl_data *Dev,
+ uint8_t StartNotStopFlag)
+{
+ uint8_t InterruptConfig;
+ unsigned int ThresholdLow;
+ unsigned int ThresholdHigh;
+ int8_t Status = VL_ERROR_NONE;
+
+ InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality);
+
+ if ((InterruptConfig ==
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW) ||
+ (InterruptConfig ==
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH) ||
+ (InterruptConfig ==
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT)) {
+
+ Status = VL_GetInterruptThresholds(Dev,
+ VL_DEVICEMODE_CONTINUOUS_RANGING,
+ &ThresholdLow, &ThresholdHigh);
+
+ if (((ThresholdLow > 255*65536) ||
+ (ThresholdHigh > 255*65536)) &&
+ (Status == VL_ERROR_NONE)) {
+
+ if (StartNotStopFlag != 0) {
+ Status = VL_load_tuning_settings(Dev,
+ InterruptThresholdSettings);
+ } else {
+ Status |= VL_WrByte(Dev, 0xFF, 0x04);
+ Status |= VL_WrByte(Dev, 0x70, 0x00);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL_WrByte(Dev, 0x80, 0x00);
+ }
+
+ }
+
+
+ }
+
+ return Status;
+
+}
+
+
+int8_t VL_StartMeasurement(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t DeviceMode;
+ uint8_t Byte;
+ uint8_t StartStopByte = VL_REG_SYSRANGE_MODE_START_STOP;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ /* Get Current DeviceMode */
+ VL_GetDeviceMode(Dev, &DeviceMode);
+
+ Status = VL_WrByte(Dev, 0x80, 0x01);
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status = VL_WrByte(Dev, 0x00, 0x00);
+ Status = VL_WrByte(Dev, 0x91, PALDevDataGet(Dev, StopVariable));
+ Status = VL_WrByte(Dev, 0x00, 0x01);
+ Status = VL_WrByte(Dev, 0xFF, 0x00);
+ Status = VL_WrByte(Dev, 0x80, 0x00);
+
+ switch (DeviceMode) {
+ case VL_DEVICEMODE_SINGLE_RANGING:
+ Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x01);
+
+ Byte = StartStopByte;
+ if (Status == VL_ERROR_NONE) {
+ /* Wait until start bit has been cleared */
+ LoopNb = 0;
+ do {
+ if (LoopNb > 0)
+ Status = VL_RdByte(Dev,
+ VL_REG_SYSRANGE_START, &Byte);
+ LoopNb = LoopNb + 1;
+ } while (((Byte & StartStopByte) == StartStopByte)
+ && (Status == VL_ERROR_NONE)
+ && (LoopNb < VL_DEFAULT_MAX_LOOP));
+
+ if (LoopNb >= VL_DEFAULT_MAX_LOOP)
+ Status = VL_ERROR_TIME_OUT;
+
+ }
+
+ break;
+ case VL_DEVICEMODE_CONTINUOUS_RANGING:
+ /* Back-to-back mode */
+
+ /* Check if need to apply interrupt settings */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_CheckAndLoadInterruptSettings(Dev, 1);
+
+ Status = VL_WrByte(Dev,
+ VL_REG_SYSRANGE_START,
+ VL_REG_SYSRANGE_MODE_BACKTOBACK);
+ if (Status == VL_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL_STATE_RUNNING);
+ }
+ break;
+ case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
+ /* Continuous mode */
+ /* Check if need to apply interrupt settings */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_CheckAndLoadInterruptSettings(Dev, 1);
+
+ Status = VL_WrByte(Dev,
+ VL_REG_SYSRANGE_START,
+ VL_REG_SYSRANGE_MODE_TIMED);
+
+ if (Status == VL_ERROR_NONE) {
+ /* Set PAL State to Running */
+ PALDevDataSet(Dev, PalState, VL_STATE_RUNNING);
+ }
+ break;
+ default:
+ /* Selected mode not supported */
+ Status = VL_ERROR_MODE_NOT_SUPPORTED;
+ }
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_StopMeasurement(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START,
+ VL_REG_SYSRANGE_MODE_SINGLESHOT);
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status = VL_WrByte(Dev, 0x00, 0x00);
+ Status = VL_WrByte(Dev, 0x91, 0x00);
+ Status = VL_WrByte(Dev, 0x00, 0x01);
+ Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL_ERROR_NONE) {
+ /* Set PAL State to Idle */
+ PALDevDataSet(Dev, PalState, VL_STATE_IDLE);
+ }
+
+ /* Check if need to apply interrupt settings */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_CheckAndLoadInterruptSettings(Dev, 0);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetMeasurementDataReady(struct vl_data *Dev,
+ uint8_t *pMeasurementDataReady)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SysRangeStatusRegister;
+ uint8_t InterruptConfig;
+ uint32_t InterruptMask;
+
+ LOG_FUNCTION_START("");
+
+ InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality);
+
+ if (InterruptConfig ==
+ VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
+ Status = VL_GetInterruptMaskStatus(Dev, &InterruptMask);
+ if (InterruptMask ==
+ VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY)
+ *pMeasurementDataReady = 1;
+ else
+ *pMeasurementDataReady = 0;
+ } else {
+ Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS,
+ &SysRangeStatusRegister);
+ if (Status == VL_ERROR_NONE) {
+ if (SysRangeStatusRegister & 0x01)
+ *pMeasurementDataReady = 1;
+ else
+ *pMeasurementDataReady = 0;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_WaitDeviceReadyForNewMeasurement(struct vl_data *Dev,
+ uint32_t MaxLoop)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented for VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+int8_t VL_GetRangingMeasurementData(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t DeviceRangeStatus;
+ uint8_t RangeFractionalEnable;
+ uint8_t PalRangeStatus;
+ uint8_t XTalkCompensationEnable;
+ uint16_t AmbientRate;
+ unsigned int SignalRate;
+ uint16_t XTalkCompensationRateMegaCps;
+ uint16_t EffectiveSpadRtnCount;
+ uint16_t tmpuint16;
+ uint16_t XtalkRangeMilliMeter;
+ uint16_t LinearityCorrectiveGain;
+ uint8_t localBuffer[12];
+ struct VL_RangingMeasurementData_t LastRangeDataBuffer;
+
+ LOG_FUNCTION_START("");
+
+ /*
+ * use multi read even if some registers are not useful, result will
+ * be more efficient
+ * start reading at 0x14 dec20
+ * end reading at 0x21 dec33 total 14 bytes to read
+ */
+ Status = VL_ReadMulti(Dev, 0x14, localBuffer, 12);
+
+ if (Status == VL_ERROR_NONE) {
+
+ pRangingMeasurementData->ZoneId = 0; /* Only one zone */
+ pRangingMeasurementData->TimeStamp = 0; /* Not Implemented */
+
+ tmpuint16 = VL_MAKEUINT16(localBuffer[11],
+ localBuffer[10]);
+ /* cut1.1 if SYSTEM__RANGE_CONFIG if 1 range is 2bits fractional
+ *(format 11.2) else no fractional
+ */
+
+ pRangingMeasurementData->MeasurementTimeUsec = 0;
+
+ SignalRate = VL_FIXPOINT97TOFIXPOINT1616(
+ VL_MAKEUINT16(localBuffer[7], localBuffer[6]));
+ /* peak_signal_count_rate_rtn_mcps */
+ pRangingMeasurementData->SignalRateRtnMegaCps = SignalRate;
+
+ AmbientRate = VL_MAKEUINT16(localBuffer[9],
+ localBuffer[8]);
+ pRangingMeasurementData->AmbientRateRtnMegaCps =
+ VL_FIXPOINT97TOFIXPOINT1616(AmbientRate);
+
+ EffectiveSpadRtnCount = VL_MAKEUINT16(localBuffer[3],
+ localBuffer[2]);
+ /* EffectiveSpadRtnCount is 8.8 format */
+ pRangingMeasurementData->EffectiveSpadRtnCount =
+ EffectiveSpadRtnCount;
+
+ DeviceRangeStatus = localBuffer[0];
+
+ /* Get Linearity Corrective Gain */
+ LinearityCorrectiveGain = PALDevDataGet(Dev,
+ LinearityCorrectiveGain);
+
+ /* Get ranging configuration */
+ RangeFractionalEnable = PALDevDataGet(Dev,
+ RangeFractionalEnable);
+
+ if (LinearityCorrectiveGain != 1000) {
+
+ tmpuint16 = (uint16_t)((LinearityCorrectiveGain
+ * tmpuint16 + 500) / 1000);
+
+ /* Implement Xtalk */
+ VL_GETPARAMETERFIELD(Dev,
+ XTalkCompensationRateMegaCps,
+ XTalkCompensationRateMegaCps);
+ VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable,
+ XTalkCompensationEnable);
+
+ if (XTalkCompensationEnable) {
+
+ if ((SignalRate
+ - ((XTalkCompensationRateMegaCps
+ * EffectiveSpadRtnCount) >> 8))
+ <= 0) {
+ if (RangeFractionalEnable)
+ XtalkRangeMilliMeter = 8888;
+ else
+ XtalkRangeMilliMeter = 8888
+ << 2;
+ } else {
+ XtalkRangeMilliMeter =
+ (tmpuint16 * SignalRate)
+ / (SignalRate
+ - ((XTalkCompensationRateMegaCps
+ * EffectiveSpadRtnCount)
+ >> 8));
+ }
+
+ tmpuint16 = XtalkRangeMilliMeter;
+ }
+
+ }
+
+ if (RangeFractionalEnable) {
+ pRangingMeasurementData->RangeMilliMeter =
+ (uint16_t)((tmpuint16) >> 2);
+ pRangingMeasurementData->RangeFractionalPart =
+ (uint8_t)((tmpuint16 & 0x03) << 6);
+ } else {
+ pRangingMeasurementData->RangeMilliMeter = tmpuint16;
+ pRangingMeasurementData->RangeFractionalPart = 0;
+ }
+
+ /*
+ * For a standard definition of RangeStatus, this should
+ * return 0 in case of good result after a ranging
+ * The range status depends on the device so call a device
+ * specific function to obtain the right Status.
+ */
+ Status |= VL_get_pal_range_status(Dev, DeviceRangeStatus,
+ SignalRate, EffectiveSpadRtnCount,
+ pRangingMeasurementData, &PalRangeStatus);
+
+ if (Status == VL_ERROR_NONE)
+ pRangingMeasurementData->RangeStatus = PalRangeStatus;
+
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ /* Copy last read data into Dev buffer */
+ LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure);
+
+ LastRangeDataBuffer.RangeMilliMeter =
+ pRangingMeasurementData->RangeMilliMeter;
+ LastRangeDataBuffer.RangeFractionalPart =
+ pRangingMeasurementData->RangeFractionalPart;
+ LastRangeDataBuffer.RangeDMaxMilliMeter =
+ pRangingMeasurementData->RangeDMaxMilliMeter;
+ LastRangeDataBuffer.MeasurementTimeUsec =
+ pRangingMeasurementData->MeasurementTimeUsec;
+ LastRangeDataBuffer.SignalRateRtnMegaCps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+ LastRangeDataBuffer.AmbientRateRtnMegaCps =
+ pRangingMeasurementData->AmbientRateRtnMegaCps;
+ LastRangeDataBuffer.EffectiveSpadRtnCount =
+ pRangingMeasurementData->EffectiveSpadRtnCount;
+ LastRangeDataBuffer.RangeStatus =
+ pRangingMeasurementData->RangeStatus;
+
+ PALDevDataSet(Dev, LastRangeMeasure, LastRangeDataBuffer);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev,
+ unsigned int *pMeasurementRefSignal)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SignalRefClipLimitCheckEnable = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_GetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP,
+ &SignalRefClipLimitCheckEnable);
+ if (SignalRefClipLimitCheckEnable != 0)
+ *pMeasurementRefSignal = PALDevDataGet(Dev, LastSignalRefMcps);
+ else
+ Status = VL_ERROR_INVALID_COMMAND;
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev,
+ struct VL_HistogramMeasurementData_t *pHistogramMeasurementData)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_PerformSingleRangingMeasurement(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ /* This function will do a complete single ranging */
+ /* Here we fix the mode! */
+ Status = VL_SetDeviceMode(Dev, VL_DEVICEMODE_SINGLE_RANGING);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_PerformSingleMeasurement(Dev);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetRangingMeasurementData(Dev,
+ pRangingMeasurementData);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_ClearInterruptMask(Dev, 0);
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetNumberOfROIZones(struct vl_data *Dev,
+ uint8_t NumberOfROIZones)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ if (NumberOfROIZones != 1)
+ Status = VL_ERROR_INVALID_PARAMS;
+
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetNumberOfROIZones(struct vl_data *Dev,
+ uint8_t *pNumberOfROIZones)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pNumberOfROIZones = 1;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev,
+ uint8_t *pMaxNumberOfROIZones)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ *pMaxNumberOfROIZones = 1;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Measurement Functions */
+
+int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+ uint8_t DeviceMode, uint8_t Functionality,
+ uint8_t Polarity)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ if (Pin != 0) {
+ Status = VL_ERROR_GPIO_NOT_EXISTING;
+ } else if (DeviceMode == VL_DEVICEMODE_GPIO_DRIVE) {
+ if (Polarity == VL_INTERRUPTPOLARITY_LOW)
+ data = 0x10;
+ else
+ data = 1;
+
+ Status = VL_WrByte(Dev,
+ VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, data);
+
+ } else if (DeviceMode == VL_DEVICEMODE_GPIO_OSC) {
+
+ Status |= VL_WrByte(Dev, 0xff, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x00);
+ Status |= VL_WrByte(Dev, 0x80, 0x01);
+ Status |= VL_WrByte(Dev, 0x85, 0x02);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x04);
+ Status |= VL_WrByte(Dev, 0xcd, 0x00);
+ Status |= VL_WrByte(Dev, 0xcc, 0x11);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x07);
+ Status |= VL_WrByte(Dev, 0xbe, 0x00);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x06);
+ Status |= VL_WrByte(Dev, 0xcc, 0x09);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x00);
+ Status |= VL_WrByte(Dev, 0xff, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x00);
+
+ } else {
+
+ if (Status == VL_ERROR_NONE) {
+ switch (Functionality) {
+ case VL_GPIOFUNCTIONALITY_OFF:
+ data = 0x00;
+ break;
+ case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW:
+ data = 0x01;
+ break;
+ case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH:
+ data = 0x02;
+ break;
+ case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT:
+ data = 0x03;
+ break;
+ case VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY:
+ data = 0x04;
+ break;
+ default:
+ Status =
+ VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, data);
+
+ if (Status == VL_ERROR_NONE) {
+ if (Polarity == VL_INTERRUPTPOLARITY_LOW)
+ data = 0;
+ else
+ data = (uint8_t)(1 << 4);
+
+ Status = VL_UpdateByte(Dev,
+ VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, 0xEF, data);
+ }
+
+ if (Status == VL_ERROR_NONE)
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ Pin0GpioFunctionality, Functionality);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_ClearInterruptMask(Dev, 0);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin,
+ uint8_t *pDeviceMode,
+ uint8_t *pFunctionality,
+ uint8_t *pPolarity)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t GpioFunctionality;
+ uint8_t data;
+
+ LOG_FUNCTION_START("");
+
+ /* pDeviceMode not managed by Ewok it return the current mode */
+
+ Status = VL_GetDeviceMode(Dev, pDeviceMode);
+
+ if (Status == VL_ERROR_NONE) {
+ if (Pin != 0) {
+ Status = VL_ERROR_GPIO_NOT_EXISTING;
+ } else {
+ Status = VL_RdByte(Dev,
+ VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, &data);
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ switch (data & 0x07) {
+ case 0x00:
+ GpioFunctionality = VL_GPIOFUNCTIONALITY_OFF;
+ break;
+ case 0x01:
+ GpioFunctionality =
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW;
+ break;
+ case 0x02:
+ GpioFunctionality =
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH;
+ break;
+ case 0x03:
+ GpioFunctionality =
+ VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT;
+ break;
+ case 0x04:
+ GpioFunctionality =
+ VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+ break;
+ default:
+ Status = VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
+ }
+ }
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_RdByte(Dev,
+ VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, &data);
+
+ if (Status == VL_ERROR_NONE) {
+ if ((data & (uint8_t)(1 << 4)) == 0)
+ *pPolarity = VL_INTERRUPTPOLARITY_LOW;
+ else
+ *pPolarity = VL_INTERRUPTPOLARITY_HIGH;
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ *pFunctionality = GpioFunctionality;
+ VL_SETDEVICESPECIFICPARAMETER(Dev, Pin0GpioFunctionality,
+ GpioFunctionality);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetInterruptThresholds(struct vl_data *Dev,
+ uint8_t DeviceMode, unsigned int ThresholdLow,
+ unsigned int ThresholdHigh)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t Threshold16;
+
+ LOG_FUNCTION_START("");
+
+ /* no dependency on DeviceMode for Ewok */
+ /* Need to divide by 2 because the FW will apply a x2 */
+ Threshold16 = (uint16_t)((ThresholdLow >> 17) & 0x00fff);
+ Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_LOW,
+ Threshold16);
+
+ if (Status == VL_ERROR_NONE) {
+ /* Need to divide by 2 because the FW will apply a x2 */
+ Threshold16 = (uint16_t)((ThresholdHigh >> 17) & 0x00fff);
+ Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_HIGH,
+ Threshold16);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetInterruptThresholds(struct vl_data *Dev,
+ uint8_t DeviceMode, unsigned int *pThresholdLow,
+ unsigned int *pThresholdHigh)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t Threshold16;
+
+ LOG_FUNCTION_START("");
+
+ /* no dependency on DeviceMode for Ewok */
+
+ Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_LOW,
+ &Threshold16);
+ /* Need to multiply by 2 because the FW will apply a x2 */
+ *pThresholdLow = (unsigned int)((0x00fff & Threshold16) << 17);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_HIGH,
+ &Threshold16);
+ /* Need to multiply by 2 because the FW will apply a x2 */
+ *pThresholdHigh =
+ (unsigned int)((0x00fff & Threshold16) << 17);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetStopCompletedStatus(struct vl_data *Dev,
+ uint32_t *pStopStatus)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte = 0;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_RdByte(Dev, 0x04, &Byte);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, 0xFF, 0x0);
+
+ *pStopStatus = Byte;
+
+ if (Byte == 0) {
+ Status = VL_WrByte(Dev, 0x80, 0x01);
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status = VL_WrByte(Dev, 0x00, 0x00);
+ Status = VL_WrByte(Dev, 0x91,
+ PALDevDataGet(Dev, StopVariable));
+ Status = VL_WrByte(Dev, 0x00, 0x01);
+ Status = VL_WrByte(Dev, 0xFF, 0x00);
+ Status = VL_WrByte(Dev, 0x80, 0x00);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* Group PAL Interrupt Functions */
+int8_t VL_ClearInterruptMask(struct vl_data *Dev,
+ uint32_t InterruptMask)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t LoopCount;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ /* clear bit 0 range interrupt, bit 1 error interrupt */
+ LoopCount = 0;
+ do {
+ Status = VL_WrByte(Dev,
+ VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x01);
+ Status |= VL_WrByte(Dev,
+ VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x00);
+ Status |= VL_RdByte(Dev,
+ VL_REG_RESULT_INTERRUPT_STATUS, &Byte);
+ LoopCount++;
+ } while (((Byte & 0x07) != 0x00)
+ && (LoopCount < 3)
+ && (Status == VL_ERROR_NONE));
+
+
+ if (LoopCount >= 3)
+ Status = VL_ERROR_INTERRUPT_NOT_CLEARED;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev,
+ uint32_t *pInterruptMaskStatus)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_RdByte(Dev, VL_REG_RESULT_INTERRUPT_STATUS,
+ &Byte);
+ *pInterruptMaskStatus = Byte & 0x07;
+
+ if (Byte & 0x18)
+ Status = VL_ERROR_RANGE_ERROR;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_EnableInterruptMask(struct vl_data *Dev,
+ uint32_t InterruptMask)
+{
+ int8_t Status = VL_ERROR_NOT_IMPLEMENTED;
+
+ LOG_FUNCTION_START("");
+
+ /* not implemented for VL53L0X */
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* End Group PAL Interrupt Functions */
+
+/* Group SPAD functions */
+
+int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev,
+ uint16_t SpadAmbientDamperThreshold)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrWord(Dev, 0x40, SpadAmbientDamperThreshold);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev,
+ uint16_t *pSpadAmbientDamperThreshold)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_RdWord(Dev, 0x40, pSpadAmbientDamperThreshold);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev,
+ uint16_t SpadAmbientDamperFactor)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Byte = (uint8_t)(SpadAmbientDamperFactor & 0x00FF);
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrByte(Dev, 0x42, Byte);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev,
+ uint16_t *pSpadAmbientDamperFactor)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t Byte;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_RdByte(Dev, 0x42, &Byte);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+ *pSpadAmbientDamperFactor = (uint16_t)Byte;
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+/* END Group SPAD functions */
+
+/*****************************************************************************
+ * Internal functions
+ *****************************************************************************/
+
+int8_t VL_SetReferenceSpads(struct vl_data *Dev, uint32_t count,
+ uint8_t isApertureSpads)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_set_reference_spads(Dev, count, isApertureSpads);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_GetReferenceSpads(struct vl_data *Dev, uint32_t *pSpadCount,
+ uint8_t *pIsApertureSpads)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_reference_spads(Dev, pSpadCount, pIsApertureSpads);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_PerformRefSpadManagement(struct vl_data *Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_perform_ref_spad_management(Dev, refSpadCount,
+ isApertureSpads);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c
new file mode 100644
index 0000000..08b5ce2
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c
@@ -0,0 +1,1266 @@
+/*
+ * vl53l0x_api_calibration.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_calibration.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+#define REF_ARRAY_SPAD_0 0
+#define REF_ARRAY_SPAD_5 5
+#define REF_ARRAY_SPAD_10 10
+
+uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5,
+ REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 };
+
+int8_t VL_perform_xtalk_calibration(struct vl_data *Dev,
+ unsigned int XTalkCalDistance,
+ unsigned int *pXTalkCompensationRateMegaCps)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t sum_ranging = 0;
+ uint16_t sum_spads = 0;
+ unsigned int sum_signalRate = 0;
+ unsigned int total_count = 0;
+ uint8_t xtalk_meas = 0;
+ struct VL_RangingMeasurementData_t RangingMeasurementData;
+ unsigned int xTalkStoredMeanSignalRate;
+ unsigned int xTalkStoredMeanRange;
+ unsigned int xTalkStoredMeanRtnSpads;
+ uint32_t signalXTalkTotalPerSpad;
+ uint32_t xTalkStoredMeanRtnSpadsAsInt;
+ uint32_t xTalkCalDistanceAsInt;
+ unsigned int XTalkCompensationRateMegaCps;
+
+ if (XTalkCalDistance <= 0)
+ Status = VL_ERROR_INVALID_PARAMS;
+
+ /* Disable the XTalk compensation */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetXTalkCompensationEnable(Dev, 0);
+
+ /* Disable the RIT */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_SetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+ }
+
+ /* Perform 50 measurements and compute the averages */
+ if (Status == VL_ERROR_NONE) {
+ sum_ranging = 0;
+ sum_spads = 0;
+ sum_signalRate = 0;
+ total_count = 0;
+ for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) {
+ Status = VL_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+
+ if (Status != VL_ERROR_NONE)
+ break;
+
+ /* The range is valid when RangeStatus = 0 */
+ if (RangingMeasurementData.RangeStatus == 0) {
+ sum_ranging = sum_ranging +
+ RangingMeasurementData.RangeMilliMeter;
+ sum_signalRate = sum_signalRate +
+ RangingMeasurementData.SignalRateRtnMegaCps;
+ sum_spads = sum_spads +
+ RangingMeasurementData.EffectiveSpadRtnCount
+ / 256;
+ total_count = total_count + 1;
+ }
+ }
+
+ /* no valid values found */
+ if (total_count == 0)
+ Status = VL_ERROR_RANGE_ERROR;
+
+ }
+
+
+ if (Status == VL_ERROR_NONE) {
+ /* unsigned int / uint16_t = unsigned int */
+ xTalkStoredMeanSignalRate = sum_signalRate / total_count;
+ xTalkStoredMeanRange = (unsigned int)((uint32_t)(
+ sum_ranging << 16) / total_count);
+ xTalkStoredMeanRtnSpads = (unsigned int)((uint32_t)(
+ sum_spads << 16) / total_count);
+
+ /* Round Mean Spads to Whole Number.
+ * Typically the calculated mean SPAD count is a whole number
+ * or very close to a whole
+ * number, therefore any truncation will not result in a
+ * significant loss in accuracy.
+ * Also, for a grey target at a typical distance of around
+ * 400mm, around 220 SPADs will
+ * be enabled, therefore, any truncation will result in a loss
+ * of accuracy of less than
+ * 0.5%.
+ */
+ xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads +
+ 0x8000) >> 16;
+
+ /* Round Cal Distance to Whole Number. */
+ /* Note that the cal distance is in mm, */
+ /* therefore no resolution is lost.*/
+ xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16;
+
+ if (xTalkStoredMeanRtnSpadsAsInt == 0 ||
+ xTalkCalDistanceAsInt == 0 ||
+ xTalkStoredMeanRange >= XTalkCalDistance) {
+ XTalkCompensationRateMegaCps = 0;
+ } else {
+ /* Round Cal Distance to Whole Number. */
+ /* Note that the cal distance is in mm, therefore no */
+ /* resolution is lost.*/
+ xTalkCalDistanceAsInt = (XTalkCalDistance +
+ 0x8000) >> 16;
+
+ /* Apply division by mean spad count early in the */
+ /* calculation to keep the numbers small. */
+ /* This ensures we can maintain a 32bit calculation. */
+ /* Fixed1616 / int := Fixed1616 */
+ signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) /
+ xTalkStoredMeanRtnSpadsAsInt;
+
+ /* Complete the calculation for total Signal */
+ /* XTalk per SPAD */
+ /* Fixed1616 * (Fixed1616 - Fixed1616/int) := */
+ /* (2^16 * Fixed1616) */
+
+ signalXTalkTotalPerSpad *= ((1 << 16) -
+ (xTalkStoredMeanRange / xTalkCalDistanceAsInt));
+
+ /* Round from 2^16 * Fixed1616, to Fixed1616. */
+ XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad
+ + 0x8000) >> 16;
+ }
+
+ *pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps;
+
+ /* Enable the XTalk compensation */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetXTalkCompensationEnable(Dev, 1);
+
+ /* Enable the XTalk compensation */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetXTalkCompensationRateMegaCps(Dev,
+ XTalkCompensationRateMegaCps);
+
+ }
+
+ return Status;
+}
+
+int8_t VL_perform_offset_calibration(struct vl_data *Dev,
+ unsigned int CalDistanceMilliMeter,
+ int32_t *pOffsetMicroMeter)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t sum_ranging = 0;
+ unsigned int total_count = 0;
+ struct VL_RangingMeasurementData_t RangingMeasurementData;
+ unsigned int StoredMeanRange;
+ uint32_t StoredMeanRangeAsInt;
+ uint32_t CalDistanceAsInt_mm;
+ uint8_t SequenceStepEnabled;
+ int meas = 0;
+
+ if (CalDistanceMilliMeter <= 0)
+ Status = VL_ERROR_INVALID_PARAMS;
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, 0);
+
+
+ /* Get the value of the TCC */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetSequenceStepEnable(Dev,
+ VL_SEQUENCESTEP_TCC, &SequenceStepEnabled);
+
+
+ /* Disable the TCC */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetSequenceStepEnable(Dev,
+ VL_SEQUENCESTEP_TCC, 0);
+
+
+ /* Disable the RIT */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_SetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
+
+ /* Perform 50 measurements and compute the averages */
+ if (Status == VL_ERROR_NONE) {
+ sum_ranging = 0;
+ total_count = 0;
+ for (meas = 0; meas < 50; meas++) {
+ Status = VL_PerformSingleRangingMeasurement(Dev,
+ &RangingMeasurementData);
+
+ if (Status != VL_ERROR_NONE)
+ break;
+
+ /* The range is valid when RangeStatus = 0 */
+ if (RangingMeasurementData.RangeStatus == 0) {
+ sum_ranging = sum_ranging +
+ RangingMeasurementData.RangeMilliMeter;
+ total_count = total_count + 1;
+ }
+ }
+
+ /* no valid values found */
+ if (total_count == 0)
+ Status = VL_ERROR_RANGE_ERROR;
+ }
+
+
+ if (Status == VL_ERROR_NONE) {
+ /* unsigned int / uint16_t = unsigned int */
+ StoredMeanRange = (unsigned int)((uint32_t)(sum_ranging << 16)
+ / total_count);
+
+ StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16;
+
+ /* Round Cal Distance to Whole Number. */
+ /* Note that the cal distance is in mm, */
+ /* therefore no resolution is lost.*/
+ CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16;
+
+ *pOffsetMicroMeter = (CalDistanceAsInt_mm -
+ StoredMeanRangeAsInt) * 1000;
+
+ /* Apply the calculated offset */
+ if (Status == VL_ERROR_NONE) {
+ VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+ *pOffsetMicroMeter);
+ Status = VL_SetOffsetCalibrationDataMicroMeter(Dev,
+ *pOffsetMicroMeter);
+ }
+
+ }
+
+ /* Restore the TCC */
+ if (Status == VL_ERROR_NONE) {
+ if (SequenceStepEnabled != 0)
+ Status = VL_SetSequenceStepEnable(Dev,
+ VL_SEQUENCESTEP_TCC, 1);
+ }
+
+ return Status;
+}
+
+
+int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev,
+ int32_t OffsetCalibrationDataMicroMeter)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t cMaxOffsetMicroMeter = 511000;
+ int32_t cMinOffsetMicroMeter = -512000;
+ int16_t cOffsetRange = 4096;
+ uint32_t encodedOffsetVal;
+
+ LOG_FUNCTION_START("");
+
+ if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter)
+ OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter;
+ else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter)
+ OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter;
+
+ /* The offset register is 10.2 format and units are mm
+ * therefore conversion is applied by a division of
+ * 250.
+ */
+ if (OffsetCalibrationDataMicroMeter >= 0) {
+ encodedOffsetVal =
+ OffsetCalibrationDataMicroMeter/250;
+ } else {
+ encodedOffsetVal =
+ cOffsetRange +
+ OffsetCalibrationDataMicroMeter/250;
+ }
+
+ Status = VL_WrWord(Dev,
+ VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
+ encodedOffsetVal);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint16_t RangeOffsetRegister;
+ int16_t cMaxOffset = 2047;
+ int16_t cOffsetRange = 4096;
+
+ /* Note that offset has 10.2 format */
+
+ Status = VL_RdWord(Dev,
+ VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
+ &RangeOffsetRegister);
+
+ if (Status == VL_ERROR_NONE) {
+ RangeOffsetRegister = (RangeOffsetRegister & 0x0fff);
+
+ /* Apply 12 bit 2's compliment conversion */
+ if (RangeOffsetRegister > cMaxOffset)
+ *pOffsetCalibrationDataMicroMeter =
+ (int16_t)(RangeOffsetRegister - cOffsetRange)
+ * 250;
+ else
+ *pOffsetCalibrationDataMicroMeter =
+ (int16_t)RangeOffsetRegister * 250;
+
+ }
+
+ return Status;
+}
+
+
+int8_t VL_apply_offset_adjustment(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t CorrectedOffsetMicroMeters;
+ int32_t CurrentOffsetMicroMeters;
+
+ /* if we run on this function we can read all the NVM info */
+ /* used by the API */
+ Status = VL_get_info_from_device(Dev, 7);
+
+ /* Read back current device offset */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetOffsetCalibrationDataMicroMeter(Dev,
+ &CurrentOffsetMicroMeters);
+ }
+
+ /* Apply Offset Adjustment derived from 400mm measurements */
+ if (Status == VL_ERROR_NONE) {
+
+ /* Store initial device offset */
+ PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter,
+ CurrentOffsetMicroMeters);
+
+ CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters +
+ (int32_t)PALDevDataGet(Dev,
+ Part2PartOffsetAdjustmentNVMMicroMeter);
+
+ Status = VL_SetOffsetCalibrationDataMicroMeter(Dev,
+ CorrectedOffsetMicroMeters);
+
+ /* store current, adjusted offset */
+ if (Status == VL_ERROR_NONE) {
+ VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
+ CorrectedOffsetMicroMeters);
+ }
+ }
+
+ return Status;
+}
+
+void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size,
+ uint32_t curr, int32_t *next)
+{
+ uint32_t startIndex;
+ uint32_t fineOffset;
+ uint32_t cSpadsPerByte = 8;
+ uint32_t coarseIndex;
+ uint32_t fineIndex;
+ uint8_t dataByte;
+ uint8_t success = 0;
+
+ /*
+ * Starting with the current good spad, loop through the array to find
+ * the next. i.e. the next bit set in the sequence.
+ *
+ * The coarse index is the byte index of the array and the fine index is
+ * the index of the bit within each byte.
+ */
+
+ *next = -1;
+
+ startIndex = curr / cSpadsPerByte;
+ fineOffset = curr % cSpadsPerByte;
+
+ for (coarseIndex = startIndex; ((coarseIndex < size) && !success);
+ coarseIndex++) {
+ fineIndex = 0;
+ dataByte = goodSpadArray[coarseIndex];
+
+ if (coarseIndex == startIndex) {
+ /* locate the bit position of the provided current */
+ /* spad bit before iterating */
+ dataByte >>= fineOffset;
+ fineIndex = fineOffset;
+ }
+
+ while (fineIndex < cSpadsPerByte) {
+ if ((dataByte & 0x1) == 1) {
+ success = 1;
+ *next = coarseIndex * cSpadsPerByte + fineIndex;
+ break;
+ }
+ dataByte >>= 1;
+ fineIndex++;
+ }
+ }
+}
+
+
+uint8_t is_aperture(uint32_t spadIndex)
+{
+ /*
+ * This function reports if a given spad index is an aperture SPAD by
+ * deriving the quadrant.
+ */
+ uint32_t quadrant;
+ uint8_t isAperture = 1;
+
+ quadrant = spadIndex >> 6;
+ if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0)
+ isAperture = 0;
+
+ return isAperture;
+}
+
+
+int8_t enable_spad_bit(uint8_t spadArray[], uint32_t size,
+ uint32_t spadIndex)
+{
+ int8_t status = VL_ERROR_NONE;
+ uint32_t cSpadsPerByte = 8;
+ uint32_t coarseIndex;
+ uint32_t fineIndex;
+
+ coarseIndex = spadIndex / cSpadsPerByte;
+ fineIndex = spadIndex % cSpadsPerByte;
+ if (coarseIndex >= size)
+ status = VL_ERROR_REF_SPAD_INIT;
+ else
+ spadArray[coarseIndex] |= (1 << fineIndex);
+
+ return status;
+}
+
+int8_t count_enabled_spads(uint8_t spadArray[],
+ uint32_t byteCount, uint32_t maxSpads,
+ uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture)
+{
+ int8_t status = VL_ERROR_NONE;
+ uint32_t cSpadsPerByte = 8;
+ uint32_t lastByte;
+ uint32_t lastBit;
+ uint32_t byteIndex = 0;
+ uint32_t bitIndex = 0;
+ uint8_t tempByte;
+ uint8_t spadTypeIdentified = 0;
+
+ /* The entire array will not be used for spads, therefore the last
+ * byte and last bit is determined from the max spads value.
+ */
+
+ lastByte = maxSpads / cSpadsPerByte;
+ lastBit = maxSpads % cSpadsPerByte;
+
+ /* Check that the max spads value does not exceed the array bounds. */
+ if (lastByte >= byteCount)
+ status = VL_ERROR_REF_SPAD_INIT;
+
+ *pTotalSpadsEnabled = 0;
+
+ /* Count the bits enabled in the whole bytes */
+ for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) {
+ tempByte = spadArray[byteIndex];
+
+ for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) {
+ if ((tempByte & 0x01) == 1) {
+ (*pTotalSpadsEnabled)++;
+ if (!spadTypeIdentified) {
+ *pIsAperture = 1;
+ if ((byteIndex < 2) && (bitIndex < 4))
+ *pIsAperture = 0;
+ spadTypeIdentified = 1;
+ }
+ }
+ tempByte >>= 1;
+ }
+ }
+
+ /* Count the number of bits enabled in the last byte accounting
+ * for the fact that not all bits in the byte may be used.
+ */
+ tempByte = spadArray[lastByte];
+
+ for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) {
+ if ((tempByte & 0x01) == 1)
+ (*pTotalSpadsEnabled)++;
+ }
+
+ return status;
+}
+
+int8_t set_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray)
+{
+ int8_t status = VL_WriteMulti(Dev,
+ VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
+ refSpadArray, 6);
+ return status;
+}
+
+int8_t get_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray)
+{
+ int8_t status = VL_ReadMulti(Dev,
+ VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
+ refSpadArray,
+ 6);
+ return status;
+}
+
+int8_t enable_ref_spads(struct vl_data *Dev,
+ uint8_t apertureSpads,
+ uint8_t goodSpadArray[],
+ uint8_t spadArray[],
+ uint32_t size,
+ uint32_t start,
+ uint32_t offset,
+ uint32_t spadCount,
+ uint32_t *lastSpad)
+{
+ int8_t status = VL_ERROR_NONE;
+ uint32_t index;
+ uint32_t i;
+ int32_t nextGoodSpad = offset;
+ uint32_t currentSpad;
+ uint8_t checkSpadArray[6];
+
+ /*
+ * This function takes in a spad array which may or may not have SPADS
+ * already enabled and appends from a given offset a requested number
+ * of new SPAD enables. The 'good spad map' is applied to
+ * determine the next SPADs to enable.
+ *
+ * This function applies to only aperture or only non-aperture spads.
+ * Checks are performed to ensure this.
+ */
+
+ currentSpad = offset;
+ for (index = 0; index < spadCount; index++) {
+ get_next_good_spad(goodSpadArray, size, currentSpad,
+ &nextGoodSpad);
+
+ if (nextGoodSpad == -1) {
+ status = VL_ERROR_REF_SPAD_INIT;
+ break;
+ }
+
+ /* Confirm that the next good SPAD is non-aperture */
+ if (is_aperture(start + nextGoodSpad) != apertureSpads) {
+ /* if we can't get the required number of good aperture
+ * spads from the current quadrant then this is an error
+ */
+ status = VL_ERROR_REF_SPAD_INIT;
+ break;
+ }
+ currentSpad = (uint32_t)nextGoodSpad;
+ enable_spad_bit(spadArray, size, currentSpad);
+ currentSpad++;
+ }
+ *lastSpad = currentSpad;
+
+ if (status == VL_ERROR_NONE)
+ status = set_ref_spad_map(Dev, spadArray);
+
+
+ if (status == VL_ERROR_NONE) {
+ status = get_ref_spad_map(Dev, checkSpadArray);
+
+ i = 0;
+
+ /* Compare spad maps. If not equal report error. */
+ while (i < size) {
+ if (spadArray[i] != checkSpadArray[i]) {
+ status = VL_ERROR_REF_SPAD_INIT;
+ break;
+ }
+ i++;
+ }
+ }
+ return status;
+}
+
+
+int8_t perform_ref_signal_measurement(struct vl_data *Dev,
+ uint16_t *refSignalRate)
+{
+ int8_t status = VL_ERROR_NONE;
+ struct VL_RangingMeasurementData_t rangingMeasurementData;
+
+ uint8_t SequenceConfig = 0;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /*
+ * This function performs a reference signal rate measurement.
+ */
+ if (status == VL_ERROR_NONE)
+ status = VL_WrByte(Dev,
+ VL_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0);
+
+ if (status == VL_ERROR_NONE)
+ status = VL_PerformSingleRangingMeasurement(Dev,
+ &rangingMeasurementData);
+
+ if (status == VL_ERROR_NONE)
+ status = VL_WrByte(Dev, 0xFF, 0x01);
+
+ if (status == VL_ERROR_NONE)
+ status = VL_RdWord(Dev,
+ VL_REG_RESULT_PEAK_SIGNAL_RATE_REF,
+ refSignalRate);
+
+ if (status == VL_ERROR_NONE)
+ status = VL_WrByte(Dev, 0xFF, 0x00);
+
+ if (status == VL_ERROR_NONE) {
+ /* restore the previous Sequence Config */
+ status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+ }
+
+ return status;
+}
+
+int8_t VL_perform_ref_spad_management(struct vl_data *Dev,
+ uint32_t *refSpadCount,
+ uint8_t *isApertureSpads)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t lastSpadArray[6];
+ uint8_t startSelect = 0xB4;
+ uint32_t minimumSpadCount = 3;
+ uint32_t maxSpadCount = 44;
+ uint32_t currentSpadIndex = 0;
+ uint32_t lastSpadIndex = 0;
+ int32_t nextGoodSpad = 0;
+ uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */
+ uint16_t peakSignalRateRef;
+ uint32_t needAptSpads = 0;
+ uint32_t index = 0;
+ uint32_t spadArraySize = 6;
+ uint32_t signalRateDiff = 0;
+ uint32_t lastSignalRateDiff = 0;
+ uint8_t complete = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint32_t refSpadCount_int = 0;
+ uint8_t isApertureSpads_int = 0;
+
+ /*
+ * The reference SPAD initialization procedure determines the minimum
+ * amount of reference spads to be enables to achieve a target reference
+ * signal rate and should be performed once during initialization.
+ *
+ * Either aperture or non-aperture spads are applied but never both.
+ * Firstly non-aperture spads are set, beginning with 5 spads, and
+ * increased one spad at a time until the closest measurement to the
+ * target rate is achieved.
+ *
+ * If the target rate is exceeded when 5 non-aperture spads are enabled,
+ * initialization is performed instead with aperture spads.
+ *
+ * When setting spads, a 'Good Spad Map' is applied.
+ *
+ * This procedure operates within a SPAD window of interest of a maximum
+ * 44 spads.
+ * The start point is currently fixed to 180, which lies towards the end
+ * of the non-aperture quadrant and runs in to the adjacent aperture
+ * quadrant.
+ */
+
+
+ targetRefRate = PALDevDataGet(Dev, targetRefRate);
+
+ /*
+ * Initialize Spad arrays.
+ * Currently the good spad map is initialised to 'All good'.
+ * This is a short term implementation. The good spad map will be
+ * provided as an input.
+ * Note that there are 6 bytes. Only the first 44 bits will be used to
+ * represent spads.
+ */
+ for (index = 0; index < spadArraySize; index++)
+ Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
+ startSelect);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
+
+ /* Perform ref calibration */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_perform_ref_calibration(Dev, &VhvSettings,
+ &PhaseCal, 0);
+
+ if (Status == VL_ERROR_NONE) {
+ /* Enable Minimum NON-APERTURE Spads */
+ currentSpadIndex = 0;
+ lastSpadIndex = currentSpadIndex;
+ needAptSpads = 0;
+ Status = enable_ref_spads(Dev,
+ needAptSpads,
+ Dev->Data.SpadData.RefGoodSpadMap,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize,
+ startSelect,
+ currentSpadIndex,
+ minimumSpadCount,
+ &lastSpadIndex);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ currentSpadIndex = lastSpadIndex;
+
+ Status = perform_ref_signal_measurement(Dev,
+ &peakSignalRateRef);
+ if ((Status == VL_ERROR_NONE) &&
+ (peakSignalRateRef > targetRefRate)) {
+ /* Signal rate measurement too high, */
+ /* switch to APERTURE SPADs */
+
+ for (index = 0; index < spadArraySize; index++)
+ Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+
+ /* Increment to the first APERTURE spad */
+ while ((is_aperture(startSelect + currentSpadIndex)
+ == 0) && (currentSpadIndex < maxSpadCount)) {
+ currentSpadIndex++;
+ }
+
+ needAptSpads = 1;
+
+ Status = enable_ref_spads(Dev,
+ needAptSpads,
+ Dev->Data.SpadData.RefGoodSpadMap,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize,
+ startSelect,
+ currentSpadIndex,
+ minimumSpadCount,
+ &lastSpadIndex);
+
+ if (Status == VL_ERROR_NONE) {
+ currentSpadIndex = lastSpadIndex;
+ Status = perform_ref_signal_measurement(Dev,
+ &peakSignalRateRef);
+
+ if ((Status == VL_ERROR_NONE) &&
+ (peakSignalRateRef > targetRefRate)) {
+ /* Signal rate still too high after
+ * setting the minimum number of
+ * APERTURE spads. Can do no more
+ * therefore set the min number of
+ * aperture spads as the result.
+ */
+ isApertureSpads_int = 1;
+ refSpadCount_int = minimumSpadCount;
+ }
+ }
+ } else {
+ needAptSpads = 0;
+ }
+ }
+
+ if ((Status == VL_ERROR_NONE) &&
+ (peakSignalRateRef < targetRefRate)) {
+ /* At this point, the minimum number of either aperture
+ * or non-aperture spads have been set. Proceed to add
+ * spads and perform measurements until the target
+ * reference is reached.
+ */
+ isApertureSpads_int = needAptSpads;
+ refSpadCount_int = minimumSpadCount;
+
+ memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize);
+ lastSignalRateDiff = abs(peakSignalRateRef -
+ targetRefRate);
+ complete = 0;
+
+ while (!complete) {
+ get_next_good_spad(
+ Dev->Data.SpadData.RefGoodSpadMap,
+ spadArraySize, currentSpadIndex,
+ &nextGoodSpad);
+
+ if (nextGoodSpad == -1) {
+ Status = VL_ERROR_REF_SPAD_INIT;
+ break;
+ }
+
+ /* Cannot combine Aperture and Non-Aperture spads, so
+ * ensure the current spad is of the correct type.
+ */
+ if (is_aperture((uint32_t)startSelect + nextGoodSpad) !=
+ needAptSpads) {
+ /* At this point we have enabled the maximum
+ * number of Aperture spads.
+ */
+ complete = 1;
+ break;
+ }
+
+ (refSpadCount_int)++;
+
+ currentSpadIndex = nextGoodSpad;
+ Status = enable_spad_bit(
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize, currentSpadIndex);
+
+ if (Status == VL_ERROR_NONE) {
+ currentSpadIndex++;
+ /* Proceed to apply the additional spad and */
+ /* perform measurement. */
+ Status = set_ref_spad_map(Dev,
+ Dev->Data.SpadData.RefSpadEnables);
+ }
+
+ if (Status != VL_ERROR_NONE)
+ break;
+
+ Status = perform_ref_signal_measurement(Dev,
+ &peakSignalRateRef);
+
+ if (Status != VL_ERROR_NONE)
+ break;
+
+ signalRateDiff = abs(peakSignalRateRef - targetRefRate);
+
+ if (peakSignalRateRef > targetRefRate) {
+ /* Select the spad map that provides the */
+ /* measurement closest to the target rate, */
+ /* either above or below it. */
+
+ if (signalRateDiff > lastSignalRateDiff) {
+ /* Previous spad map produced a closer */
+ /* measurement, so choose this. */
+ Status = set_ref_spad_map(Dev,
+ lastSpadArray);
+ memcpy(
+ Dev->Data.SpadData.RefSpadEnables,
+ lastSpadArray, spadArraySize);
+
+ (refSpadCount_int)--;
+ }
+ complete = 1;
+ } else {
+ /* Continue to add spads */
+ lastSignalRateDiff = signalRateDiff;
+ memcpy(lastSpadArray,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize);
+ }
+
+ } /* while */
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ *refSpadCount = refSpadCount_int;
+ *isApertureSpads = isApertureSpads_int;
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount, (uint8_t)(*refSpadCount));
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, *isApertureSpads);
+ }
+
+ return Status;
+}
+
+int8_t VL_set_reference_spads(struct vl_data *Dev,
+ uint32_t count, uint8_t isApertureSpads)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint32_t currentSpadIndex = 0;
+ uint8_t startSelect = 0xB4;
+ uint32_t spadArraySize = 6;
+ uint32_t maxSpadCount = 44;
+ uint32_t lastSpadIndex;
+ uint32_t index;
+
+ /*
+ * This function applies a requested number of reference spads, either
+ * aperture or
+ * non-aperture, as requested.
+ * The good spad map will be applied.
+ */
+
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
+ startSelect);
+
+ for (index = 0; index < spadArraySize; index++)
+ Dev->Data.SpadData.RefSpadEnables[index] = 0;
+
+ if (isApertureSpads) {
+ /* Increment to the first APERTURE spad */
+ while ((is_aperture(startSelect + currentSpadIndex) == 0) &&
+ (currentSpadIndex < maxSpadCount)) {
+ currentSpadIndex++;
+ }
+ }
+ Status = enable_ref_spads(Dev,
+ isApertureSpads,
+ Dev->Data.SpadData.RefGoodSpadMap,
+ Dev->Data.SpadData.RefSpadEnables,
+ spadArraySize,
+ startSelect,
+ currentSpadIndex,
+ count,
+ &lastSpadIndex);
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount, (uint8_t)(count));
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, isApertureSpads);
+ }
+
+ return Status;
+}
+
+int8_t VL_get_reference_spads(struct vl_data *Dev,
+ uint32_t *pSpadCount, uint8_t *pIsApertureSpads)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t refSpadsInitialised;
+ uint8_t refSpadArray[6];
+ uint32_t cMaxSpadCount = 44;
+ uint32_t cSpadArraySize = 6;
+ uint32_t spadsEnabled;
+ uint8_t isApertureSpads = 0;
+
+ refSpadsInitialised = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ RefSpadsInitialised);
+
+ if (refSpadsInitialised == 1) {
+
+ *pSpadCount = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount);
+ *pIsApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType);
+ } else {
+
+ /* obtain spad info from device.*/
+ Status = get_ref_spad_map(Dev, refSpadArray);
+
+ if (Status == VL_ERROR_NONE) {
+ /* count enabled spads within spad map array and
+ * determine if Aperture or Non-Aperture.
+ */
+ Status = count_enabled_spads(refSpadArray,
+ cSpadArraySize,
+ cMaxSpadCount,
+ &spadsEnabled,
+ &isApertureSpads);
+
+ if (Status == VL_ERROR_NONE) {
+
+ *pSpadCount = spadsEnabled;
+ *pIsApertureSpads = isApertureSpads;
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ RefSpadsInitialised, 1);
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount,
+ (uint8_t)spadsEnabled);
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, isApertureSpads);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+int8_t VL_perform_single_ref_calibration(struct vl_data *Dev,
+ uint8_t vhv_init_byte)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START,
+ VL_REG_SYSRANGE_MODE_START_STOP |
+ vhv_init_byte);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_measurement_poll_for_completion(Dev);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_ClearInterruptMask(Dev, 0);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x00);
+
+ return Status;
+}
+
+
+int8_t VL_ref_calibration_io(struct vl_data *Dev,
+ uint8_t read_not_write, uint8_t VhvSettings, uint8_t PhaseCal,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal,
+ const uint8_t vhv_enable, const uint8_t phase_enable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t PhaseCalint = 0;
+
+ /* Read VHV from device */
+ Status |= VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x00);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+ if (read_not_write) {
+ if (vhv_enable)
+ Status |= VL_RdByte(Dev, 0xCB, pVhvSettings);
+ if (phase_enable)
+ Status |= VL_RdByte(Dev, 0xEE, &PhaseCalint);
+ } else {
+ if (vhv_enable)
+ Status |= VL_WrByte(Dev, 0xCB, VhvSettings);
+ if (phase_enable)
+ Status |= VL_UpdateByte(Dev, 0xEE, 0x80, PhaseCal);
+ }
+
+ Status |= VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x01);
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+
+ *pPhaseCal = (uint8_t)(PhaseCalint&0xEF);
+
+ return Status;
+}
+
+
+int8_t VL_perform_vhv_calibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, const uint8_t get_data_enable,
+ const uint8_t restore_config)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint8_t PhaseCalInt = 0;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ if (restore_config)
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /* Run VHV */
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x01);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_perform_single_ref_calibration(Dev, 0x40);
+
+ /* Read VHV from device */
+ if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) {
+ Status = VL_ref_calibration_io(Dev, 1,
+ VhvSettings, PhaseCal, /* Not used here */
+ pVhvSettings, &PhaseCalInt,
+ 1, 0);
+ } else
+ *pVhvSettings = 0;
+
+
+ if ((Status == VL_ERROR_NONE) && restore_config) {
+ /* restore the previous Sequence Config */
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ }
+
+ return Status;
+}
+
+int8_t VL_perform_phase_calibration(struct vl_data *Dev,
+ uint8_t *pPhaseCal, const uint8_t get_data_enable,
+ const uint8_t restore_config)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+ uint8_t VhvSettingsint;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ if (restore_config)
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /* Run PhaseCal */
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x02);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_perform_single_ref_calibration(Dev, 0x0);
+
+ /* Read PhaseCal from device */
+ if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) {
+ Status = VL_ref_calibration_io(Dev, 1,
+ VhvSettings, PhaseCal, /* Not used here */
+ &VhvSettingsint, pPhaseCal,
+ 0, 1);
+ } else
+ *pPhaseCal = 0;
+
+
+ if ((Status == VL_ERROR_NONE) && restore_config) {
+ /* restore the previous Sequence Config */
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ }
+
+ return Status;
+}
+
+int8_t VL_perform_ref_calibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t SequenceConfig = 0;
+
+ /* store the value of the sequence config,
+ * this will be reset before the end of the function
+ */
+
+ SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
+
+ /* In the following function we don't save the config to optimize */
+ /* writes on device. Config is saved and restored only once. */
+ Status = VL_perform_vhv_calibration(
+ Dev, pVhvSettings, get_data_enable, 0);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_perform_phase_calibration(
+ Dev, pPhaseCal, get_data_enable, 0);
+
+
+ if (Status == VL_ERROR_NONE) {
+ /* restore the previous Sequence Config */
+ Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG,
+ SequenceConfig);
+ if (Status == VL_ERROR_NONE)
+ PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
+
+ }
+
+ return Status;
+}
+
+int8_t VL_set_ref_calibration(struct vl_data *Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t pVhvSettings;
+ uint8_t pPhaseCal;
+
+ Status = VL_ref_calibration_io(Dev, 0,
+ VhvSettings, PhaseCal,
+ &pVhvSettings, &pPhaseCal,
+ 1, 1);
+
+ return Status;
+}
+
+int8_t VL_get_ref_calibration(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t VhvSettings = 0;
+ uint8_t PhaseCal = 0;
+
+ Status = VL_ref_calibration_io(Dev, 1,
+ VhvSettings, PhaseCal,
+ pVhvSettings, pPhaseCal,
+ 1, 1);
+
+ return Status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c
new file mode 100644
index 0000000..ceb3585
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c
@@ -0,0 +1,2220 @@
+/*
+ * vl53l0x_api_core.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_calibration.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+int8_t VL_reverse_bytes(uint8_t *data, uint32_t size)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t tempData;
+ uint32_t mirrorIndex;
+ uint32_t middle = size/2;
+ uint32_t index;
+
+ for (index = 0; index < middle; index++) {
+ mirrorIndex = size - index - 1;
+ tempData = data[index];
+ data[index] = data[mirrorIndex];
+ data[mirrorIndex] = tempData;
+ }
+ return Status;
+}
+
+int8_t VL_measurement_poll_for_completion(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t NewDataReady = 0;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ LoopNb = 0;
+
+ do {
+ Status = VL_GetMeasurementDataReady(Dev, &NewDataReady);
+ if (Status != 0)
+ break; /* the error is set */
+
+ if (NewDataReady == 1)
+ break; /* done note that status == 0 */
+
+ LoopNb++;
+ if (LoopNb >= VL_DEFAULT_MAX_LOOP) {
+ Status = VL_ERROR_TIME_OUT;
+ break;
+ }
+
+ VL_PollingDelay(Dev);
+ } while (1);
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg)
+{
+ /*!
+ * Converts the encoded VCSEL period register value into the real
+ * period in PLL clocks
+ */
+
+ uint8_t vcsel_period_pclks = 0;
+
+ vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
+
+ return vcsel_period_pclks;
+}
+
+uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks)
+{
+ /*!
+ * Converts the encoded VCSEL period register value into the real period
+ * in PLL clocks
+ */
+
+ uint8_t vcsel_period_reg = 0;
+
+ vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
+
+ return vcsel_period_reg;
+}
+
+
+uint32_t VL_isqrt(uint32_t num)
+{
+ /*
+ * Implements an integer square root
+ *
+ * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
+ */
+
+ uint32_t res = 0;
+ uint32_t bit = 1 << 30;
+ /* The second-to-top bit is set: */
+ /* 1 << 14 for 16-bits, 1 << 30 for 32 bits */
+
+ /* "bit" starts at the highest power of four <= the argument. */
+ while (bit > num)
+ bit >>= 2;
+
+
+ while (bit != 0) {
+ if (num >= res + bit) {
+ num -= res + bit;
+ res = (res >> 1) + bit;
+ } else
+ res >>= 1;
+
+ bit >>= 2;
+ }
+
+ return res;
+}
+
+
+uint32_t VL_quadrature_sum(uint32_t a, uint32_t b)
+{
+ /*
+ * Implements a quadrature sum
+ *
+ * rea = sqrt(a^2 + b^2)
+ *
+ * Trap overflow case max input value is 65535 (16-bit value)
+ * as internal calc are 32-bit wide
+ *
+ * If overflow then seta output to maximum
+ */
+ uint32_t res = 0;
+
+ if (a > 65535 || b > 65535)
+ res = 65535;
+ else
+ res = VL_isqrt(a * a + b * b);
+
+ return res;
+}
+
+
+int8_t VL_device_read_strobe(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t strobe;
+ uint32_t LoopNb;
+
+ LOG_FUNCTION_START("");
+
+ Status |= VL_WrByte(Dev, 0x83, 0x00);
+
+ /* polling use timeout to avoid deadlock*/
+ if (Status == VL_ERROR_NONE) {
+ LoopNb = 0;
+ do {
+ Status = VL_RdByte(Dev, 0x83, &strobe);
+ if ((strobe != 0x00) || Status != VL_ERROR_NONE)
+ break;
+ LoopNb = LoopNb + 1;
+ } while (LoopNb < VL_DEFAULT_MAX_LOOP);
+
+ if (LoopNb >= VL_DEFAULT_MAX_LOOP)
+ Status = VL_ERROR_TIME_OUT;
+
+ }
+
+ Status |= VL_WrByte(Dev, 0x83, 0x01);
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
+
+int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option)
+{
+
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t byte;
+ uint32_t TmpDWord;
+ uint8_t ModuleId;
+ uint8_t Revision;
+ uint8_t ReferenceSpadCount = 0;
+ uint8_t ReferenceSpadType = 0;
+ uint32_t PartUIDUpper = 0;
+ uint32_t PartUIDLower = 0;
+ uint32_t OffsetFixed1104_mm = 0;
+ int16_t OffsetMicroMeters = 0;
+ uint32_t DistMeasTgtFixed1104_mm = 400 << 4;
+ uint32_t DistMeasFixed1104_400_mm = 0;
+ uint32_t SignalRateMeasFixed1104_400_mm = 0;
+ char ProductId[19];
+ char *ProductId_tmp;
+ uint8_t ReadDataFromDeviceDone;
+ unsigned int SignalRateMeasFixed400mmFix = 0;
+ uint8_t NvmRefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE];
+ int i;
+
+
+ LOG_FUNCTION_START("");
+
+ ReadDataFromDeviceDone = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ReadDataFromDeviceDone);
+
+ /* This access is done only once after that a GetDeviceInfo or */
+ /* datainit is done*/
+ if (ReadDataFromDeviceDone != 7) {
+
+ Status |= VL_WrByte(Dev, 0x80, 0x01);
+ Status |= VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x00);
+
+ Status |= VL_WrByte(Dev, 0xFF, 0x06);
+ Status |= VL_RdByte(Dev, 0x83, &byte);
+ Status |= VL_WrByte(Dev, 0x83, byte|4);
+ Status |= VL_WrByte(Dev, 0xFF, 0x07);
+ Status |= VL_WrByte(Dev, 0x81, 0x01);
+
+ Status |= VL_PollingDelay(Dev);
+
+ Status |= VL_WrByte(Dev, 0x80, 0x01);
+
+ if (((option & 1) == 1) &&
+ ((ReadDataFromDeviceDone & 1) == 0)) {
+ Status |= VL_WrByte(Dev, 0x94, 0x6b);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f);
+ ReferenceSpadType = (uint8_t)((TmpDWord >> 15) & 0x01);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x24);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+
+ NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24)
+ & 0xff);
+ NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16)
+ & 0xff);
+ NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8)
+ & 0xff);
+ NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x25);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24)
+ & 0xff);
+ NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16)
+ & 0xff);
+ }
+
+ if (((option & 2) == 2) &&
+ ((ReadDataFromDeviceDone & 2) == 0)) {
+
+ Status |= VL_WrByte(Dev, 0x94, 0x02);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdByte(Dev, 0x90, &ModuleId);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x7B);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdByte(Dev, 0x90, &Revision);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x77);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[0] = (char)((TmpDWord >> 25) & 0x07f);
+ ProductId[1] = (char)((TmpDWord >> 18) & 0x07f);
+ ProductId[2] = (char)((TmpDWord >> 11) & 0x07f);
+ ProductId[3] = (char)((TmpDWord >> 4) & 0x07f);
+
+ byte = (uint8_t)((TmpDWord & 0x00f) << 3);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x78);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[4] = (char)(byte +
+ ((TmpDWord >> 29) & 0x07f));
+ ProductId[5] = (char)((TmpDWord >> 22) & 0x07f);
+ ProductId[6] = (char)((TmpDWord >> 15) & 0x07f);
+ ProductId[7] = (char)((TmpDWord >> 8) & 0x07f);
+ ProductId[8] = (char)((TmpDWord >> 1) & 0x07f);
+
+ byte = (uint8_t)((TmpDWord & 0x001) << 6);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x79);
+
+ Status |= VL_device_read_strobe(Dev);
+
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[9] = (char)(byte +
+ ((TmpDWord >> 26) & 0x07f));
+ ProductId[10] = (char)((TmpDWord >> 19) & 0x07f);
+ ProductId[11] = (char)((TmpDWord >> 12) & 0x07f);
+ ProductId[12] = (char)((TmpDWord >> 5) & 0x07f);
+
+ byte = (uint8_t)((TmpDWord & 0x01f) << 2);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x7A);
+
+ Status |= VL_device_read_strobe(Dev);
+
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ ProductId[13] = (char)(byte +
+ ((TmpDWord >> 30) & 0x07f));
+ ProductId[14] = (char)((TmpDWord >> 23) & 0x07f);
+ ProductId[15] = (char)((TmpDWord >> 16) & 0x07f);
+ ProductId[16] = (char)((TmpDWord >> 9) & 0x07f);
+ ProductId[17] = (char)((TmpDWord >> 2) & 0x07f);
+ ProductId[18] = '\0';
+
+ }
+
+ if (((option & 4) == 4) &&
+ ((ReadDataFromDeviceDone & 4) == 0)) {
+
+ Status |= VL_WrByte(Dev, 0x94, 0x7B);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &PartUIDUpper);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x7C);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &PartUIDLower);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x73);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ SignalRateMeasFixed1104_400_mm = (TmpDWord &
+ 0x0000000ff) << 8;
+
+ Status |= VL_WrByte(Dev, 0x94, 0x74);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ SignalRateMeasFixed1104_400_mm |= ((TmpDWord &
+ 0xff000000) >> 24);
+
+ Status |= VL_WrByte(Dev, 0x94, 0x75);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff)
+ << 8;
+
+ Status |= VL_WrByte(Dev, 0x94, 0x76);
+ Status |= VL_device_read_strobe(Dev);
+ Status |= VL_RdDWord(Dev, 0x90, &TmpDWord);
+
+ DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000)
+ >> 24);
+ }
+
+ Status |= VL_WrByte(Dev, 0x81, 0x00);
+ Status |= VL_WrByte(Dev, 0xFF, 0x06);
+ Status |= VL_RdByte(Dev, 0x83, &byte);
+ Status |= VL_WrByte(Dev, 0x83, byte&0xfb);
+ Status |= VL_WrByte(Dev, 0xFF, 0x01);
+ Status |= VL_WrByte(Dev, 0x00, 0x01);
+
+ Status |= VL_WrByte(Dev, 0xFF, 0x00);
+ Status |= VL_WrByte(Dev, 0x80, 0x00);
+ }
+
+ if ((Status == VL_ERROR_NONE) &&
+ (ReadDataFromDeviceDone != 7)) {
+ /* Assign to variable if status is ok */
+ if (((option & 1) == 1) &&
+ ((ReadDataFromDeviceDone & 1) == 0)) {
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadCount, ReferenceSpadCount);
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ReferenceSpadType, ReferenceSpadType);
+
+ for (i = 0; i < VL_REF_SPAD_BUFFER_SIZE; i++) {
+ Dev->Data.SpadData.RefGoodSpadMap[i] =
+ NvmRefGoodSpadMap[i];
+ }
+ }
+
+ if (((option & 2) == 2) &&
+ ((ReadDataFromDeviceDone & 2) == 0)) {
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ ModuleId, ModuleId);
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ Revision, Revision);
+
+ ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ProductId);
+ VL_COPYSTRING(ProductId_tmp, ProductId);
+
+ }
+
+ if (((option & 4) == 4) &&
+ ((ReadDataFromDeviceDone & 4) == 0)) {
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ PartUIDUpper, PartUIDUpper);
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ PartUIDLower, PartUIDLower);
+
+ SignalRateMeasFixed400mmFix =
+ VL_FIXPOINT97TOFIXPOINT1616(
+ SignalRateMeasFixed1104_400_mm);
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ SignalRateMeasFixed400mm,
+ SignalRateMeasFixed400mmFix);
+
+ OffsetMicroMeters = 0;
+ if (DistMeasFixed1104_400_mm != 0) {
+ OffsetFixed1104_mm = DistMeasFixed1104_400_mm -
+ DistMeasTgtFixed1104_mm;
+ OffsetMicroMeters = (OffsetFixed1104_mm
+ * 1000) >> 4;
+ OffsetMicroMeters *= -1;
+ }
+
+ PALDevDataSet(Dev,
+ Part2PartOffsetAdjustmentNVMMicroMeter,
+ OffsetMicroMeters);
+ }
+ byte = (uint8_t)(ReadDataFromDeviceDone|option);
+ VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone,
+ byte);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+uint32_t VL_calc_macro_period_ps(struct vl_data *Dev,
+ uint8_t vcsel_period_pclks)
+{
+ uint64_t PLL_period_ps;
+ uint32_t macro_period_vclks;
+ uint32_t macro_period_ps;
+
+ LOG_FUNCTION_START("");
+
+ /* The above calculation will produce rounding errors, */
+ /* therefore set fixed value */
+ PLL_period_ps = 1655;
+
+ macro_period_vclks = 2304;
+ macro_period_ps = (uint32_t)(macro_period_vclks
+ * vcsel_period_pclks * PLL_period_ps);
+
+ LOG_FUNCTION_END("");
+ return macro_period_ps;
+}
+
+uint16_t VL_encode_timeout(uint32_t timeout_macro_clks)
+{
+ /*!
+ * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
+ */
+
+ uint16_t encoded_timeout = 0;
+ uint32_t ls_byte = 0;
+ uint16_t ms_byte = 0;
+
+ if (timeout_macro_clks > 0) {
+ ls_byte = timeout_macro_clks - 1;
+
+ while ((ls_byte & 0xFFFFFF00) > 0) {
+ ls_byte = ls_byte >> 1;
+ ms_byte++;
+ }
+
+ encoded_timeout = (ms_byte << 8)
+ + (uint16_t) (ls_byte & 0x000000FF);
+ }
+
+ return encoded_timeout;
+
+}
+
+uint32_t VL_decode_timeout(uint16_t encoded_timeout)
+{
+ /*!
+ * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
+ */
+
+ uint32_t timeout_macro_clks = 0;
+
+ timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF)
+ << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1;
+
+ return timeout_macro_clks;
+}
+
+
+/* To convert ms into register value */
+uint32_t VL_calc_timeout_mclks(struct vl_data *Dev,
+ uint32_t timeout_period_us,
+ uint8_t vcsel_period_pclks)
+{
+ uint32_t macro_period_ps;
+ uint32_t macro_period_ns;
+ uint32_t timeout_period_mclks = 0;
+
+ macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks);
+ macro_period_ns = (macro_period_ps + 500) / 1000;
+
+ timeout_period_mclks =
+ (uint32_t) (((timeout_period_us * 1000)
+ + (macro_period_ns / 2)) / macro_period_ns);
+
+ return timeout_period_mclks;
+}
+
+/* To convert register value into us */
+uint32_t VL_calc_timeout_us(struct vl_data *Dev,
+ uint16_t timeout_period_mclks,
+ uint8_t vcsel_period_pclks)
+{
+ uint32_t macro_period_ps;
+ uint32_t macro_period_ns;
+ uint32_t actual_timeout_period_us = 0;
+
+ macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks);
+ macro_period_ns = (macro_period_ps + 500) / 1000;
+
+ actual_timeout_period_us =
+ ((timeout_period_mclks * macro_period_ns) + 500) / 1000;
+
+ return actual_timeout_period_us;
+}
+
+
+int8_t get_sequence_step_timeout(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ uint32_t *pTimeOutMicroSecs)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t CurrentVCSELPulsePeriodPClk;
+ uint8_t EncodedTimeOutByte = 0;
+ uint32_t TimeoutMicroSeconds = 0;
+ uint16_t PreRangeEncodedTimeOut = 0;
+ uint16_t MsrcTimeOutMClks;
+ uint16_t PreRangeTimeOutMClks;
+ uint16_t FinalRangeTimeOutMClks = 0;
+ uint16_t FinalRangeEncodedTimeOut;
+ struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+
+ if ((SequenceStepId == VL_SEQUENCESTEP_TCC) ||
+ (SequenceStepId == VL_SEQUENCESTEP_DSS) ||
+ (SequenceStepId == VL_SEQUENCESTEP_MSRC)) {
+
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdByte(Dev,
+ VL_REG_MSRC_CONFIG_TIMEOUT_MACROP,
+ &EncodedTimeOutByte);
+ }
+ MsrcTimeOutMClks = VL_decode_timeout(EncodedTimeOutByte);
+
+ TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
+ MsrcTimeOutMClks,
+ CurrentVCSELPulsePeriodPClk);
+ } else if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) {
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ /* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */
+ if (Status == VL_ERROR_NONE) {
+
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdWord(Dev,
+ VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ &PreRangeEncodedTimeOut);
+ }
+
+ PreRangeTimeOutMClks = VL_decode_timeout(
+ PreRangeEncodedTimeOut);
+
+ TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
+ PreRangeTimeOutMClks,
+ CurrentVCSELPulsePeriodPClk);
+ }
+ } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) {
+
+ VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+ PreRangeTimeOutMClks = 0;
+
+ if (SchedulerSequenceSteps.PreRangeOn) {
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ /* Retrieve PRE-RANGE Timeout in Macro periods */
+ /* (MCLKS) */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdWord(Dev,
+ VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ &PreRangeEncodedTimeOut);
+ PreRangeTimeOutMClks = VL_decode_timeout(
+ PreRangeEncodedTimeOut);
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ /* Retrieve FINAL-RANGE VCSEL Period */
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_FINAL_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ }
+
+ /* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdWord(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ &FinalRangeEncodedTimeOut);
+ FinalRangeTimeOutMClks = VL_decode_timeout(
+ FinalRangeEncodedTimeOut);
+ }
+
+ FinalRangeTimeOutMClks -= PreRangeTimeOutMClks;
+ TimeoutMicroSeconds = VL_calc_timeout_us(Dev,
+ FinalRangeTimeOutMClks,
+ CurrentVCSELPulsePeriodPClk);
+ }
+
+ *pTimeOutMicroSecs = TimeoutMicroSeconds;
+
+ return Status;
+}
+
+
+int8_t set_sequence_step_timeout(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ uint32_t TimeOutMicroSecs)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t CurrentVCSELPulsePeriodPClk;
+ uint8_t MsrcEncodedTimeOut;
+ uint16_t PreRangeEncodedTimeOut;
+ uint16_t PreRangeTimeOutMClks;
+ uint16_t MsrcRangeTimeOutMClks;
+ uint32_t FinalRangeTimeOutMClks;
+ uint16_t FinalRangeEncodedTimeOut;
+ struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+
+ if ((SequenceStepId == VL_SEQUENCESTEP_TCC) ||
+ (SequenceStepId == VL_SEQUENCESTEP_DSS) ||
+ (SequenceStepId == VL_SEQUENCESTEP_MSRC)) {
+
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ if (Status == VL_ERROR_NONE) {
+ MsrcRangeTimeOutMClks = VL_calc_timeout_mclks(Dev,
+ TimeOutMicroSecs,
+ (uint8_t)CurrentVCSELPulsePeriodPClk);
+
+ if (MsrcRangeTimeOutMClks > 256)
+ MsrcEncodedTimeOut = 255;
+ else
+ MsrcEncodedTimeOut =
+ (uint8_t)MsrcRangeTimeOutMClks - 1;
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ LastEncodedTimeout,
+ MsrcEncodedTimeOut);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_WrByte(Dev,
+ VL_REG_MSRC_CONFIG_TIMEOUT_MACROP,
+ MsrcEncodedTimeOut);
+ }
+ } else {
+
+ if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) {
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ PreRangeTimeOutMClks =
+ VL_calc_timeout_mclks(Dev,
+ TimeOutMicroSecs,
+ (uint8_t)CurrentVCSELPulsePeriodPClk);
+ PreRangeEncodedTimeOut = VL_encode_timeout(
+ PreRangeTimeOutMClks);
+
+ VL_SETDEVICESPECIFICPARAMETER(Dev,
+ LastEncodedTimeout,
+ PreRangeEncodedTimeOut);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_WrWord(Dev,
+ VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
+ PreRangeEncodedTimeOut);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeTimeoutMicroSecs,
+ TimeOutMicroSecs);
+ }
+ } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) {
+
+ /* For the final range timeout, the pre-range timeout
+ * must be added. To do this both final and pre-range
+ * timeouts must be expressed in macro periods MClks
+ * because they have different vcsel periods.
+ */
+
+ VL_GetSequenceStepEnables(Dev,
+ &SchedulerSequenceSteps);
+ PreRangeTimeOutMClks = 0;
+ if (SchedulerSequenceSteps.PreRangeOn) {
+
+ /* Retrieve PRE-RANGE VCSEL Period */
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_PRE_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+
+ /* Retrieve PRE-RANGE Timeout in Macro */
+ /* periods (MCLKS) */
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdWord(Dev, 0x51,
+ &PreRangeEncodedTimeOut);
+ PreRangeTimeOutMClks =
+ VL_decode_timeout(
+ PreRangeEncodedTimeOut);
+ }
+ }
+
+ /* Calculate FINAL RANGE Timeout in Macro Periods */
+ /* (MCLKS) and add PRE-RANGE value */
+ if (Status == VL_ERROR_NONE) {
+
+ Status = VL_GetVcselPulsePeriod(Dev,
+ VL_VCSEL_PERIOD_FINAL_RANGE,
+ &CurrentVCSELPulsePeriodPClk);
+ }
+ if (Status == VL_ERROR_NONE) {
+
+ FinalRangeTimeOutMClks =
+ VL_calc_timeout_mclks(Dev,
+ TimeOutMicroSecs,
+ (uint8_t) CurrentVCSELPulsePeriodPClk);
+
+ FinalRangeTimeOutMClks += PreRangeTimeOutMClks;
+
+ FinalRangeEncodedTimeOut =
+ VL_encode_timeout(FinalRangeTimeOutMClks);
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_WrWord(Dev, 0x71,
+ FinalRangeEncodedTimeOut);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeTimeoutMicroSecs,
+ TimeOutMicroSecs);
+ }
+ }
+ } else
+ Status = VL_ERROR_INVALID_PARAMS;
+
+ }
+ return Status;
+}
+
+int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t vcsel_period_reg;
+ uint8_t MinPreVcselPeriodPCLK = 12;
+ uint8_t MaxPreVcselPeriodPCLK = 18;
+ uint8_t MinFinalVcselPeriodPCLK = 8;
+ uint8_t MaxFinalVcselPeriodPCLK = 14;
+ uint32_t MeasurementTimingBudgetMicroSeconds;
+ uint32_t FinalRangeTimeoutMicroSeconds;
+ uint32_t PreRangeTimeoutMicroSeconds;
+ uint32_t MsrcTimeoutMicroSeconds;
+ uint8_t PhaseCalInt = 0;
+
+ /* Check if valid clock period requested */
+
+ if ((VCSELPulsePeriodPCLK % 2) != 0) {
+ /* Value must be an even number */
+ Status = VL_ERROR_INVALID_PARAMS;
+ } else if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE &&
+ (VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK ||
+ VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) {
+ Status = VL_ERROR_INVALID_PARAMS;
+ } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE &&
+ (VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK ||
+ VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) {
+
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+
+ /* Apply specific settings for the requested clock period */
+
+ if (Status != VL_ERROR_NONE)
+ return Status;
+
+
+ if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE) {
+
+ /* Set phase check limits */
+ if (VCSELPulsePeriodPCLK == 12) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x18);
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ } else if (VCSELPulsePeriodPCLK == 14) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x30);
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ } else if (VCSELPulsePeriodPCLK == 16) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x40);
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ } else if (VCSELPulsePeriodPCLK == 18) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x50);
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+ }
+ } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE) {
+
+ if (VCSELPulsePeriodPCLK == 8) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x10);
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL_WrByte(Dev,
+ VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x01);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_LIM,
+ 0x30);
+ Status |= VL_WrByte(Dev, 0xff, 0x00);
+ } else if (VCSELPulsePeriodPCLK == 10) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x28);
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL_WrByte(Dev,
+ VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x01);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_LIM,
+ 0x20);
+ Status |= VL_WrByte(Dev, 0xff, 0x00);
+ } else if (VCSELPulsePeriodPCLK == 12) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x38);
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL_WrByte(Dev,
+ VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x01);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_LIM,
+ 0x20);
+ Status |= VL_WrByte(Dev, 0xff, 0x00);
+ } else if (VCSELPulsePeriodPCLK == 14) {
+
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
+ 0x048);
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
+ 0x08);
+
+ Status |= VL_WrByte(Dev,
+ VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
+
+ Status |= VL_WrByte(Dev, 0xff, 0x01);
+ Status |= VL_WrByte(Dev,
+ VL_REG_ALGO_PHASECAL_LIM,
+ 0x20);
+ Status |= VL_WrByte(Dev, 0xff, 0x00);
+ }
+ }
+
+
+ /* Re-calculate and apply timeouts, in macro periods */
+
+ if (Status == VL_ERROR_NONE) {
+ vcsel_period_reg = VL_encode_vcsel_period((uint8_t)
+ VCSELPulsePeriodPCLK);
+
+ /* When the VCSEL period for the pre or final range is changed, */
+ /* the corresponding timeout must be read from the device using */
+ /* the current VCSEL period, then the new VCSEL period can be */
+ /* applied. The timeout then must be written back to the device */
+ /* using the new VCSEL period. */
+ /* For the MSRC timeout, the same applies - this timeout being */
+ /* dependent on the pre-range vcsel period. */
+ switch (VcselPeriodType) {
+ case VL_VCSEL_PERIOD_PRE_RANGE:
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_PRE_RANGE,
+ &PreRangeTimeoutMicroSeconds);
+
+ if (Status == VL_ERROR_NONE)
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_MSRC,
+ &MsrcTimeoutMicroSeconds);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
+ vcsel_period_reg);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = set_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_PRE_RANGE,
+ PreRangeTimeoutMicroSeconds);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = set_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_MSRC,
+ MsrcTimeoutMicroSeconds);
+
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ PreRangeVcselPulsePeriod,
+ VCSELPulsePeriodPCLK);
+ break;
+ case VL_VCSEL_PERIOD_FINAL_RANGE:
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_FINAL_RANGE,
+ &FinalRangeTimeoutMicroSeconds);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
+ vcsel_period_reg);
+
+
+ if (Status == VL_ERROR_NONE)
+ Status = set_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_FINAL_RANGE,
+ FinalRangeTimeoutMicroSeconds);
+
+ VL_SETDEVICESPECIFICPARAMETER(
+ Dev,
+ FinalRangeVcselPulsePeriod,
+ VCSELPulsePeriodPCLK);
+ break;
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ /* Finally, the timing budget must be re-applied */
+ if (Status == VL_ERROR_NONE) {
+ VL_GETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+
+ Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+
+ /* Perform the phase calibration. This is needed after changing on */
+ /* vcsel period. */
+ /* get_data_enable = 0, restore_config = 1 */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_perform_phase_calibration(
+ Dev, &PhaseCalInt, 0, 1);
+
+ return Status;
+}
+
+int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev,
+ uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t vcsel_period_reg;
+
+ switch (VcselPeriodType) {
+ case VL_VCSEL_PERIOD_PRE_RANGE:
+ Status = VL_RdByte(Dev,
+ VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ case VL_VCSEL_PERIOD_FINAL_RANGE:
+ Status = VL_RdByte(Dev,
+ VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
+ &vcsel_period_reg);
+ break;
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+
+ if (Status == VL_ERROR_NONE)
+ *pVCSELPulsePeriodPCLK =
+ VL_decode_vcsel_period(vcsel_period_reg);
+
+ return Status;
+}
+
+
+
+int8_t VL_set_measurement_timing_budget_micro_seconds(
+ struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint32_t FinalRangeTimingBudgetMicroSeconds;
+ struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+ uint32_t MsrcDccTccTimeoutMicroSeconds = 2000;
+ uint32_t StartOverheadMicroSeconds = 1910;
+ uint32_t EndOverheadMicroSeconds = 960;
+ uint32_t MsrcOverheadMicroSeconds = 660;
+ uint32_t TccOverheadMicroSeconds = 590;
+ uint32_t DssOverheadMicroSeconds = 690;
+ uint32_t PreRangeOverheadMicroSeconds = 660;
+ uint32_t FinalRangeOverheadMicroSeconds = 550;
+ uint32_t PreRangeTimeoutMicroSeconds = 0;
+ uint32_t cMinTimingBudgetMicroSeconds = 20000;
+ uint32_t SubTimeout = 0;
+
+ LOG_FUNCTION_START("");
+
+ if (MeasurementTimingBudgetMicroSeconds
+ < cMinTimingBudgetMicroSeconds) {
+ Status = VL_ERROR_INVALID_PARAMS;
+ return Status;
+ }
+
+ FinalRangeTimingBudgetMicroSeconds =
+ MeasurementTimingBudgetMicroSeconds -
+ (StartOverheadMicroSeconds + EndOverheadMicroSeconds);
+
+ Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+
+ if (Status == VL_ERROR_NONE &&
+ (SchedulerSequenceSteps.TccOn ||
+ SchedulerSequenceSteps.MsrcOn ||
+ SchedulerSequenceSteps.DssOn)) {
+
+ /* TCC, MSRC and DSS all share the same timeout */
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_MSRC,
+ &MsrcDccTccTimeoutMicroSeconds);
+
+ /* Subtract the TCC, MSRC and DSS timeouts if they are */
+ /* enabled. */
+
+ if (Status != VL_ERROR_NONE)
+ return Status;
+
+ /* TCC */
+ if (SchedulerSequenceSteps.TccOn) {
+
+ SubTimeout = MsrcDccTccTimeoutMicroSeconds
+ + TccOverheadMicroSeconds;
+
+ if (SubTimeout <
+ FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds -=
+ SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ if (Status != VL_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+ /* DSS */
+ if (SchedulerSequenceSteps.DssOn) {
+
+ SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds +
+ DssOverheadMicroSeconds);
+
+ if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds
+ -= SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ } else if (SchedulerSequenceSteps.MsrcOn) {
+ /* MSRC */
+ SubTimeout = MsrcDccTccTimeoutMicroSeconds +
+ MsrcOverheadMicroSeconds;
+
+ if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds
+ -= SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ }
+
+ if (Status != VL_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+ if (SchedulerSequenceSteps.PreRangeOn) {
+
+ /* Subtract the Pre-range timeout if enabled. */
+
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_PRE_RANGE,
+ &PreRangeTimeoutMicroSeconds);
+
+ SubTimeout = PreRangeTimeoutMicroSeconds +
+ PreRangeOverheadMicroSeconds;
+
+ if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
+ FinalRangeTimingBudgetMicroSeconds -= SubTimeout;
+ } else {
+ /* Requested timeout too big. */
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+
+ if (Status == VL_ERROR_NONE &&
+ SchedulerSequenceSteps.FinalRangeOn) {
+
+ FinalRangeTimingBudgetMicroSeconds -=
+ FinalRangeOverheadMicroSeconds;
+
+ /* Final Range Timeout
+ * Note that the final range timeout is determined by the timing
+ * budget and the sum of all other timeouts within the sequence.
+ * If there is no room for the final range timeout,then an error
+ * will be set. Otherwise the remaining time will be applied to
+ * the final range.
+ */
+ Status = set_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_FINAL_RANGE,
+ FinalRangeTimingBudgetMicroSeconds);
+
+ VL_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ MeasurementTimingBudgetMicroSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+int8_t VL_get_measurement_timing_budget_micro_seconds(
+ struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds)
+{
+ int8_t Status = VL_ERROR_NONE;
+ struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps;
+ uint32_t FinalRangeTimeoutMicroSeconds;
+ uint32_t MsrcDccTccTimeoutMicroSeconds = 2000;
+ uint32_t StartOverheadMicroSeconds = 1910;
+ uint32_t EndOverheadMicroSeconds = 960;
+ uint32_t MsrcOverheadMicroSeconds = 660;
+ uint32_t TccOverheadMicroSeconds = 590;
+ uint32_t DssOverheadMicroSeconds = 690;
+ uint32_t PreRangeOverheadMicroSeconds = 660;
+ uint32_t FinalRangeOverheadMicroSeconds = 550;
+ uint32_t PreRangeTimeoutMicroSeconds = 0;
+
+ LOG_FUNCTION_START("");
+
+ /* Start and end overhead times always present */
+ *pMeasurementTimingBudgetMicroSeconds
+ = StartOverheadMicroSeconds + EndOverheadMicroSeconds;
+
+ Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
+
+ if (Status != VL_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+
+ if (SchedulerSequenceSteps.TccOn ||
+ SchedulerSequenceSteps.MsrcOn ||
+ SchedulerSequenceSteps.DssOn) {
+
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_MSRC,
+ &MsrcDccTccTimeoutMicroSeconds);
+
+ if (Status == VL_ERROR_NONE) {
+ if (SchedulerSequenceSteps.TccOn) {
+ *pMeasurementTimingBudgetMicroSeconds +=
+ MsrcDccTccTimeoutMicroSeconds +
+ TccOverheadMicroSeconds;
+ }
+
+ if (SchedulerSequenceSteps.DssOn) {
+ *pMeasurementTimingBudgetMicroSeconds +=
+ 2 * (MsrcDccTccTimeoutMicroSeconds +
+ DssOverheadMicroSeconds);
+ } else if (SchedulerSequenceSteps.MsrcOn) {
+ *pMeasurementTimingBudgetMicroSeconds +=
+ MsrcDccTccTimeoutMicroSeconds +
+ MsrcOverheadMicroSeconds;
+ }
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ if (SchedulerSequenceSteps.PreRangeOn) {
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_PRE_RANGE,
+ &PreRangeTimeoutMicroSeconds);
+ *pMeasurementTimingBudgetMicroSeconds +=
+ PreRangeTimeoutMicroSeconds +
+ PreRangeOverheadMicroSeconds;
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ if (SchedulerSequenceSteps.FinalRangeOn) {
+ Status = get_sequence_step_timeout(Dev,
+ VL_SEQUENCESTEP_FINAL_RANGE,
+ &FinalRangeTimeoutMicroSeconds);
+ *pMeasurementTimingBudgetMicroSeconds +=
+ (FinalRangeTimeoutMicroSeconds +
+ FinalRangeOverheadMicroSeconds);
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ VL_SETPARAMETERFIELD(Dev,
+ MeasurementTimingBudgetMicroSeconds,
+ *pMeasurementTimingBudgetMicroSeconds);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+
+int8_t VL_load_tuning_settings(struct vl_data *Dev,
+ uint8_t *pTuningSettingBuffer)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int i;
+ int Index;
+ uint8_t msb;
+ uint8_t lsb;
+ uint8_t SelectParam;
+ uint8_t NumberOfWrites;
+ uint8_t Address;
+ uint8_t localBuffer[4]; /* max */
+ uint16_t Temp16;
+
+ LOG_FUNCTION_START("");
+
+ Index = 0;
+
+ while ((*(pTuningSettingBuffer + Index) != 0) &&
+ (Status == VL_ERROR_NONE)) {
+ NumberOfWrites = *(pTuningSettingBuffer + Index);
+ Index++;
+ if (NumberOfWrites == 0xFF) {
+ /* internal parameters */
+ SelectParam = *(pTuningSettingBuffer + Index);
+ Index++;
+ switch (SelectParam) {
+ case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, SigmaEstRefArray, Temp16);
+ break;
+ case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, SigmaEstEffPulseWidth,
+ Temp16);
+ break;
+ case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16);
+ break;
+ case 3: /* uint16_t targetRefRate -> 2 bytes */
+ msb = *(pTuningSettingBuffer + Index);
+ Index++;
+ lsb = *(pTuningSettingBuffer + Index);
+ Index++;
+ Temp16 = VL_MAKEUINT16(lsb, msb);
+ PALDevDataSet(Dev, targetRefRate, Temp16);
+ break;
+ default: /* invalid parameter */
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+
+ } else if (NumberOfWrites <= 4) {
+ Address = *(pTuningSettingBuffer + Index);
+ Index++;
+
+ for (i = 0; i < NumberOfWrites; i++) {
+ localBuffer[i] = *(pTuningSettingBuffer +
+ Index);
+ Index++;
+ }
+
+ Status = VL_WriteMulti(Dev, Address, localBuffer,
+ NumberOfWrites);
+
+ } else {
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_total_xtalk_rate(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ unsigned int *ptotal_xtalk_rate_mcps)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ uint8_t xtalkCompEnable;
+ unsigned int totalXtalkMegaCps;
+ unsigned int xtalkPerSpadMegaCps;
+
+ *ptotal_xtalk_rate_mcps = 0;
+
+ Status = VL_GetXTalkCompensationEnable(Dev, &xtalkCompEnable);
+ if (Status == VL_ERROR_NONE) {
+
+ if (xtalkCompEnable) {
+
+ VL_GETPARAMETERFIELD(
+ Dev,
+ XTalkCompensationRateMegaCps,
+ xtalkPerSpadMegaCps);
+
+ /* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */
+ totalXtalkMegaCps =
+ pRangingMeasurementData->EffectiveSpadRtnCount *
+ xtalkPerSpadMegaCps;
+
+ /* FixPoint0824 >> 8 = FixPoint1616 */
+ *ptotal_xtalk_rate_mcps =
+ (totalXtalkMegaCps + 0x80) >> 8;
+ }
+ }
+
+ return Status;
+}
+
+int8_t VL_get_total_signal_rate(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ unsigned int *ptotal_signal_rate_mcps)
+{
+ int8_t Status = VL_ERROR_NONE;
+ unsigned int totalXtalkMegaCps;
+
+ LOG_FUNCTION_START("");
+
+ *ptotal_signal_rate_mcps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+
+ Status = VL_get_total_xtalk_rate(
+ Dev, pRangingMeasurementData, &totalXtalkMegaCps);
+
+ if (Status == VL_ERROR_NONE)
+ *ptotal_signal_rate_mcps += totalXtalkMegaCps;
+
+ return Status;
+}
+
+int8_t VL_calc_dmax(
+ struct vl_data *Dev,
+ unsigned int totalSignalRate_mcps,
+ unsigned int totalCorrSignalRate_mcps,
+ unsigned int pwMult,
+ uint32_t sigmaEstimateP1,
+ unsigned int sigmaEstimateP2,
+ uint32_t peakVcselDuration_us,
+ uint32_t *pdmax_mm)
+{
+ const uint32_t cSigmaLimit = 18;
+ const unsigned int cSignalLimit = 0x4000; /* 0.25 */
+ const unsigned int cSigmaEstRef = 0x00000042; /* 0.001 */
+ const uint32_t cAmbEffWidthSigmaEst_ns = 6;
+ const uint32_t cAmbEffWidthDMax_ns = 7;
+ uint32_t dmaxCalRange_mm;
+ unsigned int dmaxCalSignalRateRtn_mcps;
+ unsigned int minSignalNeeded;
+ unsigned int minSignalNeeded_p1;
+ unsigned int minSignalNeeded_p2;
+ unsigned int minSignalNeeded_p3;
+ unsigned int minSignalNeeded_p4;
+ unsigned int sigmaLimitTmp;
+ unsigned int sigmaEstSqTmp;
+ unsigned int signalLimitTmp;
+ unsigned int SignalAt0mm;
+ unsigned int dmaxDark;
+ unsigned int dmaxAmbient;
+ unsigned int dmaxDarkTmp;
+ unsigned int sigmaEstP2Tmp;
+ uint32_t signalRateTemp_mcps;
+
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ dmaxCalRange_mm =
+ PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
+
+ dmaxCalSignalRateRtn_mcps =
+ PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps);
+
+ /* uint32 * FixPoint1616 = FixPoint1616 */
+ SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps;
+
+ /* FixPoint1616 >> 8 = FixPoint2408 */
+ SignalAt0mm = (SignalAt0mm + 0x80) >> 8;
+ SignalAt0mm *= dmaxCalRange_mm;
+
+ minSignalNeeded_p1 = 0;
+ if (totalCorrSignalRate_mcps > 0) {
+
+ /* Shift by 10 bits to increase resolution prior to the */
+ /* division */
+ signalRateTemp_mcps = totalSignalRate_mcps << 10;
+
+ /* Add rounding value prior to division */
+ minSignalNeeded_p1 = signalRateTemp_mcps +
+ (totalCorrSignalRate_mcps/2);
+
+ /* FixPoint0626/FixPoint1616 = FixPoint2210 */
+ minSignalNeeded_p1 /= totalCorrSignalRate_mcps;
+
+ /* Apply a factored version of the speed of light. */
+ /* Correction to be applied at the end */
+ minSignalNeeded_p1 *= 3;
+
+ /* FixPoint2210 * FixPoint2210 = FixPoint1220 */
+ minSignalNeeded_p1 *= minSignalNeeded_p1;
+
+ /* FixPoint1220 >> 16 = FixPoint2804 */
+ minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16;
+ }
+
+ minSignalNeeded_p2 = pwMult * sigmaEstimateP1;
+
+ /* FixPoint1616 >> 16 = uint32 */
+ minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16;
+
+ /* uint32 * uint32 = uint32 */
+ minSignalNeeded_p2 *= minSignalNeeded_p2;
+
+ /* Check sigmaEstimateP2
+ * If this value is too high there is not enough signal rate
+ * to calculate dmax value so set a suitable value to ensure
+ * a very small dmax.
+ */
+ sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16;
+ sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/
+ cAmbEffWidthSigmaEst_ns;
+ sigmaEstP2Tmp *= cAmbEffWidthDMax_ns;
+
+ if (sigmaEstP2Tmp > 0xffff) {
+ minSignalNeeded_p3 = 0xfff00000;
+ } else {
+
+ /* DMAX uses a different ambient width from sigma, so apply
+ * correction.
+ * Perform division before multiplication to prevent overflow.
+ */
+ sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/
+ cAmbEffWidthSigmaEst_ns;
+ sigmaEstimateP2 *= cAmbEffWidthDMax_ns;
+
+ /* FixPoint1616 >> 16 = uint32 */
+ minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16;
+
+ minSignalNeeded_p3 *= minSignalNeeded_p3;
+
+ }
+
+ /* FixPoint1814 / uint32 = FixPoint1814 */
+ sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000;
+
+ /* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */
+ sigmaLimitTmp *= sigmaLimitTmp;
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef;
+
+ /* FixPoint3232 >> 4 = FixPoint0428 */
+ sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4;
+
+ /* FixPoint0428 - FixPoint0428 = FixPoint0428 */
+ sigmaLimitTmp -= sigmaEstSqTmp;
+
+ /* uint32_t * FixPoint0428 = FixPoint0428 */
+ minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp;
+
+ /* FixPoint0428 >> 14 = FixPoint1814 */
+ minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14;
+
+ /* uint32 + uint32 = uint32 */
+ minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3);
+
+ /* uint32 / uint32 = uint32 */
+ minSignalNeeded += (peakVcselDuration_us/2);
+ minSignalNeeded /= peakVcselDuration_us;
+
+ /* uint32 << 14 = FixPoint1814 */
+ minSignalNeeded <<= 14;
+
+ /* FixPoint1814 / FixPoint1814 = uint32 */
+ minSignalNeeded += (minSignalNeeded_p4/2);
+ minSignalNeeded /= minSignalNeeded_p4;
+
+ /* FixPoint3200 * FixPoint2804 := FixPoint2804*/
+ minSignalNeeded *= minSignalNeeded_p1;
+
+ /* Apply correction by dividing by 1000000.
+ * This assumes 10E16 on the numerator of the equation
+ * and 10E-22 on the denominator.
+ * We do this because 32bit fix point calculation can't
+ * handle the larger and smaller elements of this equation,
+ * i.e. speed of light and pulse widths.
+ */
+ minSignalNeeded = (minSignalNeeded + 500) / 1000;
+ minSignalNeeded <<= 4;
+
+ minSignalNeeded = (minSignalNeeded + 500) / 1000;
+
+ /* FixPoint1616 >> 8 = FixPoint2408 */
+ signalLimitTmp = (cSignalLimit + 0x80) >> 8;
+
+ /* FixPoint2408/FixPoint2408 = uint32 */
+ if (signalLimitTmp != 0)
+ dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2))
+ / signalLimitTmp;
+ else
+ dmaxDarkTmp = 0;
+
+ dmaxDark = VL_isqrt(dmaxDarkTmp);
+
+ /* FixPoint2408/FixPoint2408 = uint32 */
+ if (minSignalNeeded != 0)
+ dmaxAmbient = (SignalAt0mm + minSignalNeeded/2)
+ / minSignalNeeded;
+ else
+ dmaxAmbient = 0;
+
+ dmaxAmbient = VL_isqrt(dmaxAmbient);
+
+ *pdmax_mm = dmaxDark;
+ if (dmaxDark > dmaxAmbient)
+ *pdmax_mm = dmaxAmbient;
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+int8_t VL_calc_sigma_estimate(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ unsigned int *pSigmaEstimate,
+ uint32_t *pDmax_mm)
+{
+ /* Expressed in 100ths of a ns, i.e. centi-ns */
+ const uint32_t cPulseEffectiveWidth_centi_ns = 800;
+ /* Expressed in 100ths of a ns, i.e. centi-ns */
+ const uint32_t cAmbientEffectiveWidth_centi_ns = 600;
+ /* 25ms */
+ const unsigned int cDfltFinalRangeIntegrationTimeMilliSecs =
+ 0x00190000;
+ const uint32_t cVcselPulseWidth_ps = 4700; /* pico secs */
+ const unsigned int cSigmaEstMax = 0x028F87AE;
+ const unsigned int cSigmaEstRtnMax = 0xF000;
+ const unsigned int cAmbToSignalRatioMax = 0xF0000000/
+ cAmbientEffectiveWidth_centi_ns;
+ /* Time Of Flight per mm (6.6 pico secs) */
+ const unsigned int cTOF_per_mm_ps = 0x0006999A;
+ const uint32_t c16BitRoundingParam = 0x00008000;
+ const unsigned int cMaxXTalk_kcps = 0x00320000;
+ const uint32_t cPllPeriod_ps = 1655;
+
+ uint32_t vcselTotalEventsRtn;
+ uint32_t finalRangeTimeoutMicroSecs;
+ uint32_t preRangeTimeoutMicroSecs;
+ uint32_t finalRangeIntegrationTimeMilliSecs;
+ unsigned int sigmaEstimateP1;
+ unsigned int sigmaEstimateP2;
+ unsigned int sigmaEstimateP3;
+ unsigned int deltaT_ps;
+ unsigned int pwMult;
+ unsigned int sigmaEstRtn;
+ unsigned int sigmaEstimate;
+ unsigned int xTalkCorrection;
+ unsigned int ambientRate_kcps;
+ unsigned int peakSignalRate_kcps;
+ unsigned int xTalkCompRate_mcps;
+ uint32_t xTalkCompRate_kcps;
+ int8_t Status = VL_ERROR_NONE;
+ unsigned int diff1_mcps;
+ unsigned int diff2_mcps;
+ unsigned int sqr1;
+ unsigned int sqr2;
+ unsigned int sqrSum;
+ unsigned int sqrtResult_centi_ns;
+ unsigned int sqrtResult;
+ unsigned int totalSignalRate_mcps;
+ unsigned int correctedSignalRate_mcps;
+ unsigned int sigmaEstRef;
+ uint32_t vcselWidth;
+ uint32_t finalRangeMacroPCLKS;
+ uint32_t preRangeMacroPCLKS;
+ uint32_t peakVcselDuration_us;
+ uint8_t finalRangeVcselPCLKS;
+ uint8_t preRangeVcselPCLKS;
+ /*! \addtogroup calc_sigma_estimate
+ * @{
+ *
+ * Estimates the range sigma
+ */
+
+ LOG_FUNCTION_START("");
+
+ VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
+ xTalkCompRate_mcps);
+
+ /*
+ * We work in kcps rather than mcps as this helps keep within the
+ * confines of the 32 Fix1616 type.
+ */
+
+ ambientRate_kcps =
+ (pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16;
+
+ correctedSignalRate_mcps =
+ pRangingMeasurementData->SignalRateRtnMegaCps;
+
+
+ Status = VL_get_total_signal_rate(
+ Dev, pRangingMeasurementData, &totalSignalRate_mcps);
+ Status = VL_get_total_xtalk_rate(
+ Dev, pRangingMeasurementData, &xTalkCompRate_mcps);
+
+
+ /* Signal rate measurement provided by device is the
+ * peak signal rate, not average.
+ */
+ peakSignalRate_kcps = (totalSignalRate_mcps * 1000);
+ peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16;
+
+ xTalkCompRate_kcps = xTalkCompRate_mcps * 1000;
+
+ if (xTalkCompRate_kcps > cMaxXTalk_kcps)
+ xTalkCompRate_kcps = cMaxXTalk_kcps;
+
+ if (Status == VL_ERROR_NONE) {
+
+ /* Calculate final range macro periods */
+ finalRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER(
+ Dev, FinalRangeTimeoutMicroSecs);
+
+ finalRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER(
+ Dev, FinalRangeVcselPulsePeriod);
+
+ finalRangeMacroPCLKS = VL_calc_timeout_mclks(
+ Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS);
+
+ /* Calculate pre-range macro periods */
+ preRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER(
+ Dev, PreRangeTimeoutMicroSecs);
+
+ preRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER(
+ Dev, PreRangeVcselPulsePeriod);
+
+ preRangeMacroPCLKS = VL_calc_timeout_mclks(
+ Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS);
+
+ vcselWidth = 3;
+ if (finalRangeVcselPCLKS == 8)
+ vcselWidth = 2;
+
+
+ peakVcselDuration_us = vcselWidth * 2048 *
+ (preRangeMacroPCLKS + finalRangeMacroPCLKS);
+ peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
+ peakVcselDuration_us *= cPllPeriod_ps;
+ peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
+
+ /* Fix1616 >> 8 = Fix2408 */
+ totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8;
+
+ /* Fix2408 * uint32 = Fix2408 */
+ vcselTotalEventsRtn = totalSignalRate_mcps *
+ peakVcselDuration_us;
+
+ /* Fix2408 >> 8 = uint32 */
+ vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8;
+
+ /* Fix2408 << 8 = Fix1616 = */
+ totalSignalRate_mcps <<= 8;
+ }
+
+ if (Status != VL_ERROR_NONE) {
+ LOG_FUNCTION_END(Status);
+ return Status;
+ }
+
+ if (peakSignalRate_kcps == 0) {
+ *pSigmaEstimate = cSigmaEstMax;
+ PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax);
+ *pDmax_mm = 0;
+ } else {
+ if (vcselTotalEventsRtn < 1)
+ vcselTotalEventsRtn = 1;
+
+ sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns;
+
+ /* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */
+ sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps;
+ if (sigmaEstimateP2 > cAmbToSignalRatioMax) {
+ /* Clip to prevent overflow. Will ensure safe */
+ /* max result. */
+ sigmaEstimateP2 = cAmbToSignalRatioMax;
+ }
+ sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns;
+
+ sigmaEstimateP3 = 2 * VL_isqrt(vcselTotalEventsRtn * 12);
+
+ /* uint32 * FixPoint1616 = FixPoint1616 */
+ deltaT_ps = pRangingMeasurementData->RangeMilliMeter *
+ cTOF_per_mm_ps;
+
+ /* vcselRate - xtalkCompRate */
+ /* (uint32 << 16) - FixPoint1616 = FixPoint1616. */
+ /* Divide result by 1000 to convert to mcps. */
+ /* 500 is added to ensure rounding when integer division */
+ /* truncates. */
+ diff1_mcps = (((peakSignalRate_kcps << 16) -
+ 2 * xTalkCompRate_kcps) + 500)/1000;
+
+ /* vcselRate + xtalkCompRate */
+ diff2_mcps = ((peakSignalRate_kcps << 16) + 500)/1000;
+
+ /* Shift by 8 bits to increase resolution prior to the */
+ /* division */
+ diff1_mcps <<= 8;
+
+ /* FixPoint0824/FixPoint1616 = FixPoint2408 */
+ xTalkCorrection = abs(diff1_mcps/diff2_mcps);
+
+ /* FixPoint2408 << 8 = FixPoint1616 */
+ xTalkCorrection <<= 8;
+
+ if (pRangingMeasurementData->RangeStatus != 0) {
+ pwMult = 1 << 16;
+ } else {
+ /* FixPoint1616/uint32 = FixPoint1616 *i */
+ /* smaller than 1.0f */
+ pwMult = deltaT_ps/cVcselPulseWidth_ps;
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232, however both */
+ /* values are small enough such that32 bits will not be */
+ /* exceeded. */
+ pwMult *= ((1 << 16) - xTalkCorrection);
+
+ /* (FixPoint3232 >> 16) = FixPoint1616 */
+ pwMult = (pwMult + c16BitRoundingParam) >> 16;
+
+ /* FixPoint1616 + FixPoint1616 = FixPoint1616 */
+ pwMult += (1 << 16);
+
+ /* At this point the value will be 1.xx, */
+ /* therefore if we square */
+ /* the value this will exceed 32 bits. */
+ /* To address this perform */
+ /* a single shift to the right before the multiplication. */
+ pwMult >>= 1;
+ /* FixPoint1715 * FixPoint1715 = FixPoint3430 */
+ pwMult = pwMult * pwMult;
+
+ /* (FixPoint3430 >> 14) = Fix1616 */
+ pwMult >>= 14;
+ }
+
+ /* FixPoint1616 * uint32 = FixPoint1616 */
+ sqr1 = pwMult * sigmaEstimateP1;
+
+ /* (FixPoint1616 >> 16) = FixPoint3200 */
+ sqr1 = (sqr1 + 0x8000) >> 16;
+
+ /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
+ sqr1 *= sqr1;
+
+ sqr2 = sigmaEstimateP2;
+
+ /* (FixPoint1616 >> 16) = FixPoint3200 */
+ sqr2 = (sqr2 + 0x8000) >> 16;
+
+ /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
+ sqr2 *= sqr2;
+
+ /* FixPoint64000 + FixPoint6400 = FixPoint6400 */
+ sqrSum = sqr1 + sqr2;
+
+ /* SQRT(FixPoin6400) = FixPoint3200 */
+ sqrtResult_centi_ns = VL_isqrt(sqrSum);
+
+ /* (FixPoint3200 << 16) = FixPoint1616 */
+ sqrtResult_centi_ns <<= 16;
+
+ /*
+ * Note that the Speed Of Light is expressed in um per 1E-10
+ * seconds (2997) Therefore to get mm/ns we have to divide by
+ * 10000
+ */
+ sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) /
+ sigmaEstimateP3);
+ sigmaEstRtn *= VL_SPEED_OF_LIGHT_IN_AIR;
+
+ /* Add 5000 before dividing by 10000 to ensure rounding. */
+ sigmaEstRtn += 5000;
+ sigmaEstRtn /= 10000;
+
+ if (sigmaEstRtn > cSigmaEstRtnMax) {
+ /* Clip to prevent overflow. Will ensure safe */
+ /* max result. */
+ sigmaEstRtn = cSigmaEstRtnMax;
+ }
+ finalRangeIntegrationTimeMilliSecs =
+ (finalRangeTimeoutMicroSecs +
+ preRangeTimeoutMicroSecs + 500)/1000;
+
+ /* sigmaEstRef = 1mm * 25ms/final range integration time */
+ /* (inc pre-range) sqrt(FixPoint1616/int) = FixPoint2408) */
+ sigmaEstRef =
+ VL_isqrt((cDfltFinalRangeIntegrationTimeMilliSecs +
+ finalRangeIntegrationTimeMilliSecs/2)/
+ finalRangeIntegrationTimeMilliSecs);
+
+ /* FixPoint2408 << 8 = FixPoint1616 */
+ sigmaEstRef <<= 8;
+ sigmaEstRef = (sigmaEstRef + 500)/1000;
+
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr1 = sigmaEstRtn * sigmaEstRtn;
+ /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
+ sqr2 = sigmaEstRef * sigmaEstRef;
+
+ /* sqrt(FixPoint3232) = FixPoint1616 */
+ sqrtResult = VL_isqrt((sqr1 + sqr2));
+ /* Note that the Shift by 4 bits increases */
+ /*resolution prior to */
+ /* the sqrt, therefore the result must be */
+ /* shifted by 2 bits to */
+ /* the right to revert back to the FixPoint1616 format. */
+
+ sigmaEstimate = 1000 * sqrtResult;
+
+ if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) ||
+ (sigmaEstimate > cSigmaEstMax)) {
+ sigmaEstimate = cSigmaEstMax;
+ }
+
+ *pSigmaEstimate = (uint32_t)(sigmaEstimate);
+ PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate);
+ Status = VL_calc_dmax(
+ Dev,
+ totalSignalRate_mcps,
+ correctedSignalRate_mcps,
+ pwMult,
+ sigmaEstimateP1,
+ sigmaEstimateP2,
+ peakVcselDuration_us,
+ pDmax_mm);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_pal_range_status(struct vl_data *Dev,
+ uint8_t DeviceRangeStatus,
+ unsigned int SignalRate,
+ uint16_t EffectiveSpadRtnCount,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData,
+ uint8_t *pPalRangeStatus)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t NoneFlag;
+ uint8_t SigmaLimitflag = 0;
+ uint8_t SignalRefClipflag = 0;
+ uint8_t RangeIgnoreThresholdflag = 0;
+ uint8_t SigmaLimitCheckEnable = 0;
+ uint8_t SignalRateFinalRangeLimitCheckEnable = 0;
+ uint8_t SignalRefClipLimitCheckEnable = 0;
+ uint8_t RangeIgnoreThresholdLimitCheckEnable = 0;
+ unsigned int SigmaEstimate;
+ unsigned int SigmaLimitValue;
+ unsigned int SignalRefClipValue;
+ unsigned int RangeIgnoreThresholdValue;
+ unsigned int SignalRatePerSpad;
+ uint8_t DeviceRangeStatusInternal = 0;
+ uint16_t tmpWord = 0;
+ uint8_t Temp8;
+ uint32_t Dmax_mm = 0;
+ unsigned int LastSignalRefMcps;
+
+ LOG_FUNCTION_START("");
+
+
+ /*
+ * VL53L0X has a good ranging when the value of the
+ * DeviceRangeStatus = 11. This function will replace the value 0 with
+ * the value 11 in the DeviceRangeStatus.
+ * In addition, the SigmaEstimator is not included in the VL53L0X
+ * DeviceRangeStatus, this will be added in the PalRangeStatus.
+ */
+
+ DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3);
+
+ if (DeviceRangeStatusInternal == 0 ||
+ DeviceRangeStatusInternal == 5 ||
+ DeviceRangeStatusInternal == 7 ||
+ DeviceRangeStatusInternal == 12 ||
+ DeviceRangeStatusInternal == 13 ||
+ DeviceRangeStatusInternal == 14 ||
+ DeviceRangeStatusInternal == 15
+ ) {
+ NoneFlag = 1;
+ } else {
+ NoneFlag = 0;
+ }
+
+ /*
+ * Check if Sigma limit is enabled, if yes then do comparison with limit
+ * value and put the result back into pPalRangeStatus.
+ */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &SigmaLimitCheckEnable);
+
+ if ((SigmaLimitCheckEnable != 0) && (Status == VL_ERROR_NONE)) {
+ /* compute the Sigma and check with limit */
+ Status = VL_calc_sigma_estimate(
+ Dev,
+ pRangingMeasurementData,
+ &SigmaEstimate,
+ &Dmax_mm);
+ if (Status == VL_ERROR_NONE)
+ pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm;
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_GetLimitCheckValue(Dev,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &SigmaLimitValue);
+
+ if ((SigmaLimitValue > 0) &&
+ (SigmaEstimate > SigmaLimitValue))
+ /* Limit Fail */
+ SigmaLimitflag = 1;
+ }
+ }
+
+ /* Check if Signal ref clip limit is enabled, */
+ /* if yes then do comparison */
+ /* with limit value and put the result back into pPalRangeStatus. */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP,
+ &SignalRefClipLimitCheckEnable);
+
+ if ((SignalRefClipLimitCheckEnable != 0) &&
+ (Status == VL_ERROR_NONE)) {
+
+ Status = VL_GetLimitCheckValue(Dev,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP,
+ &SignalRefClipValue);
+
+ /* Read LastSignalRefMcps from device */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, 0xFF, 0x01);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_RdWord(Dev,
+ VL_REG_RESULT_PEAK_SIGNAL_RATE_REF,
+ &tmpWord);
+
+ if (Status == VL_ERROR_NONE)
+ Status = VL_WrByte(Dev, 0xFF, 0x00);
+
+ LastSignalRefMcps = VL_FIXPOINT97TOFIXPOINT1616(tmpWord);
+ PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps);
+
+ if ((SignalRefClipValue > 0) &&
+ (LastSignalRefMcps > SignalRefClipValue)) {
+ /* Limit Fail */
+ SignalRefClipflag = 1;
+ }
+ }
+
+ /*
+ * Check if Signal ref clip limit is enabled, if yes then do comparison
+ * with limit value and put the result back into pPalRangeStatus.
+ * EffectiveSpadRtnCount has a format 8.8
+ * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL
+ */
+ if (Status == VL_ERROR_NONE)
+ Status = VL_GetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ &RangeIgnoreThresholdLimitCheckEnable);
+
+ if ((RangeIgnoreThresholdLimitCheckEnable != 0) &&
+ (Status == VL_ERROR_NONE)) {
+
+ /* Compute the signal rate per spad */
+ if (EffectiveSpadRtnCount == 0) {
+ SignalRatePerSpad = 0;
+ } else {
+ SignalRatePerSpad = (unsigned int)((256 * SignalRate)
+ / EffectiveSpadRtnCount);
+ }
+
+ Status = VL_GetLimitCheckValue(Dev,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ &RangeIgnoreThresholdValue);
+
+ if ((RangeIgnoreThresholdValue > 0) &&
+ (SignalRatePerSpad < RangeIgnoreThresholdValue)) {
+ /* Limit Fail add 2^6 to range status */
+ RangeIgnoreThresholdflag = 1;
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ if (NoneFlag == 1) {
+ *pPalRangeStatus = 255; /* NONE */
+ } else if (DeviceRangeStatusInternal == 1 ||
+ DeviceRangeStatusInternal == 2 ||
+ DeviceRangeStatusInternal == 3) {
+ *pPalRangeStatus = 5; /* HW fail */
+ } else if (DeviceRangeStatusInternal == 6 ||
+ DeviceRangeStatusInternal == 9) {
+ *pPalRangeStatus = 4; /* Phase fail */
+ } else if (DeviceRangeStatusInternal == 8 ||
+ DeviceRangeStatusInternal == 10 ||
+ SignalRefClipflag == 1) {
+ *pPalRangeStatus = 3; /* Min range */
+ } else if (DeviceRangeStatusInternal == 4 ||
+ RangeIgnoreThresholdflag == 1) {
+ *pPalRangeStatus = 2; /* Signal Fail */
+ } else if (SigmaLimitflag == 1) {
+ *pPalRangeStatus = 1; /* Sigma Fail */
+ } else {
+ *pPalRangeStatus = 0; /* Range Valid */
+ }
+ }
+
+ /* DMAX only relevant during range error */
+ if (*pPalRangeStatus == 0)
+ pRangingMeasurementData->RangeDMaxMilliMeter = 0;
+
+ /* fill the Limit Check Status */
+
+ Status = VL_GetLimitCheckEnable(Dev,
+ VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ &SignalRateFinalRangeLimitCheckEnable);
+
+ if (Status == VL_ERROR_NONE) {
+ if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8);
+
+ if ((DeviceRangeStatusInternal == 4) ||
+ (SignalRateFinalRangeLimitCheckEnable == 0))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ Temp8);
+
+ if ((SignalRefClipLimitCheckEnable == 0) ||
+ (SignalRefClipflag == 1))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL_CHECKENABLE_SIGNAL_REF_CLIP, Temp8);
+
+ if ((RangeIgnoreThresholdLimitCheckEnable == 0) ||
+ (RangeIgnoreThresholdflag == 1))
+ Temp8 = 1;
+ else
+ Temp8 = 0;
+
+ VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
+ VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
+ Temp8);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c
new file mode 100644
index 0000000..a1f4683
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c
@@ -0,0 +1,32 @@
+/*
+ * vl53l0x_api_ranging.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c
new file mode 100644
index 0000000..71fec10
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c
@@ -0,0 +1,455 @@
+/*
+ * vl53l0x_api_strings.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "vl53l0x_api.h"
+#include "vl53l0x_api_core.h"
+#include "vl53l0x_api_strings.h"
+
+#ifndef __KERNEL__
+#include <stdlib.h>
+#endif
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...) \
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
+
+
+int8_t VL_check_part_used(struct vl_data *Dev,
+ uint8_t *Revision,
+ struct VL_DeviceInfo_t *pVL_DeviceInfo)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t ModuleIdInt;
+ char *ProductId_tmp;
+
+ LOG_FUNCTION_START("");
+
+ Status = VL_get_info_from_device(Dev, 2);
+
+ if (Status == VL_ERROR_NONE) {
+ ModuleIdInt = VL_GETDEVICESPECIFICPARAMETER(Dev, ModuleId);
+
+ if (ModuleIdInt == 0) {
+ *Revision = 0;
+ VL_COPYSTRING(pVL_DeviceInfo->ProductId, "");
+ } else {
+ *Revision = VL_GETDEVICESPECIFICPARAMETER(Dev, Revision);
+ ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev,
+ ProductId);
+ VL_COPYSTRING(pVL_DeviceInfo->ProductId,
+ ProductId_tmp);
+ }
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+
+int8_t VL_get_device_info(struct vl_data *Dev,
+ struct VL_DeviceInfo_t *pVL_DeviceInfo)
+{
+ int8_t Status = VL_ERROR_NONE;
+ uint8_t revision_id;
+ uint8_t Revision;
+
+ Status = VL_check_part_used(Dev, &Revision, pVL_DeviceInfo);
+
+ if (Status == VL_ERROR_NONE) {
+ if (Revision == 0) {
+ VL_COPYSTRING(pVL_DeviceInfo->Name,
+ VL_STRING_DEVICE_INFO_NAME_TS0);
+ } else if ((Revision <= 34) && (Revision != 32)) {
+ VL_COPYSTRING(pVL_DeviceInfo->Name,
+ VL_STRING_DEVICE_INFO_NAME_TS1);
+ } else if (Revision < 39) {
+ VL_COPYSTRING(pVL_DeviceInfo->Name,
+ VL_STRING_DEVICE_INFO_NAME_TS2);
+ } else {
+ VL_COPYSTRING(pVL_DeviceInfo->Name,
+ VL_STRING_DEVICE_INFO_NAME_ES1);
+ }
+
+ VL_COPYSTRING(pVL_DeviceInfo->Type,
+ VL_STRING_DEVICE_INFO_TYPE);
+
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdByte(Dev,
+ VL_REG_IDENTIFICATION_MODEL_ID,
+ &pVL_DeviceInfo->ProductType);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = VL_RdByte(Dev,
+ VL_REG_IDENTIFICATION_REVISION_ID,
+ &revision_id);
+ pVL_DeviceInfo->ProductRevisionMajor = 1;
+ pVL_DeviceInfo->ProductRevisionMinor =
+ (revision_id & 0xF0) >> 4;
+ }
+
+ return Status;
+}
+
+
+int8_t VL_get_device_error_string(uint8_t ErrorCode,
+ char *pDeviceErrorString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (ErrorCode) {
+ case VL_DEVICEERROR_NONE:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_NONE);
+ break;
+ case VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE);
+ break;
+ case VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE);
+ break;
+ case VL_DEVICEERROR_NOVHVVALUEFOUND:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_NOVHVVALUEFOUND);
+ break;
+ case VL_DEVICEERROR_MSRCNOTARGET:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_MSRCNOTARGET);
+ break;
+ case VL_DEVICEERROR_SNRCHECK:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_SNRCHECK);
+ break;
+ case VL_DEVICEERROR_RANGEPHASECHECK:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_RANGEPHASECHECK);
+ break;
+ case VL_DEVICEERROR_SIGMATHRESHOLDCHECK:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK);
+ break;
+ case VL_DEVICEERROR_TCC:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_TCC);
+ break;
+ case VL_DEVICEERROR_PHASECONSISTENCY:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_PHASECONSISTENCY);
+ break;
+ case VL_DEVICEERROR_MINCLIP:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_MINCLIP);
+ break;
+ case VL_DEVICEERROR_RANGECOMPLETE:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_RANGECOMPLETE);
+ break;
+ case VL_DEVICEERROR_ALGOUNDERFLOW:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_ALGOUNDERFLOW);
+ break;
+ case VL_DEVICEERROR_ALGOOVERFLOW:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_ALGOOVERFLOW);
+ break;
+ case VL_DEVICEERROR_RANGEIGNORETHRESHOLD:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD);
+ break;
+
+ default:
+ VL_COPYSTRING(pDeviceErrorString,
+ VL_STRING_UNKNOWN_ERROR_CODE);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_range_status_string(uint8_t RangeStatus,
+ char *pRangeStatusString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (RangeStatus) {
+ case 0:
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_RANGEVALID);
+ break;
+ case 1:
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_SIGMA);
+ break;
+ case 2:
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_SIGNAL);
+ break;
+ case 3:
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_MINRANGE);
+ break;
+ case 4:
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_PHASE);
+ break;
+ case 5:
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_HW);
+ break;
+
+ default: /**/
+ VL_COPYSTRING(pRangeStatusString,
+ VL_STRING_RANGESTATUS_NONE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_pal_error_string(int8_t PalErrorCode,
+ char *pPalErrorString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (PalErrorCode) {
+ case VL_ERROR_NONE:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_NONE);
+ break;
+ case VL_ERROR_CALIBRATION_WARNING:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_CALIBRATION_WARNING);
+ break;
+ case VL_ERROR_MIN_CLIPPED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_MIN_CLIPPED);
+ break;
+ case VL_ERROR_UNDEFINED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_UNDEFINED);
+ break;
+ case VL_ERROR_INVALID_PARAMS:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_INVALID_PARAMS);
+ break;
+ case VL_ERROR_NOT_SUPPORTED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_NOT_SUPPORTED);
+ break;
+ case VL_ERROR_INTERRUPT_NOT_CLEARED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_INTERRUPT_NOT_CLEARED);
+ break;
+ case VL_ERROR_RANGE_ERROR:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_RANGE_ERROR);
+ break;
+ case VL_ERROR_TIME_OUT:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_TIME_OUT);
+ break;
+ case VL_ERROR_MODE_NOT_SUPPORTED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_MODE_NOT_SUPPORTED);
+ break;
+ case VL_ERROR_BUFFER_TOO_SMALL:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_BUFFER_TOO_SMALL);
+ break;
+ case VL_ERROR_GPIO_NOT_EXISTING:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_GPIO_NOT_EXISTING);
+ break;
+ case VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED);
+ break;
+ case VL_ERROR_CONTROL_INTERFACE:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_CONTROL_INTERFACE);
+ break;
+ case VL_ERROR_INVALID_COMMAND:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_INVALID_COMMAND);
+ break;
+ case VL_ERROR_DIVISION_BY_ZERO:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_DIVISION_BY_ZERO);
+ break;
+ case VL_ERROR_REF_SPAD_INIT:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_REF_SPAD_INIT);
+ break;
+ case VL_ERROR_NOT_IMPLEMENTED:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_ERROR_NOT_IMPLEMENTED);
+ break;
+
+ default:
+ VL_COPYSTRING(pPalErrorString,
+ VL_STRING_UNKNOWN_ERROR_CODE);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_pal_state_string(uint8_t PalStateCode,
+ char *pPalStateString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (PalStateCode) {
+ case VL_STATE_POWERDOWN:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_POWERDOWN);
+ break;
+ case VL_STATE_WAIT_STATICINIT:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_WAIT_STATICINIT);
+ break;
+ case VL_STATE_STANDBY:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_STANDBY);
+ break;
+ case VL_STATE_IDLE:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_IDLE);
+ break;
+ case VL_STATE_RUNNING:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_RUNNING);
+ break;
+ case VL_STATE_UNKNOWN:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_UNKNOWN);
+ break;
+ case VL_STATE_ERROR:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_ERROR);
+ break;
+
+ default:
+ VL_COPYSTRING(pPalStateString,
+ VL_STRING_STATE_UNKNOWN);
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
+
+int8_t VL_get_sequence_steps_info(
+ uint8_t SequenceStepId,
+ char *pSequenceStepsString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (SequenceStepId) {
+ case VL_SEQUENCESTEP_TCC:
+ VL_COPYSTRING(pSequenceStepsString,
+ VL_STRING_SEQUENCESTEP_TCC);
+ break;
+ case VL_SEQUENCESTEP_DSS:
+ VL_COPYSTRING(pSequenceStepsString,
+ VL_STRING_SEQUENCESTEP_DSS);
+ break;
+ case VL_SEQUENCESTEP_MSRC:
+ VL_COPYSTRING(pSequenceStepsString,
+ VL_STRING_SEQUENCESTEP_MSRC);
+ break;
+ case VL_SEQUENCESTEP_PRE_RANGE:
+ VL_COPYSTRING(pSequenceStepsString,
+ VL_STRING_SEQUENCESTEP_PRE_RANGE);
+ break;
+ case VL_SEQUENCESTEP_FINAL_RANGE:
+ VL_COPYSTRING(pSequenceStepsString,
+ VL_STRING_SEQUENCESTEP_FINAL_RANGE);
+ break;
+
+ default:
+ Status = VL_ERROR_INVALID_PARAMS;
+ }
+
+ LOG_FUNCTION_END(Status);
+
+ return Status;
+}
+
+
+int8_t VL_get_limit_check_info(struct vl_data *Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+
+ switch (LimitCheckId) {
+ case VL_CHECKENABLE_SIGMA_FINAL_RANGE:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE);
+ break;
+ case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE);
+ break;
+ case VL_CHECKENABLE_SIGNAL_REF_CLIP:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP);
+ break;
+ case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD);
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_MSRC:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC);
+ break;
+
+ case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE);
+ break;
+
+ default:
+ VL_COPYSTRING(pLimitCheckString,
+ VL_STRING_UNKNOWN_ERROR_CODE);
+
+ }
+
+ LOG_FUNCTION_END(Status);
+ return Status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c
new file mode 100644
index 0000000..edc4b5c
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c
@@ -0,0 +1,384 @@
+/*
+ * vl53l0x_i2c_platform.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/*!
+ * \file VL_platform.c
+ * \brief Code function definitions for EWOK Platform Layer
+ *
+ */
+
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+
+#include "vl53l0x_platform.h"
+#include "vl53l0x_i2c_platform.h"
+#include "vl53l0x_def.h"
+
+#include "vl53l0x_platform_log.h"
+
+#ifdef VL_LOG_ENABLE
+#define trace_print(level, ...) \
+ trace_print_module_function(TRACE_MODULE_PLATFORM, level,\
+ TRACE_FUNCTION_NONE, ##__VA_ARGS__)
+#define trace_i2c(...) \
+ trace_print_module_function(TRACE_MODULE_NONE, \
+ TRACE_LEVEL_NONE, TRACE_FUNCTION_I2C, ##__VA_ARGS__)
+#endif
+
+/**
+ * @def I2C_BUFFER_CONFIG
+ *
+ * @brief Configure Device register I2C access
+ *
+ * @li 0 : one GLOBAL buffer \n
+ * Use one global buffer of MAX_I2C_XFER_SIZE byte in data space \n
+ * This solution is not multi-Device compliant nor multi-thread cpu safe \n
+ * It can be the best option for small 8/16 bit MCU without stack and limited
+ * ram (STM8s, 80C51 ...)
+ *
+ * @li 1 : ON_STACK/local \n
+ * Use local variable (on stack) buffer \n
+ * This solution is multi-thread with use of i2c resource lock or mutex see
+ * VL6180x_GetI2CAccess() \n
+ *
+ * @li 2 : User defined \n
+ * Per Device potentially dynamic allocated. Requires VL6180x_GetI2cBuffer()
+ * to be implemented.
+ * @ingroup Configuration
+ */
+#define I2C_BUFFER_CONFIG 1
+
+#if I2C_BUFFER_CONFIG == 0
+ /* GLOBAL config buffer */
+ uint8_t i2c_global_buffer[VL_MAX_I2C_XFER_SIZE];
+
+ #define DECL_I2C_BUFFER
+ #define VL_GetLocalBuffer(Dev, n_byte) i2c_global_buffer
+
+#elif I2C_BUFFER_CONFIG == 1
+ /* ON STACK */
+ uint8_t LocBuffer[VL_MAX_I2C_XFER_SIZE];
+ #define VL_GetLocalBuffer(Dev, n_byte) LocBuffer
+#elif I2C_BUFFER_CONFIG == 2
+ /* user define buffer type declare DECL_I2C_BUFFER as access via */
+ /* VL_GetLocalBuffer */
+ #define DECL_I2C_BUFFER
+#else
+#error "invalid I2C_BUFFER_CONFIG "
+#endif
+
+
+#define VL_I2C_USER_VAR /* none but could be for a flag var to */
+ /* get/pass to mutex interruptible return flags and try again */
+#define VL_GetI2CAccess(Dev) /* todo mutex acquire */
+#define VL_DoneI2CAcces(Dev) /* todo mutex release */
+
+
+char debug_string[VL_MAX_STRING_LENGTH_PLT];
+
+
+#define MIN_COMMS_VERSION_MAJOR 1
+#define MIN_COMMS_VERSION_MINOR 8
+#define MIN_COMMS_VERSION_BUILD 1
+#define MIN_COMMS_VERSION_REVISION 0
+
+#define STATUS_OK 0x00
+#define STATUS_FAIL 0x01
+
+bool _check_min_version(void)
+{
+ bool min_version_comms_dll = false;
+
+ min_version_comms_dll = true;
+
+ return min_version_comms_dll;
+}
+
+int32_t VL_comms_initialise(uint8_t comms_type, uint16_t comms_speed_khz)
+{
+ int32_t status = STATUS_OK;
+
+ return status;
+}
+
+int32_t VL_comms_close(void)
+{
+ int32_t status = STATUS_OK;
+
+
+ return status;
+}
+
+int32_t VL_set_page(struct vl_data *dev, uint8_t page_data)
+{
+ int32_t status = STATUS_OK;
+ uint16_t page_index = 0xFF;
+ uint8_t *buffer;
+
+ buffer = VL_GetLocalBuffer(dev, 3);
+ buffer[0] = page_index >> 8;
+ buffer[1] = page_index & 0xff;
+ buffer[2] = page_data;
+
+ status = VL_I2CWrite(dev, buffer, (uint8_t) 3);
+ return status;
+}
+
+int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata,
+ int32_t count)
+{
+ int32_t status = STATUS_OK;
+ uint8_t *buffer;
+
+#ifdef VL_LOG_ENABLE
+ int32_t i = 0;
+ char value_as_str[VL_MAX_STRING_LENGTH_PLT];
+ char *pvalue_as_str;
+
+ pvalue_as_str = value_as_str;
+
+ for (i = 0 ; i < count ; i++) {
+ snprintf(pvalue_as_str, sizeof(pvalue_as_str),
+ "%02X", *(pdata + i));
+
+ pvalue_as_str += 2;
+ }
+ trace_i2c("Write reg : 0x%04X, Val : 0x%s\n", index, value_as_str);
+#endif
+ if ((count + 1) > VL_MAX_I2C_XFER_SIZE)
+ return STATUS_FAIL;
+ buffer = VL_GetLocalBuffer(dev, (count+1));
+ buffer[0] = index;
+ memcpy(&buffer[1], pdata, count);
+ status = VL_I2CWrite(dev, buffer, (count+1));
+
+ return status;
+}
+
+int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata,
+ int32_t count)
+{
+ int32_t status = STATUS_OK;
+ uint8_t *buffer;
+
+#ifdef VL_LOG_ENABLE
+ int32_t i = 0;
+ char value_as_str[VL_MAX_STRING_LENGTH_PLT];
+ char *pvalue_as_str;
+#endif
+
+ if ((count + 1) > VL_MAX_I2C_XFER_SIZE)
+ return STATUS_FAIL;
+
+ buffer = VL_GetLocalBuffer(dev, 1);
+ buffer[0] = index;
+ status = VL_I2CWrite(dev, (uint8_t *)buffer, (uint8_t)1);
+ if (!status) {
+ pdata[0] = index;
+ status = VL_I2CRead(dev, pdata, count);
+ }
+
+#ifdef VL_LOG_ENABLE
+ pvalue_as_str = value_as_str;
+
+ for (i = 0 ; i < count ; i++) {
+ snprintf(pvalue_as_str, sizeof(value_as_str),
+ "%02X", *(pdata+i));
+ pvalue_as_str += 2;
+ }
+
+ trace_i2c("Read reg : 0x%04X, Val : 0x%s\n", index, value_as_str);
+#endif
+
+ return status;
+}
+
+
+int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data)
+{
+ int32_t status = STATUS_OK;
+ const int32_t cbyte_count = 1;
+
+ status = VL_write_multi(dev, index, &data, cbyte_count);
+
+ return status;
+
+}
+
+
+int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data)
+{
+ int32_t status = STATUS_OK;
+
+ uint8_t buffer[BYTES_PER_WORD];
+
+ /* Split 16-bit word into MS and LS uint8_t */
+ buffer[0] = (uint8_t)(data >> 8);
+ buffer[1] = (uint8_t)(data & 0x00FF);
+
+ status = VL_write_multi(dev, index, buffer, BYTES_PER_WORD);
+
+ return status;
+
+}
+
+
+int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data)
+{
+ int32_t status = STATUS_OK;
+ uint8_t buffer[BYTES_PER_DWORD];
+
+ /* Split 32-bit word into MS ... LS bytes */
+ buffer[0] = (uint8_t) (data >> 24);
+ buffer[1] = (uint8_t)((data & 0x00FF0000) >> 16);
+ buffer[2] = (uint8_t)((data & 0x0000FF00) >> 8);
+ buffer[3] = (uint8_t) (data & 0x000000FF);
+
+ status = VL_write_multi(dev, index, buffer, BYTES_PER_DWORD);
+
+ return status;
+
+}
+
+
+int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata)
+{
+ int32_t status = STATUS_OK;
+ int32_t cbyte_count = 1;
+
+ status = VL_read_multi(dev, index, pdata, cbyte_count);
+
+ return status;
+
+}
+
+
+int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata)
+{
+ int32_t status = STATUS_OK;
+ uint8_t buffer[BYTES_PER_WORD];
+
+ status = VL_read_multi(dev, index, buffer, BYTES_PER_WORD);
+ *pdata = ((uint16_t)buffer[0]<<8) + (uint16_t)buffer[1];
+
+ return status;
+
+}
+
+int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata)
+{
+ int32_t status = STATUS_OK;
+ uint8_t buffer[BYTES_PER_DWORD];
+
+ status = VL_read_multi(dev, index, buffer, BYTES_PER_DWORD);
+ *pdata = ((uint32_t)buffer[0]<<24) + ((uint32_t)buffer[1]<<16) +
+ ((uint32_t)buffer[2]<<8) + (uint32_t)buffer[3];
+
+ return status;
+
+}
+
+int32_t VL_platform_wait_us(int32_t wait_us)
+{
+ int32_t status = STATUS_OK;
+
+ msleep((wait_us/1000));
+
+#ifdef VL_LOG_ENABLE
+ trace_i2c("Wait us : %6d\n", wait_us);
+#endif
+
+ return status;
+
+}
+
+
+int32_t VL_wait_ms(int32_t wait_ms)
+{
+ int32_t status = STATUS_OK;
+
+ msleep(wait_ms);
+
+#ifdef VL_LOG_ENABLE
+ trace_i2c("Wait ms : %6d\n", wait_ms);
+#endif
+
+ return status;
+
+}
+
+
+int32_t VL_set_gpio(uint8_t level)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+ trace_i2c("// Set GPIO = %d;\n", level);
+#endif
+
+ return status;
+
+}
+
+
+int32_t VL_get_gpio(uint8_t *plevel)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+ trace_i2c("// Get GPIO = %d;\n", *plevel);
+#endif
+ return status;
+}
+
+
+int32_t VL_release_gpio(void)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+ trace_i2c("// Releasing force on GPIO\n");
+#endif
+ return status;
+
+}
+
+int32_t VL_cycle_power(void)
+{
+ int32_t status = STATUS_OK;
+#ifdef VL_LOG_ENABLE
+ trace_i2c("// cycle sensor power\n");
+#endif
+
+ return status;
+}
+
+
+int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz)
+{
+ *ptimer_freq_hz = 0;
+ return STATUS_FAIL;
+}
+
+
+int32_t VL_get_timer_value(int32_t *ptimer_count)
+{
+ *ptimer_count = 0;
+ return STATUS_FAIL;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c
new file mode 100644
index 0000000..79df3db
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c
@@ -0,0 +1,232 @@
+/*
+ * vl53l0x_platform.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/**
+ * @file VL_i2c.c
+ *
+ * Copyright (C) 2014 ST MicroElectronics
+ *
+ * provide variable word size byte/Word/dword VL6180x register access via i2c
+ *
+ */
+#include "vl53l0x_platform.h"
+#include "vl53l0x_i2c_platform.h"
+#include "vl53l0x_api.h"
+
+#define LOG_FUNCTION_START(fmt, ...) \
+ _LOG_FUNCTION_START(TRACE_MODULE_PLATFORM, fmt, ##__VA_ARGS__)
+#define LOG_FUNCTION_END(status, ...) \
+ _LOG_FUNCTION_END(TRACE_MODULE_PLATFORM, status, ##__VA_ARGS__)
+#define LOG_FUNCTION_END_FMT(status, fmt, ...)\
+ _LOG_FUNCTION_END_FMT(TRACE_MODULE_PLATFORM, status,\
+ fmt, ##__VA_ARGS__)
+
+
+
+int8_t VL_LockSequenceAccess(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ return Status;
+}
+
+int8_t VL_UnlockSequenceAccess(struct vl_data *Dev)
+{
+ int8_t Status = VL_ERROR_NONE;
+
+ return Status;
+}
+
+/* the ranging_sensor_comms.dll will take care of the page selection */
+int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count)
+{
+
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int = 0;
+ uint8_t deviceAddress;
+
+ if (count >= VL_MAX_I2C_XFER_SIZE)
+ Status = VL_ERROR_INVALID_PARAMS;
+
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_write_multi(Dev, index, pdata, count);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+/* the ranging_sensor_comms.dll will take care of the page selection */
+int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index,
+ uint8_t *pdata, uint32_t count)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ if (count >= VL_MAX_I2C_XFER_SIZE)
+ Status = VL_ERROR_INVALID_PARAMS;
+
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_read_multi(Dev, index, pdata, count);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+
+int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_write_byte(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_write_word(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_write_dword(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index,
+ uint8_t AndData, uint8_t OrData)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+ uint8_t data;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_read_byte(Dev, index, &data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ if (Status == VL_ERROR_NONE) {
+ data = (data & AndData) | OrData;
+ status_int = VL_write_byte(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+ }
+
+ return Status;
+}
+
+int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_read_byte(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_read_word(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data)
+{
+ int8_t Status = VL_ERROR_NONE;
+ int32_t status_int;
+ uint8_t deviceAddress;
+
+ deviceAddress = Dev->I2cDevAddr;
+
+ status_int = VL_read_dword(Dev, index, data);
+
+ if (status_int != 0)
+ Status = VL_ERROR_CONTROL_INTERFACE;
+
+ return Status;
+}
+
+#define VL_POLLINGDELAY_LOOPNB 250
+int8_t VL_PollingDelay(struct vl_data *Dev)
+{
+ int8_t status = VL_ERROR_NONE;
+
+ LOG_FUNCTION_START("");
+ usleep_range(1000, 1001);
+ LOG_FUNCTION_END(status);
+ return status;
+}
diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c
new file mode 100644
index 0000000..9e14f79
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c
@@ -0,0 +1,168 @@
+/*
+ * vl53l0x_port_i2c.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+#include "vl53l0x_platform.h"
+#include "vl53l0x_i2c_platform.h"
+#include "stmvl53l0x.h"
+
+#define I2C_M_WR 0x00
+#define STATUS_OK 0x00
+#define STATUS_FAIL (-1)
+/** int VL_I2CWrite(VL_Dev_t dev, void *buff, uint8_t len);
+ * @brief Write data buffer to VL53L0 device via i2c
+ * @param dev The device to write to
+ * @param buff The data buffer
+ * @param len The length of the transaction in byte
+ * @return 0 on success
+ */
+int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len)
+{
+
+
+ int err = 0;
+
+ if (dev->bus_type == CCI_BUS) {
+#ifdef CAMERA_CCI
+ uint16_t index;
+ struct cci_data *cci_client_obj =
+ (struct cci_data *)dev->client_object;
+ struct msm_camera_i2c_client *client = cci_client_obj->client;
+
+ index = buff[0];
+ /*dbg("%s: index: %d len: %d\n", __func__, index, len); */
+
+ if (len == 2) {
+ uint8_t data;
+
+ data = buff[1];
+ /* for byte access */
+ err = client->i2c_func_tbl->i2c_write(client, index,
+ data, MSM_CAMERA_I2C_BYTE_DATA);
+ if (err < 0) {
+ dbg("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+ } else if (len == 3) {
+ uint16_t data;
+
+ data = ((uint16_t)buff[1] << 8) | (uint16_t)buff[2];
+ err = client->i2c_func_tbl->i2c_write(client, index,
+ data, MSM_CAMERA_I2C_WORD_DATA);
+ if (err < 0) {
+ dbg("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+ } else if (len >= 5) {
+ err = client->i2c_func_tbl->i2c_write_seq(client,
+ index, &buff[1], (len-1));
+ if (err < 0) {
+ dbg("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+
+ }
+#endif
+#ifndef CAMERA_CCI
+ } else {
+ struct i2c_msg msg[1];
+ struct i2c_data *i2c_client_obj =
+ (struct i2c_data *)dev->client_object;
+ struct i2c_client *client =
+ (struct i2c_client *)i2c_client_obj->client;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = I2C_M_WR;
+ msg[0].buf = buff;
+ msg[0].len = len;
+
+ err = i2c_transfer(client->adapter, msg, 1);
+ /* return the actual messages transfer */
+ if (err != 1) {
+ dbg("%s: i2c_transfer err:%d, addr:0x%x, reg:0x%x\n",
+ __func__, err, client->addr,
+ (buff[0] << 8 | buff[1]));
+ return STATUS_FAIL;
+ }
+#endif
+ }
+
+ return 0;
+}
+
+
+/** int VL_I2CRead(VL_Dev_t dev, void *buff, uint8_t len);
+ * @brief Read data buffer from VL53L0 device via i2c
+ * @param dev The device to read from
+ * @param buff The data buffer to fill
+ * @param len The length of the transaction in byte
+ * @return transaction status
+ */
+int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len)
+{
+
+ int err = 0;
+
+ if (dev->bus_type == CCI_BUS) {
+#ifdef CAMERA_CCI
+ uint16_t index;
+ struct cci_data *cci_client_obj =
+ (struct cci_data *)dev->client_object;
+ struct msm_camera_i2c_client *client = cci_client_obj->client;
+
+ index = buff[0];
+ /* dbg("%s: index: %d\n", __func__, index); */
+ err = client->i2c_func_tbl->i2c_read_seq(client,
+ index, buff, len);
+ if (err < 0) {
+ dbg("%s:%d failed status=%d\n",
+ __func__, __LINE__, err);
+ return err;
+ }
+#endif
+ } else {
+#ifndef CAMERA_CCI
+ struct i2c_msg msg[1];
+ struct i2c_data *i2c_client_obj =
+ (struct i2c_data *)dev->client_object;
+ struct i2c_client *client =
+ (struct i2c_client *) i2c_client_obj->client;
+
+ msg[0].addr = client->addr;
+ msg[0].flags = I2C_M_RD|client->flags;
+ msg[0].buf = buff;
+ msg[0].len = len;
+
+ err = i2c_transfer(client->adapter, &msg[0], 1);
+ /* return the actual message transfer */
+ if (err != 1) {
+ dbg("%s: Read i2c_transfer err:%d, addr:0x%x\n",
+ __func__, err, client->addr);
+ return STATUS_FAIL;
+ }
+#endif
+ }
+
+ return 0;
+}
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h
new file mode 100644
index 0000000..5476ef9
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h
@@ -0,0 +1,57 @@
+/*
+ * stmvl53l0x-cci.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef STMVL_CCI_H
+#define STMVL_CCI_H
+#include <linux/types.h>
+
+#ifdef CAMERA_CCI
+#include <soc/qcom/camera2.h>
+#include "msm_camera_i2c.h"
+#include "msm_camera_dt_util.h"
+#include "msm_camera_io_util.h"
+#include "msm_cci.h"
+
+#define MSM_TOF_MAX_VREGS (10)
+
+struct msm_tof_vreg {
+ struct camera_vreg_t *cam_vreg;
+ void *data[MSM_TOF_MAX_VREGS];
+ int num_vreg;
+};
+
+struct cci_data {
+ struct msm_camera_i2c_client g_client;
+ struct msm_camera_i2c_client *client;
+ struct platform_device *pdev;
+ enum msm_camera_device_type_t device_type;
+ enum cci_i2c_master_t cci_master;
+ struct msm_tof_vreg vreg_cfg;
+ struct msm_sd_subdev msm_sd;
+ struct v4l2_subdev sdev;
+ struct v4l2_subdev_ops *subdev_ops;
+ char subdev_initialized;
+ uint32_t subdev_id;
+ uint8_t power_up;
+};
+int stmvl53l0x_init_cci(void);
+void stmvl53l0x_exit_cci(void *cci_object);
+int stmvl53l0x_power_down_cci(void *cci_object);
+int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag);
+#endif /* CAMERA_CCI */
+#endif /* STMVL_CCI_H */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h
new file mode 100644
index 0000000..68f7d37
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h
@@ -0,0 +1,35 @@
+/*
+ * stmvl53l0x-i2c.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef STMVL_I2C_H
+#define STMVL_I2C_H
+#include <linux/types.h>
+
+#ifndef CAMERA_CCI
+struct i2c_data {
+ struct i2c_client *client;
+ struct regulator *vana;
+ uint8_t power_up;
+};
+int stmvl53l0x_init_i2c(void);
+void stmvl53l0x_exit_i2c(void *i2c_object);
+int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag);
+int stmvl53l0x_power_down_i2c(void *i2c_object);
+
+#endif /* NOT CAMERA_CCI */
+#endif /* STMVL_I2C_H */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x.h b/drivers/input/misc/vl53l0x/stmvl53l0x.h
new file mode 100644
index 0000000..1f15278
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x.h
@@ -0,0 +1,186 @@
+/*
+ * stmvl53l0x.h - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef STMVL_H
+#define STMVL_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/miscdevice.h>
+#include <linux/wait.h>
+
+
+#define STMVL_DRV_NAME "stmvl53l0"
+#define STMVL_SLAVE_ADDR (0x52>>1)
+
+#define DRIVER_VERSION "1.0.5"
+#define I2C_M_WR 0x00
+/* #define INT_POLLING_DELAY 20 */
+
+/* if don't want to have output from dbg, comment out #DEBUG macro */
+#ifdef DEBUG
+#define dbg(fmt, ...) \
+ printk(fmt, ##__VA_ARGS__)
+#else
+#define dbg(fmt, ...)
+#endif
+
+#define err(fmt, ...) \
+ printk(fmt, ##__VA_ARGS__)
+
+#define VL_VDD_MIN 2600000
+#define VL_VDD_MAX 3000000
+
+enum init_mode_e {
+ NORMAL_MODE = 0,
+ OFFSETCALIB_MODE = 1,
+ XTALKCALIB_MODE = 2,
+};
+
+enum parameter_name_e {
+ OFFSET_PAR = 0,
+ XTALKRATE_PAR = 1,
+ XTALKENABLE_PAR = 2,
+ GPIOFUNC_PAR = 3,
+ LOWTHRESH_PAR = 4,
+ HIGHTHRESH_PAR = 5,
+ DEVICEMODE_PAR = 6,
+ INTERMEASUREMENT_PAR = 7,
+ REFERENCESPADS_PAR = 8,
+ REFCALIBRATION_PAR = 9,
+};
+
+enum {
+ CCI_BUS = 0,
+ I2C_BUS = 1,
+};
+
+/*
+ * IOCTL register data structs
+ */
+struct stmvl53l0x_register {
+ uint32_t is_read; /*1: read 0: write*/
+ uint32_t reg_index;
+ uint32_t reg_bytes;
+ uint32_t reg_data;
+ int32_t status;
+};
+
+/*
+ * IOCTL parameter structs
+ */
+struct stmvl53l0x_parameter {
+ uint32_t is_read; /*1: Get 0: Set*/
+ enum parameter_name_e name;
+ int32_t value;
+ int32_t value2;
+ int32_t status;
+};
+
+/*
+ * driver data structs
+ */
+struct vl_data {
+
+ struct VL_DevData_t Data; /* !<embed ST VL53L0 Dev data as "dev_data" */
+ uint8_t I2cDevAddr; /* !< i2c device address user specific field */
+ uint8_t comms_type; /* !< Type of comms : */
+ /* VL_COMMS_I2C or VL_COMMS_SPI */
+ uint16_t comms_speed_khz; /*!< Comms speed [kHz] : */
+ /*typically 400kHz for I2C */
+ uint8_t bus_type; /* CCI_BUS; I2C_BUS */
+
+ void *client_object; /* cci or i2c client */
+
+ struct mutex update_lock;
+ struct delayed_work dwork; /* for PS work handler */
+ struct input_dev *input_dev_ps;
+ struct kobject *range_kobj;
+
+ const char *dev_name;
+ /* function pointer */
+
+ /* misc device */
+ struct miscdevice miscdev;
+
+ int irq;
+ unsigned int reset;
+
+ /* control flag from HAL */
+ unsigned int enable_ps_sensor;
+
+ /* PS parameters */
+ unsigned int ps_data; /* to store PS data */
+
+ /* Calibration parameters */
+ unsigned int offsetCalDistance;
+ unsigned int xtalkCalDistance;
+
+
+ /* Range Data */
+ struct VL_RangingMeasurementData_t rangeData;
+
+ /* Device parameters */
+ uint8_t deviceMode;
+ uint32_t interMeasurems;
+ uint8_t gpio_function;
+ uint8_t gpio_polarity;
+ unsigned int low_threshold;
+ unsigned int high_threshold;
+
+ /* delay time in miniseconds*/
+ uint8_t delay_ms;
+
+ /* Timing Budget */
+ uint32_t timingBudget;
+ /* Use this threshold to force restart ranging */
+ uint32_t noInterruptCount;
+ /* Use this flag to use long ranging*/
+ int useLongRange;
+
+ /* Polling thread */
+ struct task_struct *poll_thread;
+ /* Wait Queue on which the poll thread blocks */
+ wait_queue_head_t poll_thread_wq;
+
+ /* Recent interrupt status */
+ uint32_t interruptStatus;
+
+ struct mutex work_mutex;
+
+ /* Debug */
+ unsigned int enableDebug;
+ uint8_t interrupt_received;
+};
+
+/*
+ * function pointer structs
+ */
+struct stmvl53l0x_module_fn_t {
+ int (*init)(void);
+ void (*deinit)(void *);
+ int (*power_up)(void *, unsigned int *);
+ int (*power_down)(void *);
+};
+
+
+
+int stmvl53l0x_setup(struct vl_data *data);
+
+#endif /* STMVL_H */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c
new file mode 100644
index 0000000..39b802f
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c
@@ -0,0 +1,411 @@
+/*
+ * stmvl53l0x_module-cci.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+/*
+ * power specific includes
+ */
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/clk.h>
+#include <linux/of_gpio.h>
+/*
+ * API includes
+ */
+#include "vl53l0x_api.h"
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+#include "stmvl53l0x-cci.h"
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x.h"
+
+#ifdef CAMERA_CCI
+/*
+ * Global data
+ */
+static struct v4l2_file_operations msm_tof_v4l2_subdev_fops;
+static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = {
+ .i2c_read = msm_camera_cci_i2c_read,
+ .i2c_read_seq = msm_camera_cci_i2c_read_seq,
+ .i2c_write = msm_camera_cci_i2c_write,
+ .i2c_write_seq = msm_camera_cci_i2c_write_seq,
+ .i2c_write_table = msm_camera_cci_i2c_write_table,
+ .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table,
+ .i2c_write_table_w_microdelay =
+ msm_camera_cci_i2c_write_table_w_microdelay,
+ .i2c_util = msm_sensor_cci_i2c_util,
+ .i2c_poll = msm_camera_cci_i2c_poll,
+};
+static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data);
+
+/*
+ * QCOM specific functions
+ */
+static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data)
+{
+ int rc = 0;
+
+ dbg("Enter\n");
+
+ if (dev->of_node) {
+ struct device_node *of_node = dev->of_node;
+ struct msm_tof_vreg *vreg_cfg;
+
+ if (!of_node) {
+ err("failed %d\n", __LINE__);
+ return -EINVAL;
+ }
+
+ rc = of_property_read_u32(of_node,
+ "cell-index", &data->pdev->id);
+ if (rc < 0) {
+ err("failed %d\n", __LINE__);
+ return rc;
+ }
+ dbg("cell-index: %d\n", data->pdev->id);
+ rc = of_property_read_u32(of_node, "qcom,cci-master",
+ &data->cci_master);
+ if (rc < 0) {
+ err("failed %d\n", __LINE__);
+ /* Set default master 0 */
+ data->cci_master = MASTER_0;
+ rc = 0;
+ }
+ dbg("cci_master: %d\n", data->cci_master);
+ if (of_find_property(of_node, "qcom,cam-vreg-name", NULL)) {
+ vreg_cfg = &data->vreg_cfg;
+ rc = msm_camera_get_dt_vreg_data(of_node,
+ &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg);
+ if (rc < 0) {
+ err("failed %d\n", __LINE__);
+ return rc;
+ }
+ }
+ dbg("vreg-name: %s min_volt: %d max_volt: %d",
+ vreg_cfg->cam_vreg->reg_name,
+ vreg_cfg->cam_vreg->min_voltage,
+ vreg_cfg->cam_vreg->max_voltage);
+ }
+ dbg("End rc =%d\n", rc);
+
+ return rc;
+}
+
+static int32_t stmvl53l0x_vreg_control(struct cci_data *data, int config)
+{
+ int rc = 0, i, cnt;
+ struct msm_tof_vreg *vreg_cfg;
+
+ dbg("Enter\n");
+
+ vreg_cfg = &data->vreg_cfg;
+ cnt = vreg_cfg->num_vreg;
+ dbg("num_vreg: %d\n", cnt);
+ if (!cnt) {
+ err("failed %d\n", __LINE__);
+ return 0;
+ }
+
+ if (cnt >= MSM_TOF_MAX_VREGS) {
+ err("failed %d cnt %d\n", __LINE__, cnt);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ rc = msm_camera_config_single_vreg(&(data->pdev->dev),
+ &vreg_cfg->cam_vreg[i],
+ (struct regulator **)&vreg_cfg->data[i],
+ config);
+ }
+
+ dbg("EXIT rc =%d\n", rc);
+ return rc;
+}
+
+
+static int msm_tof_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+ return 0;
+}
+
+
+static const struct v4l2_subdev_internal_ops msm_tof_internal_ops = {
+ .close = msm_tof_close,
+};
+
+static long msm_tof_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int cmd, void *arg)
+{
+ dbg("Subdev_ioctl not handled\n");
+ return 0;
+}
+
+static int32_t msm_tof_power(struct v4l2_subdev *sd, int on)
+{
+ dbg("TOF power called\n");
+ return 0;
+}
+
+static struct v4l2_subdev_core_ops msm_tof_subdev_core_ops = {
+ .ioctl = msm_tof_subdev_ioctl,
+ .s_power = msm_tof_power,
+};
+
+static struct v4l2_subdev_ops msm_tof_subdev_ops = {
+ .core = &msm_tof_subdev_core_ops,
+};
+
+static int stmvl53l0x_cci_init(struct cci_data *data)
+{
+ int rc = 0;
+ struct msm_camera_cci_client *cci_client = data->client->cci_client;
+
+ if (data->subdev_initialized == FALSE) {
+ data->client->i2c_func_tbl = &msm_sensor_cci_func_tbl;
+ data->client->cci_client =
+ kzalloc(sizeof(struct msm_camera_cci_client),
+ GFP_KERNEL);
+ if (!data->client->cci_client) {
+ err("%d, failed no memory\n", __LINE__);
+ return -ENOMEM;
+ }
+ cci_client = data->client->cci_client;
+ cci_client->cci_subdev = msm_cci_get_subdev();
+ cci_client->cci_i2c_master = data->cci_master;
+ v4l2_subdev_init(&data->msm_sd.sd, data->subdev_ops);
+ v4l2_set_subdevdata(&data->msm_sd.sd, data);
+ data->msm_sd.sd.internal_ops = &msm_tof_internal_ops;
+ data->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ snprintf(data->msm_sd.sd.name, ARRAY_SIZE(data->msm_sd.sd.name),
+ "msm_tof");
+ media_entity_init(&data->msm_sd.sd.entity, 0, NULL, 0);
+ data->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+ data->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_TOF;
+ data->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2;
+ msm_sd_register(&data->msm_sd);
+ msm_tof_v4l2_subdev_fops = v4l2_subdev_fops;
+ data->msm_sd.sd.devnode->fops = &msm_tof_v4l2_subdev_fops;
+ data->subdev_initialized = TRUE;
+ }
+
+ cci_client->sid = 0x29;
+ cci_client->retries = 3;
+ cci_client->id_map = 0;
+ cci_client->cci_i2c_master = data->cci_master;
+ rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT);
+ if (rc < 0) {
+ err("%d: CCI Init failed\n", __LINE__);
+ return rc;
+ }
+ dbg("CCI Init Succeeded\n");
+
+ data->client->addr_type = MSM_CAMERA_I2C_BYTE_ADDR;
+
+ return 0;
+}
+
+static int32_t stmvl53l0x_platform_probe(struct platform_device *pdev)
+{
+ struct vl_data *vl53l0x_data = NULL;
+ struct cci_data *cci_object = NULL;
+ int32_t rc = 0;
+
+ dbg("Enter\n");
+
+ if (!pdev->dev.of_node) {
+ err("of_node NULL\n");
+ return -EINVAL;
+ }
+
+ vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL);
+ if (!vl53l0x_data) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ if (vl53l0x_data) {
+ vl53l0x_data->client_object =
+ kzalloc(sizeof(struct cci_data), GFP_KERNEL);
+ cci_object = (struct cci_data *)vl53l0x_data->client_object;
+ }
+ cci_object->client =
+ (struct msm_camera_i2c_client *)&cci_object->g_client;
+
+ /* setup bus type */
+ vl53l0x_data->bus_type = CCI_BUS;
+
+ /* Set platform device handle */
+ cci_object->subdev_ops = &msm_tof_subdev_ops;
+ cci_object->pdev = pdev;
+ rc = stmvl53l0x_get_dt_data(&pdev->dev, cci_object);
+ if (rc < 0) {
+ err("%d, failed rc %d\n", __LINE__, rc);
+ return rc;
+ }
+ cci_object->subdev_id = pdev->id;
+
+ /* Set device type as platform device */
+ cci_object->device_type = MSM_CAMERA_PLATFORM_DEVICE;
+ cci_object->subdev_initialized = FALSE;
+
+ /* setup device name */
+ vl53l0x_data->dev_name = dev_name(&pdev->dev);
+
+ /* setup device data */
+ dev_set_drvdata(&pdev->dev, vl53l0x_data);
+
+ /* setup other stuff */
+ rc = stmvl53l0x_setup(vl53l0x_data);
+
+ /* init default value */
+ cci_object->power_up = 0;
+
+ dbg("End\n");
+
+ return rc;
+
+}
+
+static int32_t stmvl53l0x_platform_remove(struct platform_device *pdev)
+{
+ struct vl_data *vl53l0x_data = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(vl53l0x_data->client_object);
+ kfree(vl53l0x_data);
+
+ return 0;
+}
+
+static const struct of_device_id st_stmvl53l0x_dt_match[] = {
+ { .compatible = "st,stmvl53l0", },
+ { },
+};
+
+static struct platform_driver stmvl53l0x_platform_driver = {
+ .probe = stmvl53l0x_platform_probe,
+ .remove = stmvl53l0x_platform_remove,
+ .driver = {
+ .name = STMVL_DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = st_stmvl53l0x_dt_match,
+ },
+};
+
+int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag)
+{
+ int ret = 0;
+ struct cci_data *data = (struct cci_data *)cci_object;
+
+ dbg("Enter");
+
+ /* need to init cci first */
+ ret = stmvl53l0x_cci_init(data);
+ if (ret) {
+ err("stmvl53l0x_cci_init failed %d\n", __LINE__);
+ return ret;
+ }
+ /* actual power up */
+ if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+ ret = stmvl53l0x_vreg_control(data, 1);
+ if (ret < 0) {
+ err("stmvl53l0x_vreg_control failed %d\n",
+ __LINE__);
+ return ret;
+ }
+ }
+ data->power_up = 1;
+ *preset_flag = 1;
+ dbg("End\n");
+
+ return ret;
+}
+
+int stmvl53l0x_power_down_cci(void *cci_object)
+{
+ int ret = 0;
+ struct cci_data *data = (struct cci_data *)cci_object;
+
+ dbg("Enter\n");
+ if (data->power_up) {
+ /* need to release cci first */
+ ret = data->client->i2c_func_tbl->i2c_util(data->client,
+ MSM_CCI_RELEASE);
+ if (ret < 0)
+ err("CCI Release failed rc %d\n", ret);
+
+ /* actual power down */
+ if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) {
+ ret = stmvl53l0x_vreg_control(data, 0);
+ if (ret < 0) {
+ err(
+ "stmvl53l0x_vreg_control failed %d\n",
+ __LINE__);
+ return ret;
+ }
+ }
+ }
+ data->power_up = 0;
+ dbg("End\n");
+ return ret;
+}
+
+int stmvl53l0x_init_cci(void)
+{
+ int ret = 0;
+
+ dbg("Enter\n");
+
+ /* register as a platform device */
+ ret = platform_driver_register(&stmvl53l0x_platform_driver);
+ if (ret)
+ err("%d, error ret:%d\n", __LINE__, ret);
+
+ dbg("End\n");
+
+ return ret;
+}
+
+void stmvl53l0x_exit_cci(void *cci_object)
+{
+ struct cci_data *data = (struct cci_data *)cci_object;
+
+ dbg("Enter\n");
+
+ if (data && data->client->cci_client)
+ kfree(data->client->cci_client);
+
+ dbg("End\n");
+}
+#endif /* end of CAMERA_CCI */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c
new file mode 100644
index 0000000..7e0cc15
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c
@@ -0,0 +1,246 @@
+/*
+ * stmvl53l0x_module-i2c.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+/*
+ * power specific includes
+ */
+#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/clk.h>
+#include <linux/of_gpio.h>
+/*
+ * API includes
+ */
+#include "vl53l0x_api.h"
+#include "vl53l0x_def.h"
+#include "vl53l0x_platform.h"
+#include "stmvl53l0x-i2c.h"
+#include "stmvl53l0x-cci.h"
+#include "stmvl53l0x.h"
+#ifndef CAMERA_CCI
+
+/*
+ * Global data
+ */
+static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data);
+
+/*
+ * QCOM specific functions
+ */
+static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data)
+{
+ int ret = 0;
+
+ dbg("Enter\n");
+
+ if (dev->of_node) {
+ data->vana = regulator_get(dev, "vdd");
+ if (IS_ERR(data->vana)) {
+ err("vdd supply is not provided\n");
+ ret = -1;
+ }
+ }
+ dbg("End\n");
+
+ return ret;
+}
+
+static int stmvl53l0x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc = 0;
+ struct vl_data *vl53l0x_data = NULL;
+ struct i2c_data *i2c_object = NULL;
+
+ dbg("Enter\n");
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
+ rc = -EIO;
+ return rc;
+ }
+
+ vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL);
+ if (!vl53l0x_data) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ if (vl53l0x_data) {
+ vl53l0x_data->client_object =
+ kzalloc(sizeof(struct i2c_data), GFP_KERNEL);
+ i2c_object = (struct i2c_data *)vl53l0x_data->client_object;
+ }
+ i2c_object->client = client;
+
+ /* setup bus type */
+ vl53l0x_data->bus_type = I2C_BUS;
+
+ /* setup regulator */
+ stmvl53l0x_parse_vdd(&i2c_object->client->dev, i2c_object);
+
+ /* setup device name */
+ vl53l0x_data->dev_name = dev_name(&client->dev);
+
+ /* setup device data */
+ dev_set_drvdata(&client->dev, vl53l0x_data);
+
+ /* setup client data */
+ i2c_set_clientdata(client, vl53l0x_data);
+
+ /* setup other stuff */
+ rc = stmvl53l0x_setup(vl53l0x_data);
+
+ /* init default value */
+ i2c_object->power_up = 0;
+
+ dbg("End\n");
+ return rc;
+}
+
+static int stmvl53l0x_remove(struct i2c_client *client)
+{
+ struct vl_data *data = i2c_get_clientdata(client);
+
+ dbg("Enter\n");
+
+ /* Power down the device */
+ stmvl53l0x_power_down_i2c(data->client_object);
+ kfree(data->client_object);
+ kfree(data);
+ dbg("End\n");
+ return 0;
+}
+
+static const struct i2c_device_id stmvl53l0x_id[] = {
+ { STMVL_DRV_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, stmvl53l0x_id);
+
+static const struct of_device_id st_stmvl53l0x_dt_match[] = {
+ { .compatible = "st,stmvl53l0", },
+ { },
+};
+
+static struct i2c_driver stmvl53l0x_driver = {
+ .driver = {
+ .name = STMVL_DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = st_stmvl53l0x_dt_match,
+ },
+ .probe = stmvl53l0x_probe,
+ .remove = stmvl53l0x_remove,
+ .id_table = stmvl53l0x_id,
+
+};
+
+int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag)
+{
+ int ret = 0;
+#ifndef STM_TEST
+ struct i2c_data *data = (struct i2c_data *)i2c_object;
+#endif
+
+ dbg("Enter\n");
+
+ /* actual power on */
+#ifndef STM_TEST
+ ret = regulator_set_voltage(data->vana,
+ VL_VDD_MIN, VL_VDD_MAX);
+ if (ret < 0) {
+ err("set_vol(%p) fail %d\n", data->vana, ret);
+ return ret;
+ }
+ ret = regulator_enable(data->vana);
+ usleep_range(3000, 3001);
+ if (ret < 0) {
+ err("reg enable(%p) failed.rc=%d\n",
+ data->vana, ret);
+ return ret;
+ }
+ data->power_up = 1;
+ *preset_flag = 1;
+#endif
+
+ dbg("End\n");
+ return ret;
+}
+
+int stmvl53l0x_power_down_i2c(void *i2c_object)
+{
+ int ret = 0;
+#ifndef STM_TEST
+ struct i2c_data *data = (struct i2c_data *)i2c_object;
+#endif
+
+ dbg("Enter\n");
+#ifndef STM_TEST
+ msleep(30);
+ ret = regulator_disable(data->vana);
+ if (ret < 0)
+ err("reg disable(%p) failed.rc=%d\n",
+ data->vana, ret);
+
+ data->power_up = 0;
+#endif
+
+ dbg("End\n");
+ return ret;
+}
+
+int stmvl53l0x_init_i2c(void)
+{
+ int ret = 0;
+
+ dbg("Enter\n");
+
+ /* register as a i2c client device */
+ ret = i2c_add_driver(&stmvl53l0x_driver);
+ if (ret)
+ err("%d erro ret:%d\n", __LINE__, ret);
+
+ dbg("End with rc:%d\n", ret);
+
+ return ret;
+}
+
+void stmvl53l0x_exit_i2c(void *i2c_object)
+{
+ dbg("Enter\n");
+ i2c_del_driver(&stmvl53l0x_driver);
+
+ dbg("End\n");
+}
+
+#endif /* end of NOT CAMERA_CCI */
diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
new file mode 100644
index 0000000..ece245f
--- /dev/null
+++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c
@@ -0,0 +1,1893 @@
+/*
+ * stmvl53l0x_module.c - Linux kernel modules for
+ * STM VL53L0 FlightSense TOF sensor
+ *
+ * Copyright (C) 2016 STMicroelectronics Imaging Division.
+ * 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 as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/input.h>
+#include <linux/miscdevice.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/kthread.h>
+/*
+ * API includes
+ */
+#include "vl53l0x_api.h"
+
+#define IRQ_NUM 59
+#ifdef DEBUG_TIME_LOG
+struct timeval start_tv, stop_tv;
+#endif
+
+/*
+ * Global data
+ */
+
+#ifdef CAMERA_CCI
+static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = {
+ .init = stmvl53l0x_init_cci,
+ .deinit = stmvl53l0x_exit_cci,
+ .power_up = stmvl53l0x_power_up_cci,
+ .power_down = stmvl53l0x_power_down_cci,
+};
+#else
+static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = {
+ .init = stmvl53l0x_init_i2c,
+ .deinit = stmvl53l0x_exit_i2c,
+ .power_up = stmvl53l0x_power_up_i2c,
+ .power_down = stmvl53l0x_power_down_i2c,
+};
+#endif
+struct stmvl53l0x_module_fn_t *pmodule_func_tbl;
+struct stmvl53l0x_api_fn_t {
+ int8_t (*GetVersion)(struct VL_Version_t *pVersion);
+ int8_t (*GetPalSpecVersion)(struct VL_Version_t *pPalSpecVersion);
+
+ int8_t (*GetProductRevision)(struct vl_data *Dev,
+ uint8_t *pProductRevisionMajor,
+ uint8_t *pProductRevisionMinor);
+ int8_t (*GetDeviceInfo)(struct vl_data *Dev,
+ struct VL_DeviceInfo_t *pVL_DeviceInfo);
+ int8_t (*GetDeviceErrorStatus)(struct vl_data *Dev,
+ uint8_t *pDeviceErrorStatus);
+ int8_t (*GetRangeStatusString)(uint8_t RangeStatus,
+ char *pRangeStatusString);
+ int8_t (*GetDeviceErrorString)(uint8_t ErrorCode,
+ char *pDeviceErrorString);
+ int8_t (*GetPalErrorString)(int8_t PalErrorCode,
+ char *pPalErrorString);
+ int8_t (*GetPalStateString)(uint8_t PalStateCode,
+ char *pPalStateString);
+ int8_t (*GetPalState)(struct vl_data *Dev, uint8_t *pPalState);
+ int8_t (*SetPowerMode)(struct vl_data *Dev,
+ uint8_t PowerMode);
+ int8_t (*GetPowerMode)(struct vl_data *Dev,
+ uint8_t *pPowerMode);
+ int8_t (*SetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev,
+ int32_t OffsetCalibrationDataMicroMeter);
+ int8_t (*GetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev,
+ int32_t *pOffsetCalibrationDataMicroMeter);
+ int8_t (*SetLinearityCorrectiveGain)(struct vl_data *Dev,
+ int16_t LinearityCorrectiveGain);
+ int8_t (*GetLinearityCorrectiveGain)(struct vl_data *Dev,
+ uint16_t *pLinearityCorrectiveGain);
+ int8_t (*SetGroupParamHold)(struct vl_data *Dev,
+ uint8_t GroupParamHold);
+ int8_t (*GetUpperLimitMilliMeter)(struct vl_data *Dev,
+ uint16_t *pUpperLimitMilliMeter);
+ int8_t (*SetDeviceAddress)(struct vl_data *Dev,
+ uint8_t DeviceAddress);
+ int8_t (*DataInit)(struct vl_data *Dev);
+ int8_t (*SetTuningSettingBuffer)(struct vl_data *Dev,
+ uint8_t *pTuningSettingBuffer,
+ uint8_t UseInternalTuningSettings);
+ int8_t (*GetTuningSettingBuffer)(struct vl_data *Dev,
+ uint8_t **pTuningSettingBuffer,
+ uint8_t *pUseInternalTuningSettings);
+ int8_t (*StaticInit)(struct vl_data *Dev);
+ int8_t (*WaitDeviceBooted)(struct vl_data *Dev);
+ int8_t (*ResetDevice)(struct vl_data *Dev);
+ int8_t (*SetDeviceParameters)(struct vl_data *Dev,
+ const struct VL_DeviceParameters_t *pDeviceParameters);
+ int8_t (*GetDeviceParameters)(struct vl_data *Dev,
+ struct VL_DeviceParameters_t *pDeviceParameters);
+ int8_t (*SetDeviceMode)(struct vl_data *Dev,
+ uint8_t DeviceMode);
+ int8_t (*GetDeviceMode)(struct vl_data *Dev,
+ uint8_t *pDeviceMode);
+ int8_t (*SetHistogramMode)(struct vl_data *Dev,
+ uint8_t HistogramMode);
+ int8_t (*GetHistogramMode)(struct vl_data *Dev,
+ uint8_t *pHistogramMode);
+ int8_t (*SetMeasurementTimingBudgetMicroSeconds)(struct vl_data *Dev,
+ uint32_t MeasurementTimingBudgetMicroSeconds);
+ int8_t (*GetMeasurementTimingBudgetMicroSeconds)(
+ struct vl_data *Dev,
+ uint32_t *pMeasurementTimingBudgetMicroSeconds);
+ int8_t (*GetVcselPulsePeriod)(struct vl_data *Dev,
+ uint8_t VcselPeriodType,
+ uint8_t *pVCSELPulsePeriod);
+ int8_t (*SetVcselPulsePeriod)(struct vl_data *Dev,
+ uint8_t VcselPeriodType,
+ uint8_t VCSELPulsePeriod);
+ int8_t (*SetSequenceStepEnable)(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ uint8_t SequenceStepEnabled);
+ int8_t (*GetSequenceStepEnable)(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ uint8_t *pSequenceStepEnabled);
+ int8_t (*GetSequenceStepEnables)(struct vl_data *Dev,
+ struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps);
+ int8_t (*SetSequenceStepTimeout)(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ unsigned int TimeOutMilliSecs);
+ int8_t (*GetSequenceStepTimeout)(struct vl_data *Dev,
+ uint8_t SequenceStepId,
+ unsigned int *pTimeOutMilliSecs);
+ int8_t (*GetNumberOfSequenceSteps)(struct vl_data *Dev,
+ uint8_t *pNumberOfSequenceSteps);
+ int8_t (*GetSequenceStepsInfo)(
+ uint8_t SequenceStepId,
+ char *pSequenceStepsString);
+ int8_t (*SetInterMeasurementPeriodMilliSeconds)(
+ struct vl_data *Dev,
+ uint32_t InterMeasurementPeriodMilliSeconds);
+ int8_t (*GetInterMeasurementPeriodMilliSeconds)(
+ struct vl_data *Dev,
+ uint32_t *pInterMeasurementPeriodMilliSeconds);
+ int8_t (*SetXTalkCompensationEnable)(struct vl_data *Dev,
+ uint8_t XTalkCompensationEnable);
+ int8_t (*GetXTalkCompensationEnable)(struct vl_data *Dev,
+ uint8_t *pXTalkCompensationEnable);
+ int8_t (*SetXTalkCompensationRateMegaCps)(
+ struct vl_data *Dev,
+ unsigned int XTalkCompensationRateMegaCps);
+ int8_t (*GetXTalkCompensationRateMegaCps)(
+ struct vl_data *Dev,
+ unsigned int *pXTalkCompensationRateMegaCps);
+ int8_t (*GetNumberOfLimitCheck)(
+ uint16_t *pNumberOfLimitCheck);
+ int8_t (*GetLimitCheckInfo)(struct vl_data *Dev,
+ uint16_t LimitCheckId, char *pLimitCheckString);
+ int8_t (*SetLimitCheckEnable)(struct vl_data *Dev,
+ uint16_t LimitCheckId,
+ uint8_t LimitCheckEnable);
+ int8_t (*GetLimitCheckEnable)(struct vl_data *Dev,
+ uint16_t LimitCheckId, uint8_t *pLimitCheckEnable);
+ int8_t (*SetLimitCheckValue)(struct vl_data *Dev,
+ uint16_t LimitCheckId,
+ unsigned int LimitCheckValue);
+ int8_t (*GetLimitCheckValue)(struct vl_data *Dev,
+ uint16_t LimitCheckId,
+ unsigned int *pLimitCheckValue);
+ int8_t (*GetLimitCheckCurrent)(struct vl_data *Dev,
+ uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent);
+ int8_t (*SetWrapAroundCheckEnable)(struct vl_data *Dev,
+ uint8_t WrapAroundCheckEnable);
+ int8_t (*GetWrapAroundCheckEnable)(struct vl_data *Dev,
+ uint8_t *pWrapAroundCheckEnable);
+ int8_t (*PerformSingleMeasurement)(struct vl_data *Dev);
+ int8_t (*PerformRefCalibration)(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+ int8_t (*SetRefCalibration)(struct vl_data *Dev,
+ uint8_t VhvSettings, uint8_t PhaseCal);
+ int8_t (*GetRefCalibration)(struct vl_data *Dev,
+ uint8_t *pVhvSettings, uint8_t *pPhaseCal);
+ int8_t (*PerformXTalkCalibration)(struct vl_data *Dev,
+ unsigned int XTalkCalDistance,
+ unsigned int *pXTalkCompensationRateMegaCps);
+ int8_t (*PerformOffsetCalibration)(struct vl_data *Dev,
+ unsigned int CalDistanceMilliMeter,
+ int32_t *pOffsetMicroMeter);
+ int8_t (*StartMeasurement)(struct vl_data *Dev);
+ int8_t (*StopMeasurement)(struct vl_data *Dev);
+ int8_t (*GetMeasurementDataReady)(struct vl_data *Dev,
+ uint8_t *pMeasurementDataReady);
+ int8_t (*WaitDeviceReadyForNewMeasurement)(struct vl_data *Dev,
+ uint32_t MaxLoop);
+ int8_t (*GetRangingMeasurementData)(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+ int8_t (*GetHistogramMeasurementData)(struct vl_data *Dev,
+ struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+ int8_t (*PerformSingleRangingMeasurement)(struct vl_data *Dev,
+ struct VL_RangingMeasurementData_t *pRangingMeasurementData);
+ int8_t (*PerformSingleHistogramMeasurement)(struct vl_data *Dev,
+ struct VL_HistogramMeasurementData_t *pHistogramMeasurementData);
+ int8_t (*SetNumberOfROIZones)(struct vl_data *Dev,
+ uint8_t NumberOfROIZones);
+ int8_t (*GetNumberOfROIZones)(struct vl_data *Dev,
+ uint8_t *pNumberOfROIZones);
+ int8_t (*GetMaxNumberOfROIZones)(struct vl_data *Dev,
+ uint8_t *pMaxNumberOfROIZones);
+ int8_t (*SetGpioConfig)(struct vl_data *Dev,
+ uint8_t Pin,
+ uint8_t DeviceMode,
+ uint8_t Functionality,
+ uint8_t Polarity);
+ int8_t (*GetGpioConfig)(struct vl_data *Dev,
+ uint8_t Pin,
+ uint8_t *pDeviceMode,
+ uint8_t *pFunctionality,
+ uint8_t *pPolarity);
+ int8_t (*SetInterruptThresholds)(struct vl_data *Dev,
+ uint8_t DeviceMode,
+ unsigned int ThresholdLow,
+ unsigned int ThresholdHigh);
+ int8_t (*GetInterruptThresholds)(struct vl_data *Dev,
+ uint8_t DeviceMode,
+ unsigned int *pThresholdLow,
+ unsigned int *pThresholdHigh);
+ int8_t (*ClearInterruptMask)(struct vl_data *Dev,
+ uint32_t InterruptMask);
+ int8_t (*GetInterruptMaskStatus)(struct vl_data *Dev,
+ uint32_t *pInterruptMaskStatus);
+ int8_t (*EnableInterruptMask)(struct vl_data *Dev,
+ uint32_t InterruptMask);
+ int8_t (*SetSpadAmbientDamperThreshold)(struct vl_data *Dev,
+ uint16_t SpadAmbientDamperThreshold);
+ int8_t (*GetSpadAmbientDamperThreshold)(struct vl_data *Dev,
+ uint16_t *pSpadAmbientDamperThreshold);
+ int8_t (*SetSpadAmbientDamperFactor)(struct vl_data *Dev,
+ uint16_t SpadAmbientDamperFactor);
+ int8_t (*GetSpadAmbientDamperFactor)(struct vl_data *Dev,
+ uint16_t *pSpadAmbientDamperFactor);
+ int8_t (*PerformRefSpadManagement)(struct vl_data *Dev,
+ uint32_t *refSpadCount, uint8_t *isApertureSpads);
+ int8_t (*SetReferenceSpads)(struct vl_data *Dev,
+ uint32_t count, uint8_t isApertureSpads);
+ int8_t (*GetReferenceSpads)(struct vl_data *Dev,
+ uint32_t *pSpadCount, uint8_t *pIsApertureSpads);
+};
+
+static struct stmvl53l0x_api_fn_t stmvl53l0x_api_func_tbl = {
+ .GetVersion = VL_GetVersion,
+ .GetPalSpecVersion = VL_GetPalSpecVersion,
+ .GetProductRevision = VL_GetProductRevision,
+ .GetDeviceInfo = VL_GetDeviceInfo,
+ .GetDeviceErrorStatus = VL_GetDeviceErrorStatus,
+ .GetRangeStatusString = VL_GetRangeStatusString,
+ .GetDeviceErrorString = VL_GetDeviceErrorString,
+ .GetPalErrorString = VL_GetPalErrorString,
+ .GetPalState = VL_GetPalState,
+ .SetPowerMode = VL_SetPowerMode,
+ .GetPowerMode = VL_GetPowerMode,
+ .SetOffsetCalibrationDataMicroMeter =
+ VL_SetOffsetCalibrationDataMicroMeter,
+ .SetLinearityCorrectiveGain =
+ VL_SetLinearityCorrectiveGain,
+ .GetLinearityCorrectiveGain =
+ VL_GetLinearityCorrectiveGain,
+ .GetOffsetCalibrationDataMicroMeter =
+ VL_GetOffsetCalibrationDataMicroMeter,
+ .SetGroupParamHold = VL_SetGroupParamHold,
+ .GetUpperLimitMilliMeter = VL_GetUpperLimitMilliMeter,
+ .SetDeviceAddress = VL_SetDeviceAddress,
+ .DataInit = VL_DataInit,
+ .SetTuningSettingBuffer = VL_SetTuningSettingBuffer,
+ .GetTuningSettingBuffer = VL_GetTuningSettingBuffer,
+ .StaticInit = VL_StaticInit,
+ .WaitDeviceBooted = VL_WaitDeviceBooted,
+ .ResetDevice = VL_ResetDevice,
+ .SetDeviceParameters = VL_SetDeviceParameters,
+ .SetDeviceMode = VL_SetDeviceMode,
+ .GetDeviceMode = VL_GetDeviceMode,
+ .SetHistogramMode = VL_SetHistogramMode,
+ .GetHistogramMode = VL_GetHistogramMode,
+ .SetMeasurementTimingBudgetMicroSeconds =
+ VL_SetMeasurementTimingBudgetMicroSeconds,
+ .GetMeasurementTimingBudgetMicroSeconds =
+ VL_GetMeasurementTimingBudgetMicroSeconds,
+ .GetVcselPulsePeriod = VL_GetVcselPulsePeriod,
+ .SetVcselPulsePeriod = VL_SetVcselPulsePeriod,
+ .SetSequenceStepEnable = VL_SetSequenceStepEnable,
+ .GetSequenceStepEnable = VL_GetSequenceStepEnable,
+ .GetSequenceStepEnables = VL_GetSequenceStepEnables,
+ .SetSequenceStepTimeout = VL_SetSequenceStepTimeout,
+ .GetSequenceStepTimeout = VL_GetSequenceStepTimeout,
+ .GetNumberOfSequenceSteps = VL_GetNumberOfSequenceSteps,
+ .GetSequenceStepsInfo = VL_GetSequenceStepsInfo,
+ .SetInterMeasurementPeriodMilliSeconds =
+ VL_SetInterMeasurementPeriodMilliSeconds,
+ .GetInterMeasurementPeriodMilliSeconds =
+ VL_GetInterMeasurementPeriodMilliSeconds,
+ .SetXTalkCompensationEnable = VL_SetXTalkCompensationEnable,
+ .GetXTalkCompensationEnable = VL_GetXTalkCompensationEnable,
+ .SetXTalkCompensationRateMegaCps =
+ VL_SetXTalkCompensationRateMegaCps,
+ .GetXTalkCompensationRateMegaCps =
+ VL_GetXTalkCompensationRateMegaCps,
+ .GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck,
+ .GetLimitCheckInfo = VL_GetLimitCheckInfo,
+ .SetLimitCheckEnable = VL_SetLimitCheckEnable,
+ .GetLimitCheckEnable = VL_GetLimitCheckEnable,
+ .SetLimitCheckValue = VL_SetLimitCheckValue,
+ .GetLimitCheckValue = VL_GetLimitCheckValue,
+ .GetLimitCheckCurrent = VL_GetLimitCheckCurrent,
+ .SetWrapAroundCheckEnable = VL_SetWrapAroundCheckEnable,
+ .GetWrapAroundCheckEnable = VL_GetWrapAroundCheckEnable,
+ .PerformSingleMeasurement = VL_PerformSingleMeasurement,
+ .PerformRefCalibration = VL_PerformRefCalibration,
+ .SetRefCalibration = VL_SetRefCalibration,
+ .GetRefCalibration = VL_GetRefCalibration,
+ .PerformXTalkCalibration = VL_PerformXTalkCalibration,
+ .PerformOffsetCalibration = VL_PerformOffsetCalibration,
+ .StartMeasurement = VL_StartMeasurement,
+ .StopMeasurement = VL_StopMeasurement,
+ .GetMeasurementDataReady = VL_GetMeasurementDataReady,
+ .WaitDeviceReadyForNewMeasurement =
+ VL_WaitDeviceReadyForNewMeasurement,
+ .GetRangingMeasurementData = VL_GetRangingMeasurementData,
+ .GetHistogramMeasurementData = VL_GetHistogramMeasurementData,
+ .PerformSingleRangingMeasurement =
+ VL_PerformSingleRangingMeasurement,
+ .PerformSingleHistogramMeasurement =
+ VL_PerformSingleHistogramMeasurement,
+ .SetNumberOfROIZones = VL_SetNumberOfROIZones,
+ .GetNumberOfROIZones = VL_GetNumberOfROIZones,
+ .GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones,
+ .SetGpioConfig = VL_SetGpioConfig,
+ .GetGpioConfig = VL_GetGpioConfig,
+ .SetInterruptThresholds = VL_SetInterruptThresholds,
+ .GetInterruptThresholds = VL_GetInterruptThresholds,
+ .ClearInterruptMask = VL_ClearInterruptMask,
+ .GetInterruptMaskStatus = VL_GetInterruptMaskStatus,
+ .EnableInterruptMask = VL_EnableInterruptMask,
+ .SetSpadAmbientDamperThreshold = VL_SetSpadAmbientDamperThreshold,
+ .GetSpadAmbientDamperThreshold = VL_GetSpadAmbientDamperThreshold,
+ .SetSpadAmbientDamperFactor = VL_SetSpadAmbientDamperFactor,
+ .GetSpadAmbientDamperFactor = VL_GetSpadAmbientDamperFactor,
+ .PerformRefSpadManagement = VL_PerformRefSpadManagement,
+ .SetReferenceSpads = VL_SetReferenceSpads,
+ .GetReferenceSpads = VL_GetReferenceSpads,
+
+};
+struct stmvl53l0x_api_fn_t *papi_func_tbl;
+
+/*
+ * IOCTL definitions
+ */
+#define VL_IOCTL_INIT _IO('p', 0x01)
+#define VL_IOCTL_XTALKCALB _IOW('p', 0x02, unsigned int)
+#define VL_IOCTL_OFFCALB _IOW('p', 0x03, unsigned int)
+#define VL_IOCTL_STOP _IO('p', 0x05)
+#define VL_IOCTL_SETXTALK _IOW('p', 0x06, unsigned int)
+#define VL_IOCTL_SETOFFSET _IOW('p', 0x07, int8_t)
+#define VL_IOCTL_GETDATAS \
+ _IOR('p', 0x0b, struct VL_RangingMeasurementData_t)
+#define VL_IOCTL_REGISTER \
+ _IOWR('p', 0x0c, struct stmvl53l0x_register)
+#define VL_IOCTL_PARAMETER \
+ _IOWR('p', 0x0d, struct stmvl53l0x_parameter)
+
+static long stmvl53l0x_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg);
+/*static int stmvl53l0x_flush(struct file *file, fl_owner_t id);*/
+static int stmvl53l0x_open(struct inode *inode, struct file *file);
+static int stmvl53l0x_init_client(struct vl_data *data);
+static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling,
+ enum init_mode_e mode);
+static int stmvl53l0x_stop(struct vl_data *data);
+
+#ifdef DEBUG_TIME_LOG
+static void stmvl53l0x_DebugTimeGet(struct timeval *ptv)
+{
+ do_gettimeofday(ptv);
+}
+
+static void stmvl53l0x_DebugTimeDuration(struct timeval *pstart_tv,
+ struct timeval *pstop_tv)
+{
+ long total_sec, total_msec;
+
+ total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec;
+ total_msec = (pstop_tv->tv_usec - pstart_tv->tv_usec)/1000;
+ total_msec += total_sec * 1000;
+ dbg("elapsedTime:%ld\n", total_msec);
+}
+#endif
+
+static void stmvl53l0x_setupAPIFunctions(void)
+{
+
+ /*cut 1.1*/
+ err("to setup API cut 1.1\n");
+ papi_func_tbl->GetVersion = VL_GetVersion;
+ papi_func_tbl->GetPalSpecVersion = VL_GetPalSpecVersion;
+ papi_func_tbl->GetProductRevision = VL_GetProductRevision;
+ papi_func_tbl->GetDeviceInfo = VL_GetDeviceInfo;
+ papi_func_tbl->GetDeviceErrorStatus = VL_GetDeviceErrorStatus;
+ papi_func_tbl->GetRangeStatusString = VL_GetRangeStatusString;
+ papi_func_tbl->GetDeviceErrorString = VL_GetDeviceErrorString;
+ papi_func_tbl->GetPalErrorString = VL_GetPalErrorString;
+ papi_func_tbl->GetPalState = VL_GetPalState;
+ papi_func_tbl->SetPowerMode = VL_SetPowerMode;
+ papi_func_tbl->GetPowerMode = VL_GetPowerMode;
+ papi_func_tbl->SetOffsetCalibrationDataMicroMeter =
+ VL_SetOffsetCalibrationDataMicroMeter;
+ papi_func_tbl->GetOffsetCalibrationDataMicroMeter =
+ VL_GetOffsetCalibrationDataMicroMeter;
+ papi_func_tbl->SetLinearityCorrectiveGain =
+ VL_SetLinearityCorrectiveGain;
+ papi_func_tbl->GetLinearityCorrectiveGain =
+ VL_GetLinearityCorrectiveGain;
+ papi_func_tbl->SetGroupParamHold = VL_SetGroupParamHold;
+ papi_func_tbl->GetUpperLimitMilliMeter =
+ VL_GetUpperLimitMilliMeter;
+ papi_func_tbl->SetDeviceAddress = VL_SetDeviceAddress;
+ papi_func_tbl->DataInit = VL_DataInit;
+ papi_func_tbl->SetTuningSettingBuffer = VL_SetTuningSettingBuffer;
+ papi_func_tbl->GetTuningSettingBuffer = VL_GetTuningSettingBuffer;
+ papi_func_tbl->StaticInit = VL_StaticInit;
+ papi_func_tbl->WaitDeviceBooted = VL_WaitDeviceBooted;
+ papi_func_tbl->ResetDevice = VL_ResetDevice;
+ papi_func_tbl->SetDeviceParameters = VL_SetDeviceParameters;
+ papi_func_tbl->SetDeviceMode = VL_SetDeviceMode;
+ papi_func_tbl->GetDeviceMode = VL_GetDeviceMode;
+ papi_func_tbl->SetHistogramMode = VL_SetHistogramMode;
+ papi_func_tbl->GetHistogramMode = VL_GetHistogramMode;
+ papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds =
+ VL_SetMeasurementTimingBudgetMicroSeconds;
+ papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds =
+ VL_GetMeasurementTimingBudgetMicroSeconds;
+ papi_func_tbl->GetVcselPulsePeriod = VL_GetVcselPulsePeriod;
+ papi_func_tbl->SetVcselPulsePeriod = VL_SetVcselPulsePeriod;
+ papi_func_tbl->SetSequenceStepEnable = VL_SetSequenceStepEnable;
+ papi_func_tbl->GetSequenceStepEnable = VL_GetSequenceStepEnable;
+ papi_func_tbl->GetSequenceStepEnables = VL_GetSequenceStepEnables;
+ papi_func_tbl->SetSequenceStepTimeout = VL_SetSequenceStepTimeout;
+ papi_func_tbl->GetSequenceStepTimeout = VL_GetSequenceStepTimeout;
+ papi_func_tbl->GetNumberOfSequenceSteps =
+ VL_GetNumberOfSequenceSteps;
+ papi_func_tbl->GetSequenceStepsInfo = VL_GetSequenceStepsInfo;
+ papi_func_tbl->SetInterMeasurementPeriodMilliSeconds =
+ VL_SetInterMeasurementPeriodMilliSeconds;
+ papi_func_tbl->GetInterMeasurementPeriodMilliSeconds =
+ VL_GetInterMeasurementPeriodMilliSeconds;
+ papi_func_tbl->SetXTalkCompensationEnable =
+ VL_SetXTalkCompensationEnable;
+ papi_func_tbl->GetXTalkCompensationEnable =
+ VL_GetXTalkCompensationEnable;
+ papi_func_tbl->SetXTalkCompensationRateMegaCps =
+ VL_SetXTalkCompensationRateMegaCps;
+ papi_func_tbl->GetXTalkCompensationRateMegaCps =
+ VL_GetXTalkCompensationRateMegaCps;
+ papi_func_tbl->GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck;
+ papi_func_tbl->GetLimitCheckInfo = VL_GetLimitCheckInfo;
+ papi_func_tbl->SetLimitCheckEnable = VL_SetLimitCheckEnable;
+ papi_func_tbl->GetLimitCheckEnable = VL_GetLimitCheckEnable;
+ papi_func_tbl->SetLimitCheckValue = VL_SetLimitCheckValue;
+ papi_func_tbl->GetLimitCheckValue = VL_GetLimitCheckValue;
+ papi_func_tbl->GetLimitCheckCurrent = VL_GetLimitCheckCurrent;
+ papi_func_tbl->SetWrapAroundCheckEnable =
+ VL_SetWrapAroundCheckEnable;
+ papi_func_tbl->GetWrapAroundCheckEnable =
+ VL_GetWrapAroundCheckEnable;
+ papi_func_tbl->PerformSingleMeasurement =
+ VL_PerformSingleMeasurement;
+ papi_func_tbl->PerformRefCalibration = VL_PerformRefCalibration;
+ papi_func_tbl->SetRefCalibration = VL_SetRefCalibration;
+ papi_func_tbl->GetRefCalibration = VL_GetRefCalibration;
+ papi_func_tbl->PerformXTalkCalibration =
+ VL_PerformXTalkCalibration;
+ papi_func_tbl->PerformOffsetCalibration =
+ VL_PerformOffsetCalibration;
+ papi_func_tbl->StartMeasurement = VL_StartMeasurement;
+ papi_func_tbl->StopMeasurement = VL_StopMeasurement;
+ papi_func_tbl->GetMeasurementDataReady =
+ VL_GetMeasurementDataReady;
+ papi_func_tbl->WaitDeviceReadyForNewMeasurement =
+ VL_WaitDeviceReadyForNewMeasurement;
+ papi_func_tbl->GetRangingMeasurementData =
+ VL_GetRangingMeasurementData;
+ papi_func_tbl->GetHistogramMeasurementData =
+ VL_GetHistogramMeasurementData;
+ papi_func_tbl->PerformSingleRangingMeasurement =
+ VL_PerformSingleRangingMeasurement;
+ papi_func_tbl->PerformSingleHistogramMeasurement =
+ VL_PerformSingleHistogramMeasurement;
+ papi_func_tbl->SetNumberOfROIZones = VL_SetNumberOfROIZones;
+ papi_func_tbl->GetNumberOfROIZones = VL_GetNumberOfROIZones;
+ papi_func_tbl->GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones;
+ papi_func_tbl->SetGpioConfig = VL_SetGpioConfig;
+ papi_func_tbl->GetGpioConfig = VL_GetGpioConfig;
+ papi_func_tbl->SetInterruptThresholds = VL_SetInterruptThresholds;
+ papi_func_tbl->GetInterruptThresholds = VL_GetInterruptThresholds;
+ papi_func_tbl->ClearInterruptMask = VL_ClearInterruptMask;
+ papi_func_tbl->GetInterruptMaskStatus = VL_GetInterruptMaskStatus;
+ papi_func_tbl->EnableInterruptMask = VL_EnableInterruptMask;
+ papi_func_tbl->SetSpadAmbientDamperThreshold =
+ VL_SetSpadAmbientDamperThreshold;
+ papi_func_tbl->GetSpadAmbientDamperThreshold =
+ VL_GetSpadAmbientDamperThreshold;
+ papi_func_tbl->SetSpadAmbientDamperFactor =
+ VL_SetSpadAmbientDamperFactor;
+ papi_func_tbl->GetSpadAmbientDamperFactor =
+ VL_GetSpadAmbientDamperFactor;
+ papi_func_tbl->PerformRefSpadManagement =
+ VL_PerformRefSpadManagement;
+ papi_func_tbl->SetReferenceSpads = VL_SetReferenceSpads;
+ papi_func_tbl->GetReferenceSpads = VL_GetReferenceSpads;
+
+}
+
+static void stmvl53l0x_ps_read_measurement(struct vl_data *data)
+{
+ struct timeval tv;
+ struct vl_data *vl53l0x_dev = data;
+ int8_t Status = VL_ERROR_NONE;
+ unsigned int LimitCheckCurrent;
+
+ do_gettimeofday(&tv);
+
+ data->ps_data = data->rangeData.RangeMilliMeter;
+ input_report_abs(data->input_dev_ps, ABS_DISTANCE,
+ (int)(data->ps_data + 5) / 10);
+ input_report_abs(data->input_dev_ps, ABS_HAT0X, tv.tv_sec);
+ input_report_abs(data->input_dev_ps, ABS_HAT0Y, tv.tv_usec);
+ input_report_abs(data->input_dev_ps, ABS_HAT1X,
+ data->rangeData.RangeMilliMeter);
+ input_report_abs(data->input_dev_ps, ABS_HAT1Y,
+ data->rangeData.RangeStatus);
+ input_report_abs(data->input_dev_ps, ABS_HAT2X,
+ data->rangeData.SignalRateRtnMegaCps);
+ input_report_abs(data->input_dev_ps, ABS_HAT2Y,
+ data->rangeData.AmbientRateRtnMegaCps);
+ input_report_abs(data->input_dev_ps, ABS_HAT3X,
+ data->rangeData.MeasurementTimeUsec);
+ input_report_abs(data->input_dev_ps, ABS_HAT3Y,
+ data->rangeData.RangeDMaxMilliMeter);
+ Status = papi_func_tbl->GetLimitCheckCurrent(vl53l0x_dev,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ &LimitCheckCurrent);
+ if (Status == VL_ERROR_NONE) {
+ input_report_abs(data->input_dev_ps, ABS_WHEEL,
+ LimitCheckCurrent);
+ }
+ input_report_abs(data->input_dev_ps, ABS_PRESSURE,
+ data->rangeData.EffectiveSpadRtnCount);
+ input_sync(data->input_dev_ps);
+
+ if (data->enableDebug)
+ err("range:%d, RtnRateMcps:%d,err:0x%x\n",
+ data->rangeData.RangeMilliMeter,
+ data->rangeData.SignalRateRtnMegaCps,
+ data->rangeData.RangeStatus);
+ err("Dmax:%d,rtnambr:%d,time:%d,Spad:%d,SigmaLimit:%d\n",
+ data->rangeData.RangeDMaxMilliMeter,
+ data->rangeData.AmbientRateRtnMegaCps,
+ data->rangeData.MeasurementTimeUsec,
+ data->rangeData.EffectiveSpadRtnCount,
+ LimitCheckCurrent);
+
+
+}
+
+static void stmvl53l0x_cancel_handler(struct vl_data *data)
+{
+ unsigned long flags;
+ bool ret;
+
+ spin_lock_irqsave(&data->update_lock.wait_lock, flags);
+ /*
+ * If work is already scheduled then subsequent schedules will not
+ * change the scheduled time that's why we have to cancel it first.
+ */
+ ret = cancel_delayed_work(&data->dwork);
+ if (ret == 0)
+ err("cancel_delayed_work return FALSE\n");
+
+ spin_unlock_irqrestore(&data->update_lock.wait_lock, flags);
+
+}
+
+void stmvl53l0x_schedule_handler(struct vl_data *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&data->update_lock.wait_lock, flags);
+ /*
+ * If work is already scheduled then subsequent schedules will not
+ * change the scheduled time that's why we have to cancel it first.
+ */
+ cancel_delayed_work(&data->dwork);
+ schedule_delayed_work(&data->dwork, 0);
+ spin_unlock_irqrestore(&data->update_lock.wait_lock, flags);
+
+}
+
+/* Flag used to exit the thread when kthread_stop() is invoked */
+static int poll_thread_exit;
+int stmvl53l0x_poll_thread(void *data)
+{
+ struct vl_data *vl53l0x_dev = data;
+ int8_t Status = VL_ERROR_NONE;
+ uint32_t sleep_time = 0;
+ uint32_t interruptStatus = 0;
+
+ dbg("Starting Polling thread\n");
+
+ while (!kthread_should_stop()) {
+ /* Check if enable_ps_sensor is true or */
+ /* exit request is made. If not block */
+ wait_event(vl53l0x_dev->poll_thread_wq,
+ (vl53l0x_dev->enable_ps_sensor || poll_thread_exit));
+ if (poll_thread_exit) {
+ dbg("Exiting the poll thread\n");
+ break;
+ }
+
+ mutex_lock(&vl53l0x_dev->work_mutex);
+
+ sleep_time = vl53l0x_dev->delay_ms;
+ Status = VL_GetInterruptMaskStatus(vl53l0x_dev,
+ &interruptStatus);
+ if (Status == VL_ERROR_NONE &&
+ interruptStatus &&
+ interruptStatus != vl53l0x_dev->interruptStatus) {
+ vl53l0x_dev->interruptStatus = interruptStatus;
+ vl53l0x_dev->noInterruptCount = 0;
+ stmvl53l0x_schedule_handler(vl53l0x_dev);
+
+ } else {
+ vl53l0x_dev->noInterruptCount++;
+ }
+
+ /* Force Clear interrupt mask and restart if no interrupt */
+ /* after twice the timingBudget */
+ if ((vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms) >
+ (vl53l0x_dev->timingBudget * 2)) {
+ dbg("No interrupt after (%u) msec(TimingBudget = %u)\n",
+ (vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms),
+ vl53l0x_dev->timingBudget);
+ Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0);
+ if (vl53l0x_dev->deviceMode ==
+ VL_DEVICEMODE_SINGLE_RANGING) {
+ Status = papi_func_tbl->StartMeasurement(vl53l0x_dev);
+ if (Status != VL_ERROR_NONE)
+ dbg("Status = %d\n", Status);
+ }
+ }
+
+ mutex_unlock(&vl53l0x_dev->work_mutex);
+
+ msleep(sleep_time);
+ }
+
+ return 0;
+}
+
+/* work handler */
+static void stmvl53l0x_work_handler(struct work_struct *work)
+{
+ struct vl_data *data = container_of(work,
+ struct vl_data, dwork.work);
+
+ struct vl_data *vl53l0x_dev = data;
+
+ int8_t Status = VL_ERROR_NONE;
+
+ mutex_lock(&data->work_mutex);
+ /* dbg("Enter\n"); */
+
+
+ if (vl53l0x_dev->enable_ps_sensor == 1) {
+#ifdef DEBUG_TIME_LOG
+ stmvl53l0x_DebugTimeGet(&stop_tv);
+ stmvl53l0x_DebugTimeDuration(&start_tv, &stop_tv);
+#endif
+ /* ISR has scheduled this function */
+ if (vl53l0x_dev->interrupt_received == 1) {
+ Status = papi_func_tbl->GetInterruptMaskStatus(
+ vl53l0x_dev, &vl53l0x_dev->interruptStatus);
+ if (Status != VL_ERROR_NONE) {
+ dbg("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+ }
+ vl53l0x_dev->interrupt_received = 0;
+ }
+ if (data->enableDebug)
+ dbg("interruptStatus:0x%x, interrupt_received:%d\n",
+ vl53l0x_dev->interruptStatus,
+ vl53l0x_dev->interrupt_received);
+
+ if (vl53l0x_dev->interruptStatus ==
+ vl53l0x_dev->gpio_function) {
+ Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev,
+ 0);
+ if (Status != VL_ERROR_NONE) {
+ dbg("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+ } else {
+ Status =
+ papi_func_tbl->GetRangingMeasurementData(
+ vl53l0x_dev, &(data->rangeData));
+ /* to push the measurement */
+ if (Status == VL_ERROR_NONE)
+ stmvl53l0x_ps_read_measurement(data);
+ else
+ dbg("%s(%d) : Status = %d\n",
+ __func__, __LINE__, Status);
+
+ dbg("Measured range:%d\n",
+ data->rangeData.RangeMilliMeter);
+
+ if (data->enableDebug)
+ dbg("Measured range:%d\n",
+ data->rangeData.RangeMilliMeter);
+
+ if (data->deviceMode ==
+ VL_DEVICEMODE_SINGLE_RANGING)
+ Status =
+ papi_func_tbl->StartMeasurement(
+ vl53l0x_dev);
+ }
+ }
+#ifdef DEBUG_TIME_LOG
+ stmvl53l0x_DebugTimeGet(&start_tv);
+#endif
+
+ }
+
+
+ vl53l0x_dev->interruptStatus = 0;
+
+ mutex_unlock(&data->work_mutex);
+
+}
+
+
+/*
+ * SysFS support
+ */
+static ssize_t stmvl53l0x_show_enable_ps_sensor(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->enable_ps_sensor);
+}
+
+static ssize_t stmvl53l0x_store_enable_ps_sensor(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+
+ unsigned int val;
+
+ kstrtoint(buf, 10, &val);
+ if ((val != 0) && (val != 1)) {
+ err("store unvalid value=%ld\n", val);
+ return count;
+ }
+ mutex_lock(&data->work_mutex);
+ dbg("Enter, enable_ps_sensor flag:%d\n",
+ data->enable_ps_sensor);
+ dbg("enable ps senosr ( %ld)\n", val);
+
+ if (val == 1) {
+ /* turn on tof sensor */
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0x_start(data, 3, NORMAL_MODE);
+ } else {
+ err("Already enabled. Skip !");
+ }
+ } else {
+ /* turn off tof sensor */
+ if (data->enable_ps_sensor == 1) {
+ data->enable_ps_sensor = 0;
+ /* to stop */
+ stmvl53l0x_stop(data);
+ }
+ }
+ dbg("End\n");
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_enable_ps_sensor,
+ stmvl53l0x_store_enable_ps_sensor);
+
+static ssize_t stmvl53l0x_show_enable_debug(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->enableDebug);
+}
+
+/* for debug */
+static ssize_t stmvl53l0x_store_enable_debug(struct device *dev,
+ struct device_attribute *attr, const
+ char *buf, size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ int on;
+
+ kstrtoint(buf, 10, &on);
+ if ((on != 0) && (on != 1)) {
+ err("set debug=%ld\n", on);
+ return count;
+ }
+ data->enableDebug = on;
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(enable_debug, 0660/*S_IWUSR | S_IRUGO*/,
+ stmvl53l0x_show_enable_debug,
+ stmvl53l0x_store_enable_debug);
+
+static ssize_t stmvl53l0x_show_set_delay_ms(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->delay_ms);
+}
+
+/* for work handler scheduler time */
+static ssize_t stmvl53l0x_store_set_delay_ms(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ int delay_ms;
+
+ kstrtoint(buf, 10, &delay_ms);
+ if (delay_ms == 0) {
+ err("set delay_ms=%ld\n", delay_ms);
+ return count;
+ }
+ mutex_lock(&data->work_mutex);
+ data->delay_ms = delay_ms;
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_set_delay_ms,
+ stmvl53l0x_store_set_delay_ms);
+
+/* Timing Budget */
+static ssize_t stmvl53l0x_show_timing_budget(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 10, "%d\n", data->timingBudget);
+}
+
+static ssize_t stmvl53l0x_store_set_timing_budget(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ int timingBudget;
+
+ kstrtoint(buf, 10, &timingBudget);
+ if (timingBudget == 0) {
+ err("set timingBudget=%ld\n", timingBudget);
+ return count;
+ }
+ mutex_lock(&data->work_mutex);
+ data->timingBudget = timingBudget;
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_timing_budget, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_timing_budget,
+ stmvl53l0x_store_set_timing_budget);
+
+
+/* Long Range */
+static ssize_t stmvl53l0x_show_long_range(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+
+ return snprintf(buf, 5, "%d\n", data->useLongRange);
+}
+
+static ssize_t stmvl53l0x_store_set_long_range(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ int useLongRange;
+
+ kstrtoint(buf, 10, &useLongRange);
+ if ((useLongRange != 0) && (useLongRange != 1)) {
+ err("set useLongRange=%ld\n", useLongRange);
+ return count;
+ }
+
+ mutex_lock(&data->work_mutex);
+ data->useLongRange = useLongRange;
+ if (useLongRange)
+ data->timingBudget = 26000;
+ else
+ data->timingBudget = 200000;
+
+ mutex_unlock(&data->work_mutex);
+
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(set_long_range, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_long_range,
+ stmvl53l0x_store_set_long_range);
+
+static ssize_t stmvl53l0x_show_meter(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ struct VL_RangingMeasurementData_t Measure;
+
+ papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure);
+ dbg("Measure = %d\n", Measure.RangeMilliMeter);
+ return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter);
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(show_meter, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_meter,
+ NULL);
+
+static ssize_t stmvl53l0x_show_xtalk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ struct VL_RangingMeasurementData_t Measure;
+
+ dbg("Measure = %d\n", Measure.RangeMilliMeter);
+ return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter);
+}
+
+static ssize_t stmvl53l0x_set_xtalk(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ unsigned int targetDistance;
+
+ kstrtoint(buf, 10, &targetDistance);
+ data->xtalkCalDistance = targetDistance;
+ stmvl53l0x_start(data, 3, XTALKCALIB_MODE);
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(xtalk_cal, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_xtalk,
+ stmvl53l0x_set_xtalk);
+
+static ssize_t stmvl53l0x_show_offset(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ struct VL_RangingMeasurementData_t Measure;
+
+ papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure);
+ dbg("Measure = %d\n", Measure.RangeMilliMeter);
+ return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter);
+}
+
+static ssize_t stmvl53l0x_set_offset(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vl_data *data = dev_get_drvdata(dev);
+ unsigned int targetDistance;
+
+ kstrtoint(buf, 10, &targetDistance);
+ data->offsetCalDistance = targetDistance;
+ stmvl53l0x_start(data, 3, OFFSETCALIB_MODE);
+ return count;
+}
+
+/* DEVICE_ATTR(name,mode,show,store) */
+static DEVICE_ATTR(offset_cal, 0660/*S_IWUGO | S_IRUGO*/,
+ stmvl53l0x_show_offset,
+ stmvl53l0x_set_offset);
+
+static struct attribute *stmvl53l0x_attributes[] = {
+ &dev_attr_enable_ps_sensor.attr,
+ &dev_attr_enable_debug.attr,
+ &dev_attr_set_delay_ms.attr,
+ &dev_attr_set_timing_budget.attr,
+ &dev_attr_set_long_range.attr,
+ &dev_attr_show_meter.attr,
+ &dev_attr_xtalk_cal.attr,
+ &dev_attr_offset_cal.attr,
+ NULL,
+};
+
+
+static const struct attribute_group stmvl53l0x_attr_group = {
+ .attrs = stmvl53l0x_attributes,
+};
+
+/*
+ * misc device file operation functions
+ */
+static int stmvl53l0x_ioctl_handler(struct file *file,
+ unsigned int cmd, unsigned long arg,
+ void __user *p)
+{
+ int rc = 0;
+ unsigned int xtalkint = 0;
+ unsigned int targetDistance = 0;
+ int8_t offsetint = 0;
+ struct vl_data *data =
+ container_of(file->private_data,
+ struct vl_data, miscdev);
+ struct stmvl53l0x_register reg;
+ struct stmvl53l0x_parameter parameter;
+ struct vl_data *vl53l0x_dev = data;
+ uint8_t deviceMode;
+ uint8_t page_num = 0;
+
+ if (!data)
+ return -EINVAL;
+
+ dbg("Enter enable_ps_sensor:%d\n", data->enable_ps_sensor);
+ switch (cmd) {
+ /* enable */
+ case VL_IOCTL_INIT:
+ dbg("VL_IOCTL_INIT\n");
+ /* turn on tof sensor only if it's not enabled by other */
+ /* client */
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0x_start(data, 3, NORMAL_MODE);
+ } else
+ rc = -EINVAL;
+ break;
+ /* crosstalk calibration */
+ case VL_IOCTL_XTALKCALB:
+ dbg("VL_IOCTL_XTALKCALB\n");
+ data->xtalkCalDistance = 100;
+ if (copy_from_user(&targetDistance, (unsigned int *)p,
+ sizeof(unsigned int))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ data->xtalkCalDistance = targetDistance;
+
+ /* turn on tof sensor only if it's not enabled by other */
+ /* client */
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0x_start(data, 3, XTALKCALIB_MODE);
+ } else
+ rc = -EINVAL;
+ break;
+ /* set up Xtalk value */
+ case VL_IOCTL_SETXTALK:
+ dbg("VL_IOCTL_SETXTALK\n");
+ if (copy_from_user(&xtalkint, (unsigned int *)p,
+ sizeof(unsigned int))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ dbg("SETXTALK as 0x%x\n", xtalkint);
+/* later
+ * SetXTalkCompensationRate(vl53l0x_dev, xtalkint);
+ */
+ break;
+ /* offset calibration */
+ case VL_IOCTL_OFFCALB:
+ dbg("VL_IOCTL_OFFCALB\n");
+ data->offsetCalDistance = 50;
+ if (copy_from_user(&targetDistance, (unsigned int *)p,
+ sizeof(unsigned int))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ data->offsetCalDistance = targetDistance;
+ if (data->enable_ps_sensor == 0) {
+ /* to start */
+ stmvl53l0x_start(data, 3, OFFSETCALIB_MODE);
+ } else
+ rc = -EINVAL;
+ break;
+ /* set up offset value */
+ case VL_IOCTL_SETOFFSET:
+ dbg("VL_IOCTL_SETOFFSET\n");
+ if (copy_from_user(&offsetint, (int8_t *)p, sizeof(int8_t))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ dbg("SETOFFSET as %d\n", offsetint);
+ /* later SetOffsetCalibrationData(vl53l0x_dev, offsetint); */
+ break;
+ /* disable */
+ case VL_IOCTL_STOP:
+ dbg("VL_IOCTL_STOP\n");
+ /* turn off tof sensor only if it's enabled by other client */
+ if (data->enable_ps_sensor == 1) {
+ data->enable_ps_sensor = 0;
+ /* to stop */
+ stmvl53l0x_stop(data);
+ }
+ break;
+ /* Get all range data */
+ case VL_IOCTL_GETDATAS:
+ dbg("VL_IOCTL_GETDATAS\n");
+ if (copy_to_user((struct VL_RangingMeasurementData_t *)p,
+ &(data->rangeData),
+ sizeof(struct VL_RangingMeasurementData_t))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ break;
+ /* Register tool */
+ case VL_IOCTL_REGISTER:
+ dbg("VL_IOCTL_REGISTER\n");
+ if (copy_from_user(®, (struct stmvl53l0x_register *)p,
+ sizeof(struct stmvl53l0x_register))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ reg.status = 0;
+ page_num = (uint8_t)((reg.reg_index & 0x0000ff00) >> 8);
+ dbg(
+"VL_IOCTL_REGISTER, page number:%d\n", page_num);
+ if (page_num != 0)
+ reg.status = VL_WrByte(vl53l0x_dev,
+ 0xFF, page_num);
+
+ switch (reg.reg_bytes) {
+ case(4):
+ if (reg.is_read)
+ reg.status = VL_RdDWord(vl53l0x_dev,
+ (uint8_t)reg.reg_index,
+ ®.reg_data);
+ else
+ reg.status = VL_WrDWord(vl53l0x_dev,
+ (uint8_t)reg.reg_index,
+ reg.reg_data);
+ break;
+ case(2):
+ if (reg.is_read)
+ reg.status = VL_RdWord(vl53l0x_dev,
+ (uint8_t)reg.reg_index,
+ (uint16_t *)®.reg_data);
+ else
+ reg.status = VL_WrWord(vl53l0x_dev,
+ (uint8_t)reg.reg_index,
+ (uint16_t)reg.reg_data);
+ break;
+ case(1):
+ if (reg.is_read)
+ reg.status = VL_RdByte(vl53l0x_dev,
+ (uint8_t)reg.reg_index,
+ (uint8_t *)®.reg_data);
+ else
+ reg.status = VL_WrByte(vl53l0x_dev,
+ (uint8_t)reg.reg_index,
+ (uint8_t)reg.reg_data);
+ break;
+ default:
+ reg.status = -1;
+
+ }
+ if (page_num != 0)
+ reg.status = VL_WrByte(vl53l0x_dev, 0xFF, 0);
+
+
+ if (copy_to_user((struct stmvl53l0x_register *)p, ®,
+ sizeof(struct stmvl53l0x_register))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ break;
+ /* parameter access */
+ case VL_IOCTL_PARAMETER:
+ dbg("VL_IOCTL_PARAMETER\n");
+ if (copy_from_user(¶meter, (struct stmvl53l0x_parameter *)p,
+ sizeof(struct stmvl53l0x_parameter))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ parameter.status = 0;
+ if (data->enableDebug)
+ dbg("VL_IOCTL_PARAMETER Name = %d\n",
+ parameter.name);
+ switch (parameter.name) {
+ case (OFFSET_PAR):
+ if (parameter.is_read)
+ parameter.status =
+ papi_func_tbl->GetOffsetCalibrationDataMicroMeter(
+ vl53l0x_dev, ¶meter.value);
+ else
+ parameter.status =
+ papi_func_tbl->SetOffsetCalibrationDataMicroMeter(
+ vl53l0x_dev, parameter.value);
+ dbg("get parameter value as %d\n",
+ parameter.value);
+ break;
+
+ case (REFERENCESPADS_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetReferenceSpads(vl53l0x_dev,
+ (uint32_t *)&(parameter.value),
+ (uint8_t *)&(parameter.value2));
+ if (data->enableDebug)
+ dbg("Get RefSpad: Count:%u, Type:%u\n",
+ parameter.value, (uint8_t)parameter.value2);
+ } else {
+ if (data->enableDebug)
+ dbg("Set RefSpad: Count:%u, Type:%u\n",
+ parameter.value, (uint8_t)parameter.value2);
+
+ parameter.status =
+ papi_func_tbl->SetReferenceSpads(
+ vl53l0x_dev,
+ (uint32_t)(parameter.value),
+ (uint8_t)(parameter.value2));
+ }
+ break;
+
+ case (REFCALIBRATION_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetRefCalibration(vl53l0x_dev,
+ (uint8_t *)&(parameter.value),
+ (uint8_t *)&(parameter.value2));
+ if (data->enableDebug)
+ dbg("Get Ref: Vhv:%u, PhaseCal:%u\n",
+ (uint8_t)parameter.value,
+ (uint8_t)parameter.value2);
+ } else {
+ if (data->enableDebug)
+ dbg("Set Ref: Vhv:%u, PhaseCal:%u\n",
+ (uint8_t)parameter.value,
+ (uint8_t)parameter.value2);
+ parameter.status =
+ papi_func_tbl->SetRefCalibration(
+ vl53l0x_dev, (uint8_t)(parameter.value),
+ (uint8_t)(parameter.value2));
+ }
+ break;
+ case (XTALKRATE_PAR):
+ if (parameter.is_read)
+ parameter.status =
+ papi_func_tbl->GetXTalkCompensationRateMegaCps(
+ vl53l0x_dev, (unsigned int *)
+ ¶meter.value);
+ else
+ parameter.status =
+ papi_func_tbl->SetXTalkCompensationRateMegaCps(
+ vl53l0x_dev,
+ (unsigned int)
+ parameter.value);
+
+ break;
+ case (XTALKENABLE_PAR):
+ if (parameter.is_read)
+ parameter.status =
+ papi_func_tbl->GetXTalkCompensationEnable(
+ vl53l0x_dev,
+ (uint8_t *) ¶meter.value);
+ else
+ parameter.status =
+ papi_func_tbl->SetXTalkCompensationEnable(
+ vl53l0x_dev,
+ (uint8_t) parameter.value);
+ break;
+ case (GPIOFUNC_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetGpioConfig(vl53l0x_dev, 0,
+ &deviceMode,
+ &data->gpio_function,
+ &data->gpio_polarity);
+ parameter.value = data->gpio_function;
+ } else {
+ data->gpio_function = parameter.value;
+ parameter.status =
+ papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0,
+ data->gpio_function,
+ data->gpio_polarity);
+ }
+ break;
+ case (LOWTHRESH_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetInterruptThresholds(
+ vl53l0x_dev, 0, &(data->low_threshold),
+ &(data->high_threshold));
+ parameter.value = data->low_threshold >> 16;
+ } else {
+ data->low_threshold = parameter.value << 16;
+ parameter.status =
+ papi_func_tbl->SetInterruptThresholds(
+ vl53l0x_dev, 0, data->low_threshold,
+ data->high_threshold);
+ }
+ break;
+ case (HIGHTHRESH_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetInterruptThresholds(
+ vl53l0x_dev, 0, &(data->low_threshold),
+ &(data->high_threshold));
+ parameter.value = data->high_threshold >> 16;
+ } else {
+ data->high_threshold = parameter.value << 16;
+ parameter.status =
+ papi_func_tbl->SetInterruptThresholds(
+ vl53l0x_dev, 0, data->low_threshold,
+ data->high_threshold);
+ }
+ break;
+ case (DEVICEMODE_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetDeviceMode(
+ vl53l0x_dev,
+ (uint8_t *)&
+ (parameter.value));
+ } else {
+ parameter.status =
+ papi_func_tbl->SetDeviceMode(
+ vl53l0x_dev,
+ (uint8_t)(parameter.value));
+ data->deviceMode =
+ (uint8_t)(parameter.value);
+ }
+ break;
+
+
+
+ case (INTERMEASUREMENT_PAR):
+ if (parameter.is_read) {
+ parameter.status =
+ papi_func_tbl->GetInterMeasurementPeriodMilliSeconds(
+ vl53l0x_dev, (uint32_t *)&(parameter.value));
+ } else {
+ parameter.status =
+ papi_func_tbl->SetInterMeasurementPeriodMilliSeconds(
+ vl53l0x_dev, (uint32_t)(parameter.value));
+ data->interMeasurems = parameter.value;
+ }
+ break;
+
+ }
+
+ if (copy_to_user((struct stmvl53l0x_parameter *)p, ¶meter,
+ sizeof(struct stmvl53l0x_parameter))) {
+ err("%d, fail\n", __LINE__);
+ return -EFAULT;
+ }
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
+
+ return rc;
+}
+
+static int stmvl53l0x_open(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int stmvl53l0x_flush(struct file *file, fl_owner_t id)
+{
+ struct vl_data *data = container_of(file->private_data,
+ struct vl_data, miscdev);
+ (void) file;
+ (void) id;
+
+ if (data) {
+ if (data->enable_ps_sensor == 1) {
+ /* turn off tof sensor if it's enabled */
+ data->enable_ps_sensor = 0;
+ /* to stop */
+ stmvl53l0x_stop(data);
+ }
+ }
+ return 0;
+}
+
+static long stmvl53l0x_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ long ret;
+ struct vl_data *data =
+ container_of(file->private_data,
+ struct vl_data, miscdev);
+ mutex_lock(&data->work_mutex);
+ ret = stmvl53l0x_ioctl_handler(file, cmd, arg, (void __user *)arg);
+ mutex_unlock(&data->work_mutex);
+
+ return ret;
+}
+
+/*
+ * Initialization function
+ */
+static int stmvl53l0x_init_client(struct vl_data *data)
+{
+
+ int8_t Status = VL_ERROR_NONE;
+ struct VL_DeviceInfo_t DeviceInfo;
+ struct vl_data *vl53l0x_dev = data;
+
+ uint32_t refSpadCount;
+ uint8_t isApertureSpads;
+ uint8_t VhvSettings;
+ uint8_t PhaseCal;
+
+ dbg("Enter\n");
+
+ vl53l0x_dev->I2cDevAddr = 0x52;
+ vl53l0x_dev->comms_type = 1;
+ vl53l0x_dev->comms_speed_khz = 400;
+
+ /* Setup API functions based on revision */
+ stmvl53l0x_setupAPIFunctions();
+
+ if (Status == VL_ERROR_NONE && data->reset) {
+ dbg("Call of VL_DataInit\n");
+ /* Data initialization */
+ Status = papi_func_tbl->DataInit(vl53l0x_dev);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ dbg("VL_GetDeviceInfo:\n");
+ Status = papi_func_tbl->GetDeviceInfo(vl53l0x_dev, &DeviceInfo);
+ if (Status == VL_ERROR_NONE) {
+ dbg("Device Name : %s\n", DeviceInfo.Name);
+ dbg("Device Type : %s\n", DeviceInfo.Type);
+ dbg("Device ID : %s\n", DeviceInfo.ProductId);
+ dbg("Product type: %d\n", DeviceInfo.ProductType);
+ dbg("ProductRevisionMajor : %d\n",
+ DeviceInfo.ProductRevisionMajor);
+ dbg("ProductRevisionMinor : %d\n",
+ DeviceInfo.ProductRevisionMinor);
+ }
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ dbg("Call of VL_StaticInit\n");
+ Status = papi_func_tbl->StaticInit(vl53l0x_dev);
+ /* Device Initialization */
+ }
+
+ if (Status == VL_ERROR_NONE && data->reset) {
+ if (papi_func_tbl->PerformRefCalibration != NULL) {
+ dbg("Call of VL_PerformRefCalibration\n");
+ Status = papi_func_tbl->PerformRefCalibration(
+ vl53l0x_dev, &VhvSettings, &PhaseCal);
+ /* Ref calibration */
+ }
+ }
+
+ if (Status == VL_ERROR_NONE && data->reset) {
+ if (papi_func_tbl->PerformRefSpadManagement != NULL) {
+ dbg("Call of VL_PerformRefSpadManagement\n");
+ Status = papi_func_tbl->PerformRefSpadManagement(
+ vl53l0x_dev, &refSpadCount, &isApertureSpads);
+ /* Ref Spad Management */
+ }
+ data->reset = 0;
+ /* needed, even the function is NULL */
+ }
+
+ if (Status == VL_ERROR_NONE) {
+
+ dbg("Call of VL_SetDeviceMode\n");
+ Status = papi_func_tbl->SetDeviceMode(vl53l0x_dev,
+ VL_DEVICEMODE_SINGLE_RANGING);
+ /* Setup in single ranging mode */
+ }
+ if (Status == VL_ERROR_NONE)
+ Status = papi_func_tbl->SetWrapAroundCheckEnable(
+ vl53l0x_dev, 1);
+
+ dbg("End\n");
+
+ return 0;
+}
+
+static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling,
+ enum init_mode_e mode)
+{
+ int rc = 0;
+ struct vl_data *vl53l0x_dev = data;
+ int8_t Status = VL_ERROR_NONE;
+
+ dbg("Enter\n");
+
+ /* Power up */
+ rc = pmodule_func_tbl->power_up(data->client_object, &data->reset);
+ if (rc) {
+ err("%d,error rc %d\n", __LINE__, rc);
+ return rc;
+ }
+ /* init */
+ rc = stmvl53l0x_init_client(data);
+ if (rc) {
+ err("%d, error rc %d\n", __LINE__, rc);
+ pmodule_func_tbl->power_down(data->client_object);
+ return -EINVAL;
+ }
+
+ /* check mode */
+ if (mode != NORMAL_MODE)
+ papi_func_tbl->SetXTalkCompensationEnable(vl53l0x_dev, 1);
+
+ if (mode == OFFSETCALIB_MODE) {
+ /*VL_SetOffsetCalibrationDataMicroMeter(vl53l0x_dev, 0);*/
+ unsigned int OffsetMicroMeter;
+
+ papi_func_tbl->PerformOffsetCalibration(vl53l0x_dev,
+ (data->offsetCalDistance<<16),
+ &OffsetMicroMeter);
+ dbg("Offset calibration:%u\n", OffsetMicroMeter);
+ return rc;
+ } else if (mode == XTALKCALIB_MODE) {
+ unsigned int XTalkCompensationRateMegaCps;
+ /*caltarget distance : 100mm and convert to */
+ /* fixed point 16 16 format */
+ papi_func_tbl->PerformXTalkCalibration(vl53l0x_dev,
+ (data->xtalkCalDistance<<16),
+ &XTalkCompensationRateMegaCps);
+ dbg("Xtalk calibration:%u\n", XTalkCompensationRateMegaCps);
+ return rc;
+ }
+ /* set up device parameters */
+ data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW;
+
+ /* Following two calls are made from IOCTL as well */
+ papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0,
+ data->gpio_function,
+ VL_INTERRUPTPOLARITY_LOW);
+
+ papi_func_tbl->SetInterruptThresholds(vl53l0x_dev, 0,
+ data->low_threshold, data->high_threshold);
+
+ if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING) {
+ papi_func_tbl->SetInterMeasurementPeriodMilliSeconds(
+ vl53l0x_dev, data->interMeasurems);
+ }
+
+ dbg("DeviceMode:0x%x, interMeasurems:%d==\n", data->deviceMode,
+ data->interMeasurems);
+ papi_func_tbl->SetDeviceMode(vl53l0x_dev,
+ data->deviceMode);
+ papi_func_tbl->ClearInterruptMask(vl53l0x_dev,
+ 0);
+
+ if (vl53l0x_dev->useLongRange) {
+ dbg("Configure Long Ranging\n");
+ Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+ VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ (unsigned int)(65536/10)); /* 0.1 * 65536 */
+ if (Status == VL_ERROR_NONE) {
+ Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ (unsigned int)(60*65536));
+ } else {
+ dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n",
+ Status);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ dbg("Set Timing Budget = %u\n",
+ vl53l0x_dev->timingBudget);
+ Status =
+ papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds(
+ vl53l0x_dev, vl53l0x_dev->timingBudget);
+ } else {
+ dbg("SetLimitCheckValue failed err =%d\n",
+ Status);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+ VL_VCSEL_PERIOD_PRE_RANGE, 18);
+ } else {
+ dbg("SetMeasurementTimingBudget failed err = %d\n",
+ Status);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+ VL_VCSEL_PERIOD_FINAL_RANGE, 14);
+ } else {
+ dbg("SetVcselPulsePeriod(PRE, 18) failed err = %d\n",
+ Status);
+ }
+
+ if (Status != VL_ERROR_NONE) {
+ dbg("SetVcselPulsePeriod(FINAL, 14) failed err = %d\n",
+ Status);
+ }
+ } else {
+ dbg("Configure High Accuracy\n");
+ Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+ VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
+ (unsigned int)(25 * 65536 / 100)); /* 0.25 * 65536 */
+ if (Status == VL_ERROR_NONE) {
+ Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev,
+ VL_CHECKENABLE_SIGMA_FINAL_RANGE,
+ (unsigned int)(18*65536));
+ } else {
+ dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n",
+ Status);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ dbg("Set Timing Budget = %u\n",
+ vl53l0x_dev->timingBudget);
+ Status =
+ papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds(
+ vl53l0x_dev, vl53l0x_dev->timingBudget);
+ } else {
+ dbg("SetLimitCheckValue failed err = %d\n",
+ Status);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+ VL_VCSEL_PERIOD_PRE_RANGE, 14);
+ } else {
+ dbg("SetMeasurementTimingBudget failed err = %d\n",
+ Status);
+ }
+
+ if (Status == VL_ERROR_NONE) {
+ Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev,
+ VL_VCSEL_PERIOD_FINAL_RANGE, 10);
+ } else {
+ dbg("SetVcselPulsePeriod failed err = %d\n",
+ Status);
+ }
+
+ if (Status != VL_ERROR_NONE) {
+ dbg("SetVcselPulsePeriod failed err = %d\n",
+ Status);
+ }
+
+ }
+
+ /* start the ranging */
+ papi_func_tbl->StartMeasurement(vl53l0x_dev);
+ data->enable_ps_sensor = 1;
+
+
+ dbg("End\n");
+
+ return rc;
+}
+
+static int stmvl53l0x_stop(struct vl_data *data)
+{
+ int rc = 0;
+ struct vl_data *vl53l0x_dev = data;
+
+ dbg("Enter\n");
+
+ /* stop - if continuous mode */
+ if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_RANGING ||
+ data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING)
+ papi_func_tbl->StopMeasurement(vl53l0x_dev);
+
+ /* clean interrupt */
+ papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0);
+
+ /* cancel work handler */
+ stmvl53l0x_cancel_handler(data);
+ /* power down */
+ rc = pmodule_func_tbl->power_down(data->client_object);
+ if (rc) {
+ err("%d, error rc %d\n", __LINE__, rc);
+ return rc;
+ }
+ dbg("End\n");
+
+ return rc;
+}
+
+/*
+ * I2C init/probing/exit functions
+ */
+static const struct file_operations stmvl53l0x_ranging_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = stmvl53l0x_ioctl,
+ .open = stmvl53l0x_open,
+ .flush = stmvl53l0x_flush,
+};
+
+int stmvl53l0x_setup(struct vl_data *data)
+{
+ int rc = 0;
+
+ dbg("Enter\n");
+
+ /* init mutex */
+ mutex_init(&data->update_lock);
+ mutex_init(&data->work_mutex);
+
+ init_waitqueue_head(&data->poll_thread_wq);
+
+ data->poll_thread = kthread_run(&stmvl53l0x_poll_thread,
+ (void *)data, "STM-VL53L0");
+ if (data->poll_thread == NULL) {
+ dbg("%s(%d) - Failed to create Polling thread\n",
+ __func__, __LINE__);
+ goto exit_free_irq;
+ }
+
+ /* init work handler */
+ INIT_DELAYED_WORK(&data->dwork, stmvl53l0x_work_handler);
+
+ /* Register to Input Device */
+ data->input_dev_ps = input_allocate_device();
+ if (!data->input_dev_ps) {
+ rc = -ENOMEM;
+ err("%d error:%d\n", __LINE__, rc);
+
+ goto exit_free_irq;
+ }
+ set_bit(EV_ABS, data->input_dev_ps->evbit);
+ /* range in cm*/
+ input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 76, 0, 0);
+ /* tv_sec */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT0X, 0, 0xffffffff,
+ 0, 0);
+ /* tv_usec */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT0Y, 0, 0xffffffff,
+ 0, 0);
+ /* range in_mm */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT1X, 0, 765, 0, 0);
+ /* error code change maximum to 0xff for more flexibility */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT1Y, 0, 0xff, 0, 0);
+ /* rtnRate */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT2X, 0, 0xffffffff,
+ 0, 0);
+ /* rtn_amb_rate */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT2Y, 0, 0xffffffff,
+ 0, 0);
+ /* rtn_conv_time */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT3X, 0, 0xffffffff,
+ 0, 0);
+ /* dmax */
+ input_set_abs_params(data->input_dev_ps, ABS_HAT3Y, 0, 0xffffffff,
+ 0, 0);
+
+ input_set_abs_params(data->input_dev_ps, ABS_PRESSURE, 0, 0xffffffff,
+ 0, 0);
+
+ input_set_abs_params(data->input_dev_ps, ABS_WHEEL, 0, 0xffffffff,
+ 0, 0);
+
+ data->input_dev_ps->name = "STM VL53L0 proximity sensor";
+
+ rc = input_register_device(data->input_dev_ps);
+ if (rc) {
+ rc = -ENOMEM;
+ err("%d error:%d\n", __LINE__, rc);
+ goto exit_free_dev_ps;
+ }
+ /* setup drv data */
+ 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) {
+ rc = -ENOMEM;
+ err("%d error:%d\n", __LINE__, rc);
+ goto exit_unregister_dev_ps_1;
+ }
+ /* init default device parameter value */
+ data->enable_ps_sensor = 0;
+ data->reset = 1;
+ data->delay_ms = 30; /* delay time to 30ms */
+ data->enableDebug = 0;
+ data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW;
+ data->gpio_function = VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY;
+ data->low_threshold = 60;
+ data->high_threshold = 200;
+ data->deviceMode = VL_DEVICEMODE_SINGLE_RANGING;
+ data->interMeasurems = 30;
+ data->timingBudget = 26000;
+ data->useLongRange = 1;
+
+ dbg("support ver. %s enabled\n", DRIVER_VERSION);
+ dbg("End");
+
+ 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);
+exit_free_irq:
+ kfree(data);
+ return rc;
+}
+
+static int __init stmvl53l0x_init(void)
+{
+ int ret = -1;
+
+ dbg("Enter\n");
+
+ /* assign function table */
+ pmodule_func_tbl = &stmvl53l0x_module_func_tbl;
+ papi_func_tbl = &stmvl53l0x_api_func_tbl;
+
+ /* client specific init function */
+ ret = pmodule_func_tbl->init();
+
+ if (ret)
+ err("%d failed with %d\n", __LINE__, ret);
+
+ dbg("End\n");
+
+ return ret;
+}
+
+static void __exit stmvl53l0x_exit(void)
+{
+ dbg("Enter\n");
+
+ dbg("End\n");
+}
+
+MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver");
+MODULE_LICENSE("GPL v2");
+
+module_init(stmvl53l0x_init);
+module_exit(stmvl53l0x_exit);
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index af83d2e..a8a96def 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -2538,13 +2538,31 @@
}
static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
- struct alps_data *priv)
+ struct alps_data *priv,
+ struct psmouse *psmouse)
{
bool is_dual = false;
+ int reg_val = 0;
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
- if (IS_SS4PLUS_DEV(priv->dev_id))
+ if (IS_SS4PLUS_DEV(priv->dev_id)) {
is_dual = (otp[0][0] >> 4) & 0x01;
+ if (!is_dual) {
+ /* For support TrackStick of Thinkpad L/E series */
+ if (alps_exit_command_mode(psmouse) == 0 &&
+ alps_enter_command_mode(psmouse) == 0) {
+ reg_val = alps_command_mode_read_reg(psmouse,
+ 0xD7);
+ }
+ alps_exit_command_mode(psmouse);
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+ if (reg_val == 0x0C || reg_val == 0x1D)
+ is_dual = true;
+ }
+ }
+
if (is_dual)
priv->flags |= ALPS_DUALPOINT |
ALPS_DUALPOINT_WITH_PRESSURE;
@@ -2567,7 +2585,7 @@
alps_update_btn_info_ss4_v2(otp, priv);
- alps_update_dual_info_ss4_v2(otp, priv);
+ alps_update_dual_info_ss4_v2(otp, priv, psmouse);
return 0;
}
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index c9d491b..3851d57 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -1082,6 +1082,13 @@
return error;
}
+ /* Make sure there is something at this address */
+ error = i2c_smbus_read_byte(client);
+ if (error < 0) {
+ dev_dbg(&client->dev, "nothing at this address: %d\n", error);
+ return -ENXIO;
+ }
+
/* Initialize the touchpad. */
error = elan_initialize(data);
if (error)
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index a679e56..765879d 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -557,7 +557,14 @@
long ret;
int error;
int len;
- u8 buffer[ETP_I2C_INF_LENGTH];
+ u8 buffer[ETP_I2C_REPORT_LEN];
+
+ len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
+ if (len != ETP_I2C_REPORT_LEN) {
+ error = len < 0 ? len : -EIO;
+ dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
+ error, len);
+ }
reinit_completion(completion);
enable_irq(client->irq);
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 59603a5..c519c0b 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1711,6 +1711,17 @@
etd->samples[0], etd->samples[1], etd->samples[2]);
}
+ if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) {
+ /*
+ * This module has a bug which makes absolute mode
+ * unusable, so let's abort so we'll be using standard
+ * PS/2 protocol.
+ */
+ psmouse_info(psmouse,
+ "absolute mode broken, forcing standard PS/2 protocol\n");
+ goto init_fail;
+ }
+
if (elantech_set_absolute_mode(psmouse)) {
psmouse_err(psmouse,
"failed to put touchpad into absolute mode.\n");
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index b604564..30328e5 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -15,6 +15,7 @@
#define MOUSEDEV_MINORS 31
#define MOUSEDEV_MIX 63
+#include <linux/bitops.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
@@ -103,7 +104,7 @@
spinlock_t packet_lock;
int pos_x, pos_y;
- signed char ps2[6];
+ u8 ps2[6];
unsigned char ready, buffer, bufsiz;
unsigned char imexseq, impsseq;
enum mousedev_emul mode;
@@ -291,11 +292,10 @@
}
client->pos_x += packet->dx;
- client->pos_x = client->pos_x < 0 ?
- 0 : (client->pos_x >= xres ? xres : client->pos_x);
+ client->pos_x = clamp_val(client->pos_x, 0, xres);
+
client->pos_y += packet->dy;
- client->pos_y = client->pos_y < 0 ?
- 0 : (client->pos_y >= yres ? yres : client->pos_y);
+ client->pos_y = clamp_val(client->pos_y, 0, yres);
p->dx += packet->dx;
p->dy += packet->dy;
@@ -571,44 +571,50 @@
return error;
}
-static inline int mousedev_limit_delta(int delta, int limit)
-{
- return delta > limit ? limit : (delta < -limit ? -limit : delta);
-}
-
-static void mousedev_packet(struct mousedev_client *client,
- signed char *ps2_data)
+static void mousedev_packet(struct mousedev_client *client, u8 *ps2_data)
{
struct mousedev_motion *p = &client->packets[client->tail];
+ s8 dx, dy, dz;
- ps2_data[0] = 0x08 |
- ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07);
- ps2_data[1] = mousedev_limit_delta(p->dx, 127);
- ps2_data[2] = mousedev_limit_delta(p->dy, 127);
- p->dx -= ps2_data[1];
- p->dy -= ps2_data[2];
+ dx = clamp_val(p->dx, -127, 127);
+ p->dx -= dx;
+
+ dy = clamp_val(p->dy, -127, 127);
+ p->dy -= dy;
+
+ ps2_data[0] = BIT(3);
+ ps2_data[0] |= ((dx & BIT(7)) >> 3) | ((dy & BIT(7)) >> 2);
+ ps2_data[0] |= p->buttons & 0x07;
+ ps2_data[1] = dx;
+ ps2_data[2] = dy;
switch (client->mode) {
case MOUSEDEV_EMUL_EXPS:
- ps2_data[3] = mousedev_limit_delta(p->dz, 7);
- p->dz -= ps2_data[3];
- ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1);
+ dz = clamp_val(p->dz, -7, 7);
+ p->dz -= dz;
+
+ ps2_data[3] = (dz & 0x0f) | ((p->buttons & 0x18) << 1);
client->bufsiz = 4;
break;
case MOUSEDEV_EMUL_IMPS:
- ps2_data[0] |=
- ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
- ps2_data[3] = mousedev_limit_delta(p->dz, 127);
- p->dz -= ps2_data[3];
+ dz = clamp_val(p->dz, -127, 127);
+ p->dz -= dz;
+
+ ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
+ ((p->buttons & 0x08) >> 1);
+ ps2_data[3] = dz;
+
client->bufsiz = 4;
break;
case MOUSEDEV_EMUL_PS2:
default:
- ps2_data[0] |=
- ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1);
p->dz = 0;
+
+ ps2_data[0] |= ((p->buttons & 0x10) >> 3) |
+ ((p->buttons & 0x08) >> 1);
+
client->bufsiz = 3;
break;
}
@@ -714,7 +720,7 @@
{
struct mousedev_client *client = file->private_data;
struct mousedev *mousedev = client->mousedev;
- signed char data[sizeof(client->ps2)];
+ u8 data[sizeof(client->ps2)];
int retval = 0;
if (!client->ready && !client->buffer && mousedev->exist &&
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index d1051e3..e484ea2 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -530,6 +530,20 @@
{ }
};
+static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = {
+ {
+ /*
+ * Sony Vaio VGN-CS series require MUX or the touch sensor
+ * buttons will disturb touchpad operation
+ */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"),
+ },
+ },
+ { }
+};
+
/*
* On some Asus laptops, just running self tests cause problems.
*/
@@ -693,6 +707,13 @@
},
},
{
+ /* Lenovo ThinkPad L460 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"),
+ },
+ },
+ {
/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Notebook"),
@@ -1223,6 +1244,9 @@
if (dmi_check_system(i8042_dmi_nomux_table))
i8042_nomux = true;
+ if (dmi_check_system(i8042_dmi_forcemux_table))
+ i8042_nomux = false;
+
if (dmi_check_system(i8042_dmi_notimeout_table))
i8042_notimeout = true;
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 25791c2..6c4156a 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -1279,4 +1279,16 @@
If unsure, say N.
+config TOUCHSCREEN_HIMAX_CHIPSET
+ bool "Himax touchpanel CHIPSET"
+ depends on I2C
+ help
+ Say Y here if you have a Himax CHIPSET touchscreen.
+ HIMAX controllers are multi touch controllers which can
+ report 10 touches at a time.
+
+ If unsure, say N.
+
+source "drivers/input/touchscreen/hxchipset/Kconfig"
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 34e8823..a5952ca 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -104,3 +104,4 @@
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_HIMAX_CHIPSET) += hxchipset/
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 240b16f..5907fdd 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -778,8 +778,10 @@
int error;
/* We need gpio pins to suspend/resume */
- if (!ts->gpiod_int || !ts->gpiod_rst)
+ if (!ts->gpiod_int || !ts->gpiod_rst) {
+ disable_irq(client->irq);
return 0;
+ }
wait_for_completion(&ts->firmware_loading_complete);
@@ -819,8 +821,10 @@
struct goodix_ts_data *ts = i2c_get_clientdata(client);
int error;
- if (!ts->gpiod_int || !ts->gpiod_rst)
+ if (!ts->gpiod_int || !ts->gpiod_rst) {
+ enable_irq(client->irq);
return 0;
+ }
/*
* Exit sleep mode by outputting HIGH level to INT pin
diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i
diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i
diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig
new file mode 100644
index 0000000..ebf3aa4
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/Kconfig
@@ -0,0 +1,21 @@
+#
+# Himax Touchscreen driver configuration
+#
+
+config TOUCHSCREEN_HIMAX_I2C
+ tristate "HIMAX chipset i2c touchscreen"
+ depends on TOUCHSCREEN_HIMAX_CHIPSET
+ help
+ This enables support for HIMAX CHIPSET over I2C based touchscreens.
+
+config TOUCHSCREEN_HIMAX_DEBUG
+ tristate "HIMAX debug function"
+ depends on TOUCHSCREEN_HIMAX_I2C
+ help
+ This enables support for HIMAX debug function.
+
+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.
diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile
new file mode 100644
index 0000000..509d491
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/Makefile
@@ -0,0 +1,3 @@
+# Makefile for the Himax touchscreen drivers.
+
+obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o
diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c
new file mode 100644
index 0000000..417b0c0
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_common.c
@@ -0,0 +1,1936 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_common.h"
+#include "himax_ic.h"
+
+#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F
+#define TS_WAKE_LOCK_TIMEOUT (2 * HZ)
+#define FRAME_COUNT 5
+
+#if defined(HX_AUTO_UPDATE_FW)
+ static unsigned char i_CTPM_FW[]=
+ {
+ #include "HX83100_Amber_0901_030B.i"
+ };
+#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
+
+struct himax_ts_data *private_ts;
+struct himax_ic_data* ic_data;
+
+static int HX_TOUCH_INFO_POINT_CNT;
+
+#ifdef HX_AUTO_UPDATE_FW
+extern unsigned long FW_VER_MAJ_FLASH_ADDR;
+extern unsigned long FW_VER_MIN_FLASH_ADDR;
+extern unsigned long CFG_VER_MAJ_FLASH_ADDR;
+extern unsigned long CFG_VER_MIN_FLASH_ADDR;
+#endif
+extern unsigned long FW_VER_MAJ_FLASH_LENG;
+extern unsigned long FW_VER_MIN_FLASH_LENG;
+extern unsigned long CFG_VER_MAJ_FLASH_LENG;
+extern unsigned long CFG_VER_MIN_FLASH_LENG;
+extern unsigned char IC_TYPE;
+extern unsigned char IC_CHECKSUM;
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+extern int himax_touch_proc_init(void);
+extern void himax_touch_proc_deinit(void);
+//PROC-START
+#ifdef HX_TP_PROC_FLASH_DUMP
+extern void himax_ts_flash_func(void);
+extern void setFlashBuffer(void);
+extern bool getFlashDumpGoing(void);
+extern uint8_t getSysOperation(void);
+extern void setSysOperation(uint8_t operation);
+#endif
+
+#ifdef HX_TP_PROC_HITOUCH
+extern bool hitouch_is_connect;
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+ extern int touch_monitor_stop_flag;
+ extern int touch_monitor_stop_limit;
+ extern void himax_ts_diag_func(void);
+ extern int16_t *getMutualBuffer(void);
+ extern int16_t *getMutualNewBuffer(void);
+ extern int16_t *getMutualOldBuffer(void);
+ extern int16_t *getSelfBuffer(void);
+ extern uint8_t getXChannel(void);
+ extern uint8_t getYChannel(void);
+ extern uint8_t getDiagCommand(void);
+ extern void setXChannel(uint8_t x);
+ extern void setYChannel(uint8_t y);
+ extern void setMutualBuffer(void);
+ extern void setMutualNewBuffer(void);
+ extern void setMutualOldBuffer(void);
+ extern uint8_t coordinate_dump_enable;
+ extern struct file *coordinate_fn;
+ extern uint8_t diag_coor[128];
+#ifdef HX_TP_PROC_2T2R
+ extern int16_t *getMutualBuffer_2(void);
+ extern uint8_t getXChannel_2(void);
+ extern uint8_t getYChannel_2(void);
+ extern void setXChannel_2(uint8_t x);
+ extern void setYChannel_2(uint8_t y);
+ extern void setMutualBuffer_2(void);
+#endif
+#endif
+//PROC-END
+#endif
+
+extern int himax_parse_dt(struct himax_ts_data *ts,
+ struct himax_i2c_platform_data *pdata);
+extern int himax_ts_pinctrl_init(struct himax_ts_data *ts);
+
+static uint8_t vk_press;
+static uint8_t AA_press;
+static uint8_t EN_NoiseFilter;
+static uint8_t Last_EN_NoiseFilter;
+static int hx_point_num; // for himax_ts_work_func use
+static int p_point_num = 0xFFFF;
+static int tpd_key;
+static int tpd_key_old;
+static int probe_fail_flag;
+static bool config_load;
+static struct himax_config *config_selected;
+
+//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,
+ unsigned long event, void *data);
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+static void himax_ts_early_suspend(struct early_suspend *h);
+static void himax_ts_late_resume(struct early_suspend *h);
+#endif
+
+int himax_input_register(struct himax_ts_data *ts)
+{
+ int ret;
+ ts->input_dev = input_allocate_device();
+ if (ts->input_dev == NULL) {
+ ret = -ENOMEM;
+ E("%s: Failed to allocate input device\n", __func__);
+ return ret;
+ }
+ ts->input_dev->name = "himax-touchscreen";
+
+ set_bit(EV_SYN, ts->input_dev->evbit);
+ set_bit(EV_ABS, ts->input_dev->evbit);
+ set_bit(EV_KEY, ts->input_dev->evbit);
+
+ set_bit(KEY_BACK, ts->input_dev->keybit);
+ set_bit(KEY_HOME, ts->input_dev->keybit);
+ set_bit(KEY_MENU, ts->input_dev->keybit);
+ set_bit(KEY_SEARCH, ts->input_dev->keybit);
+#if defined(HX_SMART_WAKEUP)
+ set_bit(KEY_POWER, ts->input_dev->keybit);
+ set_bit(KEY_CUST_01, ts->input_dev->keybit);
+ set_bit(KEY_CUST_02, ts->input_dev->keybit);
+ set_bit(KEY_CUST_03, ts->input_dev->keybit);
+ set_bit(KEY_CUST_04, ts->input_dev->keybit);
+ set_bit(KEY_CUST_05, ts->input_dev->keybit);
+ set_bit(KEY_CUST_06, ts->input_dev->keybit);
+ set_bit(KEY_CUST_07, ts->input_dev->keybit);
+ set_bit(KEY_CUST_08, ts->input_dev->keybit);
+ set_bit(KEY_CUST_09, ts->input_dev->keybit);
+ set_bit(KEY_CUST_10, ts->input_dev->keybit);
+ set_bit(KEY_CUST_11, ts->input_dev->keybit);
+ set_bit(KEY_CUST_12, ts->input_dev->keybit);
+ set_bit(KEY_CUST_13, ts->input_dev->keybit);
+ set_bit(KEY_CUST_14, ts->input_dev->keybit);
+ set_bit(KEY_CUST_15, ts->input_dev->keybit);
+#endif
+ set_bit(BTN_TOUCH, ts->input_dev->keybit);
+
+ set_bit(KEY_F10, ts->input_dev->keybit);
+
+ set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
+
+ if (ts->protocol_type == PROTOCOL_TYPE_A) {
+ //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);
+ }
+
+ I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n",
+ ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max);
+
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0);
+ input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0);
+
+// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0);
+// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0);
+
+ return input_register_device(ts->input_dev);
+}
+
+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);
+}
+
+static void calculate_point_number(void)
+{
+ 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 ;
+ else
+ HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ;
+}
+
+#if 0
+static int himax_read_Sensor_ID(struct i2c_client *client)
+{
+ 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
+ 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);
+
+ //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*/
+ else
+ ID0=0x04;/*VCC*/
+
+ if((val_high[0] & 0x02) ==0)
+ ID1=0x02;/*GND*/
+ else if((val_low[0] & 0x02) ==0)
+ ID1=0x01;/*Floating*/
+ else
+ ID1=0x04;/*VCC*/
+ if((ID0==0x04)&&(ID1!=0x04))
+ {
+ data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/
+ i2c_himax_master_write(client, &data[0],3,normalRetry);
+ usleep_range(1000, 2000);
+
+ }
+ else if((ID0!=0x04)&&(ID1==0x04))
+ {
+ data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/
+ i2c_himax_master_write(client, &data[0],3,normalRetry);
+ usleep_range(1000, 2000);
+
+ }
+ 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);
+
+ }
+ 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);
+
+ return sensor_id;
+
+}
+#endif
+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
+}
+
+#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 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 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];
+
+ 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);
+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);
+*/
+ 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__);
+ }
+
+ himax_int_enable(private_ts->client->irq,1);
+ return result;
+ }
+ else
+ {
+ himax_sense_on(private_ts->client, 0x01);
+ return 0;//NO upgrade
+ }
+}
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+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);
+ }
+ }
+
+ I("%s: Now reset the Touch chip.\n", __func__);
+
+ himax_rst_gpio_set(ts->rst_gpio, 0);
+ msleep(20);
+ himax_rst_gpio_set(ts->rst_gpio, 1);
+ msleep(20);
+
+ 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);
+ }
+ }
+}
+#endif
+
+int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata)
+{
+
+ if (!client) {
+ E("%s: Necessary parameters client are null!\n", __func__);
+ return -EINVAL;
+ }
+
+ 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;
+ }
+ }
+
+ himax_power_on_initCMD(client);
+
+ himax_int_enable(client->irq,0);
+ himax_read_FW_ver(client);
+#ifdef HX_RST_PIN_FUNC
+ himax_HW_reset(true,false);
+#endif
+ 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);
+
+ himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM
+ msleep(120);
+#ifdef HX_ESD_WORKAROUND
+ HX_ESD_RESET_ACTIVATE = 1;
+#endif
+ I("%s: initialization complete\n", __func__);
+
+ return 1;
+}
+
+#ifdef HX_ESD_WORKAROUND
+void ESD_HW_REST(void)
+{
+ 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)
+ input_mt_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)
+{
+ uint8_t tmp_data[4];
+
+ if(HSEN_enable)
+ {
+ I(" %s in", __func__);
+ 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;
+ }
+ }
+}
+
+static void himax_HSEN_func(struct work_struct *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);
+}
+
+#endif
+
+#ifdef HX_SMART_WAKEUP
+#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;
+}
+#endif
+static int himax_parse_wake_event(struct himax_ts_data *ts)
+{
+ uint8_t buf[64];
+ unsigned char check_sum_cal = 0;
+#ifdef HX_GESTURE_TRACK
+ int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF;
+ int gest_len;
+#endif
+ int i=0, check_FC = 0, gesture_flag = 0;
+
+ himax_burst_enable(ts->client, 0);
+ 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)))
+ {
+ check_FC = 1;
+ gesture_flag = buf[i];
+ }
+ else
+ {
+ check_FC = 0;
+ I("ID START at %x , value = %x skip the event\n", i, buf[i]);
+ break;
+ }
+ }
+ 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);
+ break;
+ }
+ }
+
+ I("0x%2.2X ", buf[i]);
+ if (i % 8 == 7)
+ I("\n");
+ }
+ 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)
+ 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);
+ check_sum_cal += buf[i];
+ }
+ 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);
+
+ 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++;
+
+ 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;
+ }
+ 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
+
+ }
+
+ }
+#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)
+ return EV_GESTURE_PWR;
+ else
+ return gesture_flag;
+}
+
+void himax_wake_check_func(void)
+{
+ int ret_event = 0, KEY_EVENT = 0;
+
+ ret_event = himax_parse_wake_event(private_ts);
+ switch (ret_event) {
+ case EV_GESTURE_PWR:
+ KEY_EVENT = KEY_POWER;
+ break;
+ case EV_GESTURE_01:
+ KEY_EVENT = KEY_CUST_01;
+ break;
+ case EV_GESTURE_02:
+ KEY_EVENT = KEY_CUST_02;
+ break;
+ case EV_GESTURE_03:
+ KEY_EVENT = KEY_CUST_03;
+ break;
+ case EV_GESTURE_04:
+ KEY_EVENT = KEY_CUST_04;
+ break;
+ case EV_GESTURE_05:
+ KEY_EVENT = KEY_CUST_05;
+ break;
+ case EV_GESTURE_06:
+ KEY_EVENT = KEY_CUST_06;
+ break;
+ case EV_GESTURE_07:
+ KEY_EVENT = KEY_CUST_07;
+ break;
+ case EV_GESTURE_08:
+ KEY_EVENT = KEY_CUST_08;
+ break;
+ case EV_GESTURE_09:
+ KEY_EVENT = KEY_CUST_09;
+ break;
+ case EV_GESTURE_10:
+ KEY_EVENT = KEY_CUST_10;
+ break;
+ case EV_GESTURE_11:
+ KEY_EVENT = KEY_CUST_11;
+ break;
+ case EV_GESTURE_12:
+ KEY_EVENT = KEY_CUST_12;
+ break;
+ case EV_GESTURE_13:
+ KEY_EVENT = KEY_CUST_13;
+ break;
+ case EV_GESTURE_14:
+ KEY_EVENT = KEY_CUST_14;
+ break;
+ 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;
+#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]);
+#endif
+ }
+}
+
+#endif
+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) {
+ 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);
+ }
+ }
+ 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);
+ }
+ }
+ 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);
+ }
+ }
+ else
+ input_report_key(ts->input_dev, KEY_F10, 1);
+ }
+ input_sync(ts->input_dev);
+ }
+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) {
+ input_mt_slot(ts->input_dev, 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);
+ }
+}
+
+void himax_ts_work(struct himax_ts_data *ts)
+{
+ int ret = 0;
+ uint8_t finger_num, hw_reset_check[2];
+ uint8_t buf[128];
+ uint8_t finger_on = 0;
+ int32_t loop_i;
+ uint16_t check_sum_cal = 0;
+ 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;
+
+#ifdef HX_TP_PROC_DIAG
+ int16_t *mutual_data;
+ int16_t *self_data;
+ uint8_t diag_cmd;
+ 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
+#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;
+
+#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;
+ }
+
+#ifdef HX_TP_PROC_DIAG
+ diag_cmd = getDiagCommand();
+ if( diag_cmd ){
+ ret = read_event_stack(ts->client, buf, 128);
+ }
+ 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);
+ }
+ }
+
+ 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;
+ }
+ 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*/
+ {
+ check_sum_cal = 1;
+
+ }else if(buf[i] == 0x00)
+ {
+ ESD_00_Flag = 1;
+ }
+ else
+ {
+ check_sum_cal = 0;
+ ESD_00_counter = 0;
+ ESD_00_Flag = 0;
+ i = hx_touch_info_size;
+ break;
+ }
+ }
+ 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");
+ 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));
+#endif
+#ifdef HX_HIGH_SENSE
+ 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__);
+ }
+#endif
+ 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);
+ 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++) {
+ I("P %d = 0x%2.2X ", loop_i, buf[loop_i]);
+ if (loop_i % 8 == 7)
+ I("\n");
+ }
+ }
+
+ //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))
+ {
+ 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
+ mul_num = getXChannel_2() * getYChannel_2();
+
+#ifdef HX_EN_SEL_BUTTON
+ self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM;
+#else
+ self_num = getXChannel_2() + getYChannel_2();
+#endif
+ }
+ else
+#endif
+ {
+ mutual_data = getMutualBuffer();
+ self_data = getSelfBuffer();
+
+ // 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;
+#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);
+
+ }
+ 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_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 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);
+
+#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 = 0x00;
+#endif
+
+ p_point_num = hx_point_num;
+
+ if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff)
+ hx_point_num = 0;
+ else
+ hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f;
+
+ // Touch Point information
+ if (hx_point_num != 0 ) {
+ if(vk_press == 0x00)
+ {
+ uint16_t old_finger = ts->pre_finger_mask;
+ ts->pre_finger_mask = 0;
+ finger_num = buf[coordInfoSize - 4] & 0x0F;
+ finger_on = 1;
+ AA_press = 1;
+ for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
+ int base = loop_i * 4;
+ int x = buf[base] << 8 | buf[base + 1];
+ int y = (buf[base + 2] << 8 | buf[base + 3]);
+ int w = buf[(ts->nFinger_support * 4) + loop_i];
+ if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){
+ finger_num--;
+
+ if ((ts->debug_log_level & BIT(3)) > 0)
+ {
+ if (old_finger >> loop_i == 0)
+ {
+ if (ts->useScreenRes)
+ {
+ I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n",
+ loop_i+1, x * ts->widthFactor >> SHIFTBITS,
+ y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter);
+ }
+ else
+ {
+ I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n",
+ loop_i+1, x, y, w, EN_NoiseFilter);
+ }
+ }
+ }
+
+ if (ts->protocol_type == PROTOCOL_TYPE_B)
+ {
+ input_mt_slot(ts->input_dev, loop_i);
+ }
+
+ input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w);
+ input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
+ input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);
+
+ if (ts->protocol_type == PROTOCOL_TYPE_A)
+ {
+ input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i);
+ input_mt_sync(ts->input_dev);
+ }
+ else
+ {
+ ts->last_slot = loop_i;
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1);
+ }
+
+ if (!ts->first_pressed)
+ {
+ ts->first_pressed = 1;
+ I("S1@%d, %d\n", x, y);
+ }
+
+ ts->pre_finger_data[loop_i][0] = x;
+ ts->pre_finger_data[loop_i][1] = y;
+
+
+ if (ts->debug_log_level & BIT(1))
+ I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n",
+ loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter);
+
+ ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i);
+
+ } else {
+ if (ts->protocol_type == PROTOCOL_TYPE_B)
+ {
+ input_mt_slot(ts->input_dev, loop_i);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+ }
+
+ if (loop_i == 0 && ts->first_pressed == 1)
+ {
+ ts->first_pressed = 2;
+ I("E1@%d, %d\n",
+ ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]);
+ }
+ if ((ts->debug_log_level & BIT(3)) > 0)
+ {
+ if (old_finger >> loop_i == 1)
+ {
+ if (ts->useScreenRes)
+ {
+ I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n",
+ loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS,
+ ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter);
+ }
+ else
+ {
+ I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",
+ loop_i+1, ts->pre_finger_data[loop_i][0],
+ ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter);
+ }
+ }
+ }
+ }
+ }
+
+ }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;
+ }
+ input_report_key(ts->input_dev, BTN_TOUCH, finger_on);
+ input_sync(ts->input_dev);
+ } else if (hx_point_num == 0){
+ if(AA_press)
+ {
+ // leave event
+ finger_on = 0;
+ AA_press = 0;
+ if (ts->protocol_type == PROTOCOL_TYPE_A)
+ input_mt_sync(ts->input_dev);
+
+ for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
+ if (((ts->pre_finger_mask >> loop_i) & 1) == 1) {
+ if (ts->protocol_type == PROTOCOL_TYPE_B) {
+ input_mt_slot(ts->input_dev, loop_i);
+ input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
+ }
+ }
+ }
+ if (ts->pre_finger_mask > 0) {
+ for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) {
+ if (((ts->pre_finger_mask >> loop_i) & 1) == 1) {
+ if (ts->useScreenRes) {
+ I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS,
+ ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter);
+ } else {
+ I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter);
+ }
+ }
+ }
+ ts->pre_finger_mask = 0;
+ }
+
+ if (ts->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");
+
+ }
+ 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;
+
+workqueue_out:
+ return;
+
+err_workqueue_out:
+ I("%s: Now reset the Touch chip.\n", __func__);
+
+#ifdef HX_RST_PIN_FUNC
+ himax_HW_reset(true,false);
+#endif
+
+ goto workqueue_out;
+}
+enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer)
+{
+ struct himax_ts_data *ts;
+
+ ts = container_of(timer, struct himax_ts_data, timer);
+ queue_work(ts->himax_wq, &ts->work);
+ hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
+ return HRTIMER_NORESTART;
+}
+
+#if defined(HX_USB_DETECT)
+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) {
+ if (!atomic_read(&ts->suspend_mode)) {
+ if ((!!connect_status) != ts->usb_connected) {
+ if (!!connect_status) {
+ ts->cable_config[1] = 0x01;
+ ts->usb_connected = 0x01;
+ } else {
+ ts->cable_config[1] = 0x00;
+ ts->usb_connected = 0x00;
+ }
+
+ 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]);
+ } else
+ I("%s: Cable status is the same as previous one, 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);
+ }
+ }
+}
+
+static struct t_cable_status_notifier himax_cable_status_handler = {
+ .name = "usb_tp_connected",
+ .func = himax_cable_tp_status_handler_func,
+};
+
+#endif
+
+#if defined(HX_USB_DETECT2)
+void himax_cable_detect_func(void)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[128];
+ struct himax_ts_data *ts;
+ u32 connect_status = 0;
+
+ 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);
+ 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;
+
+ if (!!connect_status) {
+ tmp_data[0] = 0x01;
+ ts->usb_connected = 0x01;
+ } else {
+ tmp_data[0] = 0x00;
+ ts->usb_connected = 0x00;
+ }
+
+ 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__);
+ }
+}
+#endif
+
+#ifdef CONFIG_FB
+int himax_fb_register(struct himax_ts_data *ts)
+{
+ int ret = 0;
+
+ I(" %s in", __func__);
+ ts->fb_notif.notifier_call = fb_notifier_callback;
+ ret = fb_register_client(&ts->fb_notif);
+ if (ret)
+ E(" Unable to register fb_notifier: %d\n", ret);
+
+ return ret;
+}
+#endif
+
+#ifdef HX_SMART_WAKEUP
+void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable)
+{
+ uint8_t tmp_data[4];
+
+ 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;
+ }
+ }
+}
+
+static void himax_SMWP_work(struct work_struct *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);
+
+}
+#endif
+
+#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
+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)
+{
+ int ret = 0, err = 0;
+ struct himax_i2c_platform_data *pdata;
+ struct i2c_client *client;
+
+ client = ts->client;
+ pdata = ts->pdata;
+
+ I("%s: Start.\n", __func__);
+
+ /* 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);
+ }
+ }
+
+ himax_burst_enable(client, 0);
+
+ //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;
+ }
+ if (himax_ic_package_check(ts->client) == false) {
+ E("Himax chip doesn NOT EXIST");
+ goto err_ic_package_failed;
+ }
+
+ if (pdata->virtual_key)
+ ts->button = pdata->virtual_key;
+#ifdef HX_TP_PROC_FLASH_DUMP
+ ts->flash_wq = create_singlethread_workqueue("himax_flash_wq");
+ if (!ts->flash_wq)
+ {
+ E("%s: create flash workqueue failed\n", __func__);
+ err = -ENOMEM;
+ goto err_create_wq_failed;
+ }
+
+ INIT_WORK(&ts->flash_work, himax_ts_flash_work_func);
+
+ setSysOperation(0);
+ setFlashBuffer();
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+ ts->himax_diag_wq = create_singlethread_workqueue("himax_diag");
+ if (!ts->himax_diag_wq)
+ {
+ E("%s: create diag workqueue failed\n", __func__);
+ err = -ENOMEM;
+ goto err_create_wq_failed;
+ }
+ INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func);
+#endif
+
+himax_read_FW_ver(client);
+
+#ifdef HX_AUTO_UPDATE_FW
+ I(" %s in", __func__);
+ if(i_update_FW() == false)
+ I("NOT Have new FW=NOT UPDATE=\n");
+ else
+ I("Have new FW=UPDATE=\n");
+#endif
+
+ //Himax Power On and Load Config
+ if (himax_loadSensorConfig(client, pdata) < 0) {
+ E("%s: Load Sesnsor configuration 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
+
+ setMutualBuffer();
+ setMutualNewBuffer();
+ setMutualOldBuffer();
+ if (getMutualBuffer() == NULL) {
+ E("%s: mutual buffer allocate fail failed\n", __func__);
+ return;
+ }
+#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
+
+ setMutualBuffer_2();
+
+ if (getMutualBuffer_2() == NULL) {
+ E("%s: mutual buffer 2 allocate fail failed\n", __func__);
+ return;
+ }
+ }
+#endif
+#endif
+#ifdef CONFIG_OF
+ ts->power = pdata->power;
+#endif
+ ts->pdata = pdata;
+
+ 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
+ calcDataSize(ts->nFinger_support);
+ I("%s: calcDataSize complete\n", __func__);
+#ifdef CONFIG_OF
+ ts->pdata->abs_pressure_min = 0;
+ ts->pdata->abs_pressure_max = 200;
+ ts->pdata->abs_width_min = 0;
+ ts->pdata->abs_width_max = 200;
+ pdata->cable_config[0] = 0x90;
+ pdata->cable_config[1] = 0x00;
+#endif
+ ts->suspended = false;
+#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",
+ __func__, ts->input_dev->name);
+ 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->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK");
+ if (!ts->himax_smwp_wq) {
+ E(" allocate himax_smwp_wq failed\n");
+ err = -ENOMEM;
+ goto err_smwp_wq_failed;
+ }
+ INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work);
+#endif
+#ifdef HX_HIGH_SENSE
+ 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");
+ err = -ENOMEM;
+ goto err_hsen_wq_failed;
+ }
+ INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func);
+#endif
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+ himax_touch_proc_init();
+#endif
+
+#if defined(HX_USB_DETECT)
+ if (ts->cable_config)
+ cable_detect_register_notifier(&himax_cable_status_handler);
+#endif
+
+ err = himax_ts_register_interrupt(ts->client);
+ if (err)
+ goto err_register_interrupt_failed;
+ return;
+
+err_register_interrupt_failed:
+#ifdef HX_HIGH_SENSE
+err_hsen_wq_failed:
+#endif
+#ifdef HX_SMART_WAKEUP
+err_smwp_wq_failed:
+ wake_lock_destroy(&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
+err_create_wq_failed:
+#endif
+err_ic_package_failed:
+
+return;
+}
+
+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
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ E("%s: i2c check functionality error\n", __func__);
+ err = -ENODEV;
+ goto err_check_functionality_failed;
+ }
+
+ ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL);
+ if (ts == NULL) {
+ E("%s: allocate himax_ts_data failed\n", __func__);
+ err = -ENOMEM;
+ goto err_alloc_data_failed;
+ }
+
+ i2c_set_clientdata(client, ts);
+ ts->client = client;
+ ts->dev = &client->dev;
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (pdata == NULL) { /*Allocate Platform data space*/
+ err = -ENOMEM;
+ goto err_dt_platform_data_fail;
+ }
+
+ ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL);
+ if (ic_data == NULL) { /*Allocate IC data space*/
+ err = -ENOMEM;
+ goto err_dt_ic_data_fail;
+ }
+
+#ifdef CONFIG_OF
+ if (client->dev.of_node) { /*DeviceTree Init Platform_data*/
+ err = himax_parse_dt(ts, pdata);
+ if (err < 0) {
+ I(" pdata is NULL for DT\n");
+ goto err_alloc_dt_pdata_failed;
+ }
+ }
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+ ts->rst_gpio = pdata->gpio_reset;
+#endif
+
+himax_gpio_power_config(ts->client, pdata);
+
+ err = himax_ts_pinctrl_init(ts);
+ if (err || ts->ts_pinctrl == NULL) {
+ E(" Pinctrl init failed\n");
+ }
+
+#ifndef CONFIG_OF
+ if (pdata->power) {
+ err = pdata->power(1);
+ if (err < 0) {
+ E("%s: power on failed\n", __func__);
+ goto err_power_failed;
+ }
+ }
+#endif
+ ts->pdata = pdata;
+ private_ts = ts;
+
+ mutex_init(&ts->fb_mutex);
+ /* ts initialization is deferred till FB_UNBLACK event;
+ * probe is considered pending till then.*/
+ ts->probe_done = false;
+#ifdef CONFIG_FB
+ err = himax_fb_register(ts);
+ if (err) {
+ E("Falied to register fb notifier\n");
+ err = -ENOMEM;
+ goto err_fb_notif_wq_create;
+ }
+#endif
+
+ return 0;
+
+#ifdef CONFIG_FB
+err_fb_notif_wq_create:
+#endif
+#ifdef CONFIG_OF
+err_alloc_dt_pdata_failed:
+#else
+err_power_failed:
+err_get_platform_data_fail:
+#endif
+ if (ts->ts_pinctrl) {
+ if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) {
+ devm_pinctrl_put(ts->ts_pinctrl);
+ ts->ts_pinctrl = NULL;
+ } else {
+ err = pinctrl_select_state(ts->ts_pinctrl,
+ ts->pinctrl_state_release);
+ if (err)
+ E("failed to select relase pinctrl state %d\n",
+ err);
+ }
+ }
+ kfree(ic_data);
+
+err_dt_ic_data_fail:
+ kfree(pdata);
+
+err_dt_platform_data_fail:
+ kfree(ts);
+
+err_alloc_data_failed:
+
+err_check_functionality_failed:
+ probe_fail_flag = 1;
+ return err;
+
+}
+
+int himax_chip_common_remove(struct i2c_client *client)
+{
+ struct himax_ts_data *ts = i2c_get_clientdata(client);
+ int ret;
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+ 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");
+#endif
+
+ if (!ts->use_irq)
+ hrtimer_cancel(&ts->timer);
+
+ destroy_workqueue(ts->himax_wq);
+
+ if (ts->protocol_type == PROTOCOL_TYPE_B)
+ input_mt_destroy_slots(ts->input_dev);
+
+ input_unregister_device(ts->input_dev);
+
+ if (ts->ts_pinctrl) {
+ if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) {
+ devm_pinctrl_put(ts->ts_pinctrl);
+ ts->ts_pinctrl = NULL;
+ } else {
+ ret = pinctrl_select_state(ts->ts_pinctrl,
+ ts->pinctrl_state_release);
+ if (ret)
+ E("failed to select relase pinctrl state %d\n",
+ ret);
+ }
+ }
+#ifdef HX_SMART_WAKEUP
+ wake_lock_destroy(&ts->ts_SMWP_wake_lock);
+#endif
+ kfree(ts);
+
+ return 0;
+
+}
+
+int himax_chip_common_suspend(struct himax_ts_data *ts)
+{
+ int ret;
+
+ if(ts->suspended)
+ {
+ I("%s: Already suspended. Skipped. \n", __func__);
+ return 0;
+ }
+ else
+ {
+ ts->suspended = true;
+ I("%s: enter \n", __func__);
+ }
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+ 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__);
+ return 0;
+ }
+#endif
+#ifdef HX_SMART_WAKEUP
+ 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__);
+ return 0;
+ }
+#endif
+#ifdef HX_ESD_WORKAROUND
+ ESD_00_counter = 0;
+ ESD_00_Flag = 0;
+#endif
+ if (!ts->use_irq) {
+ ret = cancel_work_sync(&ts->work);
+ if (ret)
+ himax_int_enable(ts->client->irq,1);
+ }
+
+ //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) {
+ E("Failed to get idle pinctrl state %d\n", ret);
+ }
+ }
+
+ if (ts->pdata->powerOff3V3 && ts->pdata->power)
+ ts->pdata->power(0);
+
+ return 0;
+}
+
+int himax_chip_common_resume(struct himax_ts_data *ts)
+{
+ int retval;
+
+ 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_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);
+ if (retval < 0) {
+ E("Cannot get default pinctrl state %d\n", retval);
+ goto err_pinctrl_select_resume;
+ }
+ }
+
+ atomic_set(&ts->suspend_mode, 0);
+
+ himax_int_enable(ts->client->irq,1);
+
+ ts->suspended = false;
+#if defined(HX_USB_DETECT2)
+ ts->usb_connected = 0x00;
+ himax_cable_detect_func();
+#endif
+#ifdef HX_SMART_WAKEUP
+ 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));
+#endif
+ return 0;
+err_pinctrl_select_resume:
+ if (ts->pdata->powerOff3V3 && ts->pdata->power)
+ ts->pdata->power(0);
+ return retval;
+}
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h
new file mode 100644
index 0000000..27ce9aa
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_common.h
@@ -0,0 +1,395 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#ifndef HIMAX_COMMON_H
+#define HIMAX_COMMON_H
+
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/async.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/input/mt.h>
+#include <linux/firmware.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#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>
+#include <linux/fb.h>
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+#include <linux/earlysuspend.h>
+#endif
+
+#ifdef CONFIG_OF
+#include <linux/of_gpio.h>
+#endif
+#define HIMAX_DRIVER_VER "0.2.4.0"
+
+#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin"
+#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv"
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+
+#define HX_TP_PROC_DIAG
+#define HX_TP_PROC_REGISTER
+#define HX_TP_PROC_DEBUG
+#define HX_TP_PROC_FLASH_DUMP
+#define HX_TP_PROC_SELF_TEST
+#define HX_TP_PROC_RESET
+#define HX_TP_PROC_SENSE_ON_OFF
+//#define HX_TP_PROC_2T2R
+
+int himax_touch_proc_init(void);
+void himax_touch_proc_deinit(void);
+#endif
+
+//===========Himax Option function=============
+//#define HX_RST_PIN_FUNC
+//#define HX_AUTO_UPDATE_FW
+//#define HX_HIGH_SENSE
+//#define HX_SMART_WAKEUP
+//#define HX_USB_DETECT
+//#define HX_ESD_WORKAROUND
+//#define HX_USB_DETECT2
+
+//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close
+#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close
+
+#define HX_KEY_MAX_COUNT 4
+#define DEFAULT_RETRY_CNT 3
+
+#define HX_VKEY_0 KEY_BACK
+#define HX_VKEY_1 KEY_HOME
+#define HX_VKEY_2 KEY_RESERVED
+#define HX_VKEY_3 KEY_RESERVED
+#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3}
+
+#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
+
+struct himax_ic_data {
+ int vendor_fw_ver;
+ int vendor_config_ver;
+ int vendor_sensor_id;
+ int HX_RX_NUM;
+ int HX_TX_NUM;
+ int HX_BT_NUM;
+ int HX_X_RES;
+ int HX_Y_RES;
+ int HX_MAX_PT;
+ bool HX_XY_REVERSE;
+ bool HX_INT_IS_EDGE;
+#ifdef HX_TP_PROC_2T2R
+ int HX_RX_NUM_2;
+ int HX_TX_NUM_2;
+#endif
+};
+
+struct himax_virtual_key {
+ int index;
+ int keycode;
+ int x_range_min;
+ int x_range_max;
+ int y_range_min;
+ int y_range_max;
+};
+
+struct himax_config {
+ uint8_t default_cfg;
+ uint8_t sensor_id;
+ uint8_t fw_ver;
+ uint16_t length;
+ uint32_t tw_x_min;
+ uint32_t tw_x_max;
+ uint32_t tw_y_min;
+ uint32_t tw_y_max;
+ uint32_t pl_x_min;
+ uint32_t pl_x_max;
+ uint32_t pl_y_min;
+ uint32_t pl_y_max;
+ uint8_t c1[11];
+ uint8_t c2[11];
+ uint8_t c3[11];
+ uint8_t c4[11];
+ uint8_t c5[11];
+ uint8_t c6[11];
+ uint8_t c7[11];
+ uint8_t c8[11];
+ uint8_t c9[11];
+ uint8_t c10[11];
+ uint8_t c11[11];
+ uint8_t c12[11];
+ uint8_t c13[11];
+ uint8_t c14[11];
+ uint8_t c15[11];
+ uint8_t c16[11];
+ uint8_t c17[11];
+ uint8_t c18[17];
+ uint8_t c19[15];
+ uint8_t c20[5];
+ uint8_t c21[11];
+ uint8_t c22[4];
+ uint8_t c23[3];
+ uint8_t c24[3];
+ uint8_t c25[4];
+ uint8_t c26[2];
+ uint8_t c27[2];
+ uint8_t c28[2];
+ uint8_t c29[2];
+ uint8_t c30[2];
+ uint8_t c31[2];
+ uint8_t c32[2];
+ uint8_t c33[2];
+ uint8_t c34[2];
+ uint8_t c35[3];
+ uint8_t c36[5];
+ uint8_t c37[5];
+ uint8_t c38[9];
+ uint8_t c39[14];
+ uint8_t c40[159];
+ uint8_t c41[99];
+};
+
+struct himax_ts_data {
+ bool suspended;
+ bool probe_done;
+ struct mutex fb_mutex;
+ 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;
+ uint8_t area_data_size;
+ uint8_t raw_data_frame_size;
+ uint8_t raw_data_nframes;
+ 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;
+ uint32_t tw_x_min;
+ uint32_t tw_x_max;
+ uint32_t tw_y_min;
+ uint32_t tw_y_max;
+ uint32_t pl_x_min;
+ 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_virtual_key *button;
+
+#if defined(CONFIG_FB)
+ struct notifier_block fb_notif;
+#elif defined(CONFIG_HAS_EARLYSUSPEND)
+ struct early_suspend early_suspend;
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+ struct workqueue_struct *flash_wq;
+ struct work_struct flash_work;
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+ int rst_gpio;
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+ struct workqueue_struct *himax_diag_wq;
+ struct delayed_work himax_diag_delay_wrok;
+#endif
+#ifdef HX_SMART_WAKEUP
+ uint8_t SMWP_enable;
+ uint8_t gesture_cust_en[16];
+ struct wake_lock ts_SMWP_wake_lock;
+ struct workqueue_struct *himax_smwp_wq;
+ struct delayed_work smwp_work;
+#endif
+
+#ifdef HX_HIGH_SENSE
+ uint8_t HSEN_enable;
+ struct workqueue_struct *himax_hsen_wq;
+ struct delayed_work hsen_work;
+#endif
+
+#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2)
+ uint8_t usb_connected;
+ uint8_t *cable_config;
+#endif
+
+ /* pinctrl data */
+ struct pinctrl *ts_pinctrl;
+ struct pinctrl_state *pinctrl_state_active;
+ struct pinctrl_state *pinctrl_state_suspend;
+ 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_MANUALMODE 0x42
+#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_SECTOR_ERASE 0x4E
+#define HX_CMD_CB 0xCB
+#define HX_CMD_EA 0xEA
+#define HX_CMD_4A 0x4A
+#define HX_CMD_4F 0x4F
+#define HX_CMD_B9 0xB9
+#define HX_CMD_76 0x76
+
+enum input_protocol_type {
+ PROTOCOL_TYPE_A = 0x00,
+ PROTOCOL_TYPE_B = 0x01,
+};
+
+#ifdef HX_HIGH_SENSE
+void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable);
+#endif
+
+#ifdef HX_SMART_WAKEUP
+#define GEST_PTLG_ID_LEN (4)
+#define GEST_PTLG_HDR_LEN (4)
+#define GEST_PTLG_HDR_ID1 (0xCC)
+#define GEST_PTLG_HDR_ID2 (0x44)
+#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 gn_gesture_coor[16];
+#endif
+
+void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable);
+extern bool FAKE_POWER_KEY_SEND;
+
+ enum gesture_event_type {
+ EV_GESTURE_01 = 0x01,
+ EV_GESTURE_02,
+ EV_GESTURE_03,
+ EV_GESTURE_04,
+ EV_GESTURE_05,
+ EV_GESTURE_06,
+ EV_GESTURE_07,
+ EV_GESTURE_08,
+ EV_GESTURE_09,
+ EV_GESTURE_10,
+ EV_GESTURE_11,
+ EV_GESTURE_12,
+ EV_GESTURE_13,
+ EV_GESTURE_14,
+ EV_GESTURE_15,
+ EV_GESTURE_PWR = 0x80,
+ };
+
+#define KEY_CUST_01 251
+#define KEY_CUST_02 252
+#define KEY_CUST_03 253
+#define KEY_CUST_04 254
+#define KEY_CUST_05 255
+#define KEY_CUST_06 256
+#define KEY_CUST_07 257
+#define KEY_CUST_08 258
+#define KEY_CUST_09 259
+#define KEY_CUST_10 260
+#define KEY_CUST_11 261
+#define KEY_CUST_12 262
+#define KEY_CUST_13 263
+#define KEY_CUST_14 264
+#define KEY_CUST_15 265
+#endif
+
+#ifdef HX_ESD_WORKAROUND
+ extern u8 HX_ESD_RESET_ACTIVATE;
+#endif
+
+extern int irq_enable_count;
+
+#ifdef QCT
+irqreturn_t himax_ts_thread(int irq, void *ptr);
+int himax_input_register(struct himax_ts_data *ts);
+#endif
+
+extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id);
+extern int himax_chip_common_remove(struct i2c_client *client);
+extern int himax_chip_common_suspend(struct himax_ts_data *ts);
+extern int himax_chip_common_resume(struct himax_ts_data *ts);
+int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata);
+
+#ifdef HX_USB_DETECT2
+//extern kal_bool upmu_is_chr_det(void);
+void himax_cable_detect_func(void);
+#endif
+
+#endif
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c
new file mode 100644
index 0000000..f8bee11
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_debug.c
@@ -0,0 +1,2329 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "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
+
+#ifdef HX_TP_PROC_DIAG
+#ifdef HX_TP_PROC_2T2R
+int HX_RX_NUM_2 = 0;
+int HX_TX_NUM_2 = 0;
+#endif
+int touch_monitor_stop_flag = 0;
+int touch_monitor_stop_limit = 5;
+uint8_t g_diag_arr_num = 0;
+#endif
+
+#ifdef HX_ESD_WORKAROUND
+u8 HX_ESD_RESET_ACTIVATE;
+#endif
+
+#ifdef HX_SMART_WAKEUP
+bool FAKE_POWER_KEY_SEND;
+#endif
+
+//=============================================================================================================
+//
+// Segment : Himax PROC Debug Function
+//
+//=============================================================================================================
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+
+static ssize_t himax_vendor_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ ssize_t ret = 0;
+ char *temp_buf;
+
+ if(!HX_PROC_SEND_FLAG)
+ {
+ temp_buf = kzalloc(len, GFP_KERNEL);
+ if (!temp_buf) {
+ HX_PROC_SEND_FLAG=0;
+ return ret;
+ }
+
+ ret += snprintf(temp_buf, len, "%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;
+
+ if (copy_to_user(buf, temp_buf, len))
+ {
+ I("%s,here:%d\n", __func__, __LINE__);
+ }
+
+ kfree(temp_buf);
+ }
+ else
+ HX_PROC_SEND_FLAG=0;
+
+ return ret;
+}
+
+static const struct file_operations himax_proc_vendor_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_vendor_read,
+};
+
+static ssize_t himax_attn_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ ssize_t ret = 0;
+ struct himax_ts_data *ts_data;
+ 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, "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;
+
+ return ret;
+}
+
+
+static const struct file_operations himax_proc_attn_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_attn_read,
+};
+
+static ssize_t himax_int_en_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ size_t ret = 0;
+ char *temp_buf;
+
+ if (!HX_PROC_SEND_FLAG) {
+ temp_buf = kzalloc(len, GFP_KERNEL);
+ if (!temp_buf) {
+ HX_PROC_SEND_FLAG=0;
+ return ret;
+ }
+ ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled);
+ ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+ 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;
+ return ret;
+}
+
+static ssize_t himax_int_en_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ char buf_tmp[12]= {0};
+ int value, ret=0;
+
+ 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;
+ else if (buf_tmp[0] == '1')
+ value = true;
+ else
+ return -EINVAL;
+
+ if (value) {
+ if(ic_data->HX_INT_IS_EDGE)
+ {
+#ifdef MTK
+#ifdef CONFIG_OF_TOUCH
+ 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);
+#endif
+#endif
+#ifdef QCT
+ ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts);
+#endif
+ }
+ else
+ {
+#ifdef MTK
+#ifdef CONFIG_OF_TOUCH
+ 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);
+#endif
+#endif
+#ifdef QCT
+ ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts);
+#endif
+ }
+ if (ret == 0) {
+ ts->irq_enabled = 1;
+ irq_enable_count = 1;
+ }
+ } else {
+ himax_int_enable(ts->client->irq,0);
+ free_irq(ts->client->irq, ts);
+ ts->irq_enabled = 0;
+ }
+
+ return len;
+}
+
+static const struct file_operations himax_proc_int_en_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_int_en_read,
+ .write = himax_int_en_write,
+};
+
+static ssize_t himax_layout_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ size_t ret = 0;
+ char *temp_buf;
+
+ if (!HX_PROC_SEND_FLAG) {
+ temp_buf = kzalloc(len, GFP_KERNEL);
+ if (!temp_buf) {
+ HX_PROC_SEND_FLAG=0;
+ return ret;
+ }
+ ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min);
+ ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max);
+ ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min);
+ ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max);
+ ret += snprintf(temp_buf+ret, len-ret, "\n");
+
+ 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;
+
+ return ret;
+}
+
+static ssize_t himax_layout_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ char buf_tmp[5];
+ int i = 0, j = 0, k = 0, ret;
+ unsigned long value;
+ int layout[4] = {0};
+ char buf[80] = {0};
+
+ 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++) {
+ if (buf[i] == ',' || buf[i] == '\n') {
+ memset(buf_tmp, 0x0, sizeof(buf_tmp));
+ if (i - j <= 5)
+ memcpy(buf_tmp, buf + j, i - j);
+ else {
+ I("buffer size is over 5 char\n");
+ return len;
+ }
+ j = i + 1;
+ if (k < 4) {
+ ret = kstrtoul(buf_tmp, 10, &value);
+ layout[k++] = value;
+ }
+ }
+ }
+ 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);
+ 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);
+ return len;
+}
+
+static const struct file_operations himax_proc_layout_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_layout_read,
+ .write = himax_layout_write,
+};
+
+static ssize_t himax_debug_level_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ 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);
+
+ 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;
+
+ return ret;
+}
+
+static ssize_t himax_debug_level_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts;
+ char buf_tmp[11];
+ int i;
+ ts = private_ts;
+
+ 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);
+
+ if(i!=len-2)
+ ts->debug_log_level <<= 4;
+ }
+
+ if (ts->debug_log_level & BIT(3)) {
+ 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);
+ if (ts->widthFactor > 0 && ts->heightFactor > 0)
+ ts->useScreenRes = 1;
+ else {
+ ts->heightFactor = 0;
+ ts->widthFactor = 0;
+ ts->useScreenRes = 0;
+ }
+ } else
+ I("Enable finger debug with raw position mode!\n");
+ } else {
+ ts->useScreenRes = 0;
+ ts->widthFactor = 0;
+ ts->heightFactor = 0;
+ }
+
+ return len;
+}
+
+static const struct file_operations himax_proc_debug_level_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_debug_level_read,
+ .write = himax_debug_level_write,
+};
+
+#ifdef HX_TP_PROC_REGISTER
+static ssize_t himax_proc_register_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ int ret = 0;
+ uint16_t loop_i;
+ uint8_t data[128];
+ char *temp_buf;
+
+ memset(data, 0x00, sizeof(data));
+
+ I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]);
+ if(!HX_PROC_SEND_FLAG)
+ {
+ 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);
+
+ 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]);
+ if ((loop_i % 16) == 15)
+ ret += snprintf(temp_buf+ret, len-ret, "\n");
+ }
+ ret += snprintf(temp_buf+ret, len-ret, "\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;
+ return ret;
+}
+
+static ssize_t himax_proc_register_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ char buf_tmp[16], length = 0;
+ unsigned long result = 0;
+ uint8_t loop_i = 0;
+ uint16_t base = 5;
+ uint8_t write_da[128];
+ char buf[80] = {0};
+
+ 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);
+
+ 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);
+ }
+ base = 11;
+ 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++) {
+ 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);
+ }
+ I("\n");
+ return len;
+ }
+ if (buf[base + 1] == 'x') {
+ buf_tmp[10] = '\n';
+ 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);
+ }
+ length+=4;
+ }
+ base += 10;
+ }
+ }
+ }
+ return len;
+}
+
+static const struct file_operations himax_proc_register_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_proc_register_read,
+ .write = himax_proc_register_write,
+};
+#endif
+
+#ifdef HX_TP_PROC_DIAG
+int16_t *getMutualBuffer(void)
+{
+ return diag_mutual;
+}
+int16_t *getMutualNewBuffer(void)
+{
+ return diag_mutual_new;
+}
+int16_t *getMutualOldBuffer(void)
+{
+ return diag_mutual_old;
+}
+int16_t *getSelfBuffer(void)
+{
+ return &diag_self[0];
+}
+uint8_t getXChannel(void)
+{
+ return x_channel;
+}
+uint8_t getYChannel(void)
+{
+ return y_channel;
+}
+uint8_t getDiagCommand(void)
+{
+ return diag_command;
+}
+void setXChannel(uint8_t x)
+{
+ x_channel = x;
+}
+void setYChannel(uint8_t y)
+{
+ y_channel = y;
+}
+void setMutualBuffer(void)
+{
+ 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);
+}
+void setMutualOldBuffer(void)
+{
+ diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL);
+}
+
+#ifdef HX_TP_PROC_2T2R
+int16_t *getMutualBuffer_2(void)
+{
+ return diag_mutual_2;
+}
+uint8_t getXChannel_2(void)
+{
+ return x_channel_2;
+}
+uint8_t getYChannel_2(void)
+{
+ return y_channel_2;
+}
+void setXChannel_2(uint8_t x)
+{
+ x_channel_2 = x;
+}
+void setYChannel_2(uint8_t y)
+{
+ y_channel_2 = y;
+}
+void setMutualBuffer_2(void)
+{
+ 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;
+ char buf[80] = {0};
+
+ 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);
+
+ return len;
+}
+
+static 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)
+{
+ if(transpose)
+ seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]);
+ else
+ 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)
+{
+ int i;
+ int in_max = 0;
+
+ if(transpose)
+ in_max = y_channel;
+ else
+ in_max = x_channel;
+
+ 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++)
+ {
+ 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)
+{
+ int j;
+ int out_max = 0;
+
+ if(transpose)
+ out_max = x_channel;
+ else
+ out_max = y_channel;
+
+ 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++)
+ {
+ himax_diag_arrange_inloop(s, in_init, transpose, j);
+ seq_printf(s, " %5d\n", diag_self[j]);
+ }
+ }
+}
+
+static void himax_diag_arrange(struct seq_file *s)
+{
+ 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++) {
+ 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++) {
+ 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);
+}
+
+static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ return NULL;
+}
+static void himax_diag_seq_stop(struct seq_file *s, void *v)
+{
+}
+static int himax_diag_seq_read(struct seq_file *s, void *v)
+{
+ size_t count = 0;
+ int32_t loop_i;//,loop_j
+ uint16_t mutual_num, self_num, width;
+
+#ifdef HX_TP_PROC_2T2R
+ 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
+ width = x_channel_2;
+ 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
+ width = x_channel;
+ seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel);
+ }
+
+ // 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");
+#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]);
+#endif
+#ifdef HX_TP_PROC_2T2R
+ }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, "\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");
+ }
+#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]);
+#endif
+#endif
+ } else if (diag_command > 4) {
+ 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");
+ }
+ } else {
+ 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_printf(s, "ChannelEnd");
+ seq_printf(s, "\n");
+ } else if (diag_command == 7) {
+ for (loop_i = 0; loop_i < 128 ;loop_i++) {
+ if ((loop_i % 16) == 0)
+ seq_printf(s, "LineStart:");
+ seq_printf(s, "%4d", diag_coor[loop_i]);
+ if ((loop_i % 16) == 15)
+ seq_printf(s, "\n");
+ }
+ } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){
+ himax_diag_arrange(s);
+ seq_printf(s, "\n");
+ }
+
+ return count;
+}
+static const struct seq_operations himax_diag_seq_ops =
+{
+ .start = himax_diag_seq_start,
+ .next = himax_diag_seq_next,
+ .stop = himax_diag_seq_stop,
+ .show = himax_diag_seq_read,
+};
+static int himax_diag_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &himax_diag_seq_ops);
+};
+bool DSRAM_Flag;
+
+//DSRAM thread
+void himax_ts_diag_func(void)
+{
+ 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_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)
+ {
+ mutual_data = getMutualBuffer();
+ }else if(diag_command == 92){
+ mutual_data = getMutualBuffer();
+ mutual_data_new = getMutualNewBuffer();
+ mutual_data_old = getMutualOldBuffer();
+ }
+ 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];
+ }
+ 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
+ }
+ 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
+ DSRAM_Flag = false;
+
+ //Enable ISR
+ himax_int_enable(private_ts->client->irq,1);
+
+ //=====================================
+ // 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);
+ }
+ }
+}
+
+static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data)
+{
+ char messages[80] = {0};
+
+ uint8_t command[2] = {0x00, 0x00};
+ uint8_t receive[1];
+
+ memset(receive, 0x00, sizeof(receive));
+
+ 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
+ DSRAM_Flag = false;
+
+ //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);
+ }
+ 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){
+ diag_max_cnt = 0;
+ memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime
+
+ //1. Disable ISR
+ himax_int_enable(private_ts->client->irq,0);
+
+ //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);
+
+ I("%s: Start get raw data in DSRAM\n", __func__);
+
+ //3. Set DSRAM flag
+ DSRAM_Flag = true;
+ }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);
+ }
+ return len;
+}
+
+static const struct file_operations himax_proc_diag_ops =
+{
+ .owner = THIS_MODULE,
+ .open = himax_diag_proc_open,
+ .read = seq_read,
+ .write = himax_diag_write,
+};
+#endif
+
+#ifdef HX_TP_PROC_RESET
+static ssize_t himax_reset_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ char buf_tmp[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();
+
+ return len;
+}
+
+static const struct file_operations himax_proc_reset_ops =
+{
+ .owner = THIS_MODULE,
+ .write = himax_reset_write,
+};
+#endif
+
+#ifdef HX_TP_PROC_DEBUG
+static ssize_t himax_debug_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ size_t count = 0;
+ char *temp_buf;
+
+ 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 (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW)
+ {
+ count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n");
+ }
+ else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW)
+ {
+ count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n");
+ }
+ else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC)
+ {
+ count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\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-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);
+ #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);
+ }
+ #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);
+ }
+ 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;
+ 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;
+ char fileName[128];
+ char buf[80] = {0};
+ int result;
+
+ 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
+ {
+ debug_level_cmd = buf[0];
+
+ himax_int_enable(private_ts->client->irq,0);
+
+ handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail
+
+ himax_int_enable(private_ts->client->irq,1);
+
+ return len;
+ }
+
+ else if ( buf[0] == 'v') //firmware version
+ {
+ debug_level_cmd = buf[0];
+ himax_int_enable(private_ts->client->irq,0);
+#ifdef HX_RST_PIN_FUNC
+ himax_HW_reset(false,false);
+#endif
+ himax_read_FW_ver(private_ts->client);
+ //himax_check_chip_version();
+#ifdef HX_RST_PIN_FUNC
+ himax_HW_reset(true,false);
+#endif
+ himax_int_enable(private_ts->client->irq,1);
+ return len;
+ }
+
+ else if ( buf[0] == 'd') //ic information
+ {
+ debug_level_cmd = buf[0];
+ return len;
+ }
+
+ else if ( buf[0] == 'i') //driver version
+ {
+ debug_level_cmd = buf[0];
+ return len;
+ }
+
+ else if (buf[0] == 't')
+ {
+
+ 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;
+ }
+
+ I("%s: FW len %d\n", __func__, fw->size);
+ fw_data = (unsigned char *)fw->data;
+
+ I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]);
+
+ if (fw_data != NULL)
+ {
+ // start to upgrade
+ himax_int_enable(private_ts->client->irq,0);
+
+ if ((buf[1] == '6') && (buf[2] == '0'))
+ {
+ if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0)
+ {
+ E("%s: TP upgrade error, line: %d\n", __func__, __LINE__);
+ fw_update_complete = false;
+ }
+ 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__);
+ fw_update_complete = false;
+ }
+ 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__);
+ fw_update_complete = false;
+ }
+ 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__);
+ fw_update_complete = false;
+ }
+ 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__);
+ fw_update_complete = false;
+ }
+ release_firmware(fw);
+ goto firmware_upgrade_done;
+ //return count;
+ }
+ }
+
+ firmware_upgrade_done:
+
+#ifdef HX_RST_PIN_FUNC
+ himax_HW_reset(true,false);
+#endif
+
+ himax_sense_on(private_ts->client, 0x01);
+ msleep(120);
+#ifdef HX_ESD_WORKAROUND
+ HX_ESD_RESET_ACTIVATE = 1;
+#endif
+ 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);
+ return len;
+}
+
+static const struct file_operations himax_proc_debug_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_debug_read,
+ .write = himax_debug_write,
+};
+
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+
+static uint8_t getFlashCommand(void)
+{
+ return flash_command;
+}
+
+static uint8_t getFlashDumpProgress(void)
+{
+ return flash_progress;
+}
+
+static uint8_t getFlashDumpComplete(void)
+{
+ return flash_dump_complete;
+}
+
+static uint8_t getFlashDumpFail(void)
+{
+ return flash_dump_fail;
+}
+
+uint8_t getSysOperation(void)
+{
+ return sys_operation;
+}
+
+static uint8_t getFlashReadStep(void)
+{
+ return flash_read_step;
+}
+/*
+static uint8_t getFlashDumpSector(void)
+{
+ return flash_dump_sector;
+}
+
+static uint8_t getFlashDumpPage(void)
+{
+ return flash_dump_page;
+}
+*/
+bool getFlashDumpGoing(void)
+{
+ return flash_dump_going;
+}
+
+void setFlashBuffer(void)
+{
+ flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL);
+ if (flash_buffer)
+ memset(flash_buffer,0x00,Flash_Size);
+}
+
+void setSysOperation(uint8_t operation)
+{
+ sys_operation = operation;
+}
+
+static void setFlashDumpProgress(uint8_t progress)
+{
+ flash_progress = progress;
+ //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress);
+}
+
+static void setFlashDumpComplete(uint8_t status)
+{
+ flash_dump_complete = status;
+}
+
+static void setFlashDumpFail(uint8_t fail)
+{
+ flash_dump_fail = fail;
+}
+
+static void setFlashCommand(uint8_t command)
+{
+ flash_command = command;
+}
+
+static void setFlashReadStep(uint8_t step)
+{
+ flash_read_step = step;
+}
+
+static void setFlashDumpSector(uint8_t sector)
+{
+ flash_dump_sector = sector;
+}
+
+static void setFlashDumpPage(uint8_t page)
+{
+ flash_dump_page = page;
+}
+
+static void setFlashDumpGoing(bool going)
+{
+ flash_dump_going = going;
+}
+
+static ssize_t himax_proc_flash_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ int ret = 0;
+ int loop_i;
+ 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)
+ {
+ 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 (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 (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 (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 ((loop_i % 16) == 15)
+ {
+ ret += snprintf(temp_buf+ret, len-ret, "\n");
+ }
+ }
+ ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+ ret += snprintf(temp_buf+ret, len-ret, "\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
+ local_flash_read_step = getFlashReadStep();
+
+ ret += snprintf(temp_buf+ret, len-ret, "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]);
+
+ if ((loop_i % 16) == 15)
+ {
+ ret += snprintf(temp_buf+ret, len-ret, "\n");
+ }
+ }
+
+ ret += snprintf(temp_buf+ret, len-ret, "FlashEnd");
+ ret += snprintf(temp_buf+ret, len-ret, "\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;
+ return ret;
+}
+
+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;
+ uint8_t loop_i = 0;
+ int base = 0;
+ char buf[80] = {0};
+
+ 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)
+ {
+ E("%s: PROC is busy , return!\n", __func__);
+ return len;
+ }
+
+ if (buf[0] == '0')
+ {
+ setFlashCommand(0);
+ 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);
+ setFlashReadStep(result);
+ }
+ }
+ }
+ else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k
+ {
+ setSysOperation(1);
+ setFlashCommand(1);
+ setFlashDumpProgress(0);
+ setFlashDumpComplete(0);
+ setFlashDumpFail(0);
+ if ((buf[1] == '_' ) && (buf[2] == '6' )){
+ if (buf[3] == '0'){
+ Flash_Size = FW_SIZE_60k;
+ }else if (buf[3] == '4'){
+ Flash_Size = FW_SIZE_64k;
+ }
+ }else if ((buf[1] == '_' ) && (buf[2] == '2' )){
+ if (buf[3] == '4'){
+ Flash_Size = FW_SIZE_124k;
+ }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
+ {
+ setSysOperation(1);
+ setFlashCommand(2);
+ setFlashDumpProgress(0);
+ setFlashDumpComplete(0);
+ setFlashDumpFail(0);
+ if ((buf[1] == '_' ) && (buf[2] == '6' )){
+ if (buf[3] == '0'){
+ Flash_Size = FW_SIZE_60k;
+ }else if (buf[3] == '4'){
+ Flash_Size = FW_SIZE_64k;
+ }
+ }else if ((buf[1] == '_' ) && (buf[2] == '2' )){
+ if (buf[3] == '4'){
+ Flash_Size = FW_SIZE_124k;
+ }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')
+ {
+ setSysOperation(1);
+ setFlashCommand(3);
+ setFlashDumpProgress(0);
+ setFlashDumpComplete(0);
+ setFlashDumpFail(0);
+
+ 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')
+ {
+ I("%s: command 4 enter.\n", __func__);
+ setSysOperation(1);
+ setFlashCommand(4);
+ setFlashDumpProgress(0);
+ setFlashDumpComplete(0);
+ setFlashDumpFail(0);
+
+ 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++)
+ {
+ memcpy(buf_tmp, buf + base, 2);
+ if (!kstrtoul(buf_tmp, 16, &result))
+ {
+ flash_buffer[loop_i] = result;
+ I("%d ",flash_buffer[loop_i]);
+ if (loop_i % 16 == 15)
+ {
+ I("\n");
+ }
+ }
+ base += 3;
+ }
+ I("=========Himax flash page buffer end=========\n");
+
+ queue_work(private_ts->flash_wq, &private_ts->flash_work);
+ }
+ return len;
+}
+
+static const struct file_operations himax_proc_flash_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_proc_flash_read,
+ .write = himax_proc_flash_write,
+};
+
+void himax_ts_flash_func(void)
+{
+ uint8_t local_flash_command = 0;
+
+ himax_int_enable(private_ts->client->irq,0);
+ setFlashDumpGoing(true);
+
+ //sector = getFlashDumpSector();
+ //page = getFlashDumpPage();
+
+ local_flash_command = getFlashCommand();
+
+ msleep(100);
+
+ 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);
+ }
+
+ I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n");
+
+ if (local_flash_command == 2)
+ {
+ E("Flash dump failed\n");
+ }
+
+ himax_int_enable(private_ts->client->irq,1);
+ setFlashDumpGoing(false);
+
+ setFlashDumpComplete(1);
+ setSysOperation(0);
+ return;
+
+/* Flash_Dump_i2c_transfer_error:
+
+ himax_int_enable(private_ts->client->irq,1);
+ setFlashDumpGoing(false);
+ setFlashDumpComplete(0);
+ setFlashDumpFail(1);
+ setSysOperation(0);
+ return;
+*/
+}
+
+#endif
+
+#ifdef HX_TP_PROC_SELF_TEST
+static ssize_t himax_self_test_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ int val=0x00;
+ int ret = 0;
+ char *temp_buf;
+
+ 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
+ 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
+
+ if (val == 0x01) {
+ ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n");
+ } else {
+ ret += snprintf(temp_buf+ret, len-ret, "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;
+ return ret;
+}
+
+/*
+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))
+ {
+ sel_type = (uint8_t)result;
+ }
+ I("sel_type = %x \r\n", sel_type);
+ return count;
+}
+*/
+
+static const struct file_operations himax_proc_self_test_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_self_test_read,
+};
+#endif
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+static ssize_t himax_sense_on_off_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ char buf[80] = {0};
+
+ 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')
+ {
+ himax_sense_off(private_ts->client);
+ 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'){
+ himax_sense_on(private_ts->client, 0x00);
+ I("Sense on re-map on, run sram \n");
+ }else{
+ I("Do nothing \n");
+ }
+ }
+ else
+ {
+ I("Do nothing \n");
+ }
+ return len;
+}
+
+static const struct file_operations himax_proc_sense_on_off_ops =
+{
+ .owner = THIS_MODULE,
+ .write = himax_sense_on_off_write,
+};
+#endif
+
+#ifdef HX_HIGH_SENSE
+static ssize_t himax_HSEN_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ size_t count = 0;
+ char *temp_buf;
+
+ 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;
+
+ if (copy_to_user(buf, temp_buf, len))
+ {
+ I("%s,here:%d\n", __func__, __LINE__);
+ }
+
+ kfree(temp_buf);
+ }
+ else
+ HX_PROC_SEND_FLAG=0;
+ return count;
+}
+
+static ssize_t himax_HSEN_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ char buf[80] = {0};
+
+
+ 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->HSEN_enable = 0;
+ }
+ else if (buf[0] == '1'){
+ ts->HSEN_enable = 1;
+ }
+ else
+ return -EINVAL;
+
+ himax_set_HSEN_func(ts->client, ts->HSEN_enable);
+
+ I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable);
+
+ return len;
+}
+
+static const struct file_operations himax_proc_HSEN_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_HSEN_read,
+ .write = himax_HSEN_write,
+};
+#endif
+
+#ifdef HX_SMART_WAKEUP
+static ssize_t himax_SMWP_read(struct file *file, char *buf,
+ size_t len, loff_t *pos)
+{
+ size_t count = 0;
+ struct himax_ts_data *ts = private_ts;
+ char *temp_buf;
+
+ 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);
+
+ 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;
+
+ return count;
+}
+
+static ssize_t himax_SMWP_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ char buf[80] = {0};
+
+ 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;
+
+ himax_set_SMWP_func(ts->client, ts->SMWP_enable);
+ HX_SMWP_EN = ts->SMWP_enable;
+ I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN);
+
+ return len;
+}
+
+static 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)
+{
+ struct himax_ts_data *ts = private_ts;
+ int i =0;
+ int ret = 0;
+ char *temp_buf;
+
+ 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]);
+ 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
+ {
+ HX_PROC_SEND_FLAG = 0;
+ ret = 0;
+ }
+ return ret;
+}
+
+static ssize_t himax_GESTURE_write(struct file *file, const char *buff,
+ size_t len, loff_t *pos)
+{
+ struct himax_ts_data *ts = private_ts;
+ int i =0;
+ char buf[80] = {0};
+
+ 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++)
+ {
+ if (buf[i] == '0')
+ ts->gesture_cust_en[i]= 0;
+ else if (buf[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]);
+ }
+ return len;
+}
+
+static const struct file_operations himax_proc_Gesture_ops =
+{
+ .owner = THIS_MODULE,
+ .read = himax_GESTURE_read,
+ .write = himax_GESTURE_write,
+};
+#endif
+
+int himax_touch_proc_init(void)
+{
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__);
+ goto fail_15;
+ }
+#endif
+
+ return 0 ;
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+ 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:
+#endif
+#ifdef HX_HIGH_SENSE
+ 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:
+#endif
+#ifdef HX_TP_PROC_FLASH_DUMP
+ 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:
+#endif
+#ifdef HX_TP_PROC_REGISTER
+ 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:
+#endif
+#ifdef HX_TP_PROC_RESET
+ 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 );
+ 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 );
+#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 );
+#endif
+#ifdef HX_DOT_VIEW
+ 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);
+#endif
+#ifdef HX_TP_PROC_FLASH_DUMP
+ 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 );
+#endif
+#ifdef HX_TP_PROC_REGISTER
+ remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir);
+#endif
+#ifdef HX_TP_PROC_DIAG
+ 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 );
+#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 );
+}
+#endif
diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h
new file mode 100644
index 0000000..91a7ae2
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_debug.h
@@ -0,0 +1,181 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_platform.h"
+#include "himax_common.h"
+
+#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
+ #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"
+ #define HIMAX_PROC_INT_EN_FILE "int_en"
+ #define HIMAX_PROC_LAYOUT_FILE "layout"
+
+ static struct proc_dir_entry *himax_touch_proc_dir;
+ static struct proc_dir_entry *himax_proc_debug_level_file;
+ static struct proc_dir_entry *himax_proc_vendor_file;
+ static struct proc_dir_entry *himax_proc_attn_file;
+ static struct proc_dir_entry *himax_proc_int_en_file;
+ static struct proc_dir_entry *himax_proc_layout_file;
+
+ uint8_t HX_PROC_SEND_FLAG;
+
+extern int himax_touch_proc_init(void);
+extern void himax_touch_proc_deinit(void);
+bool getFlashDumpGoing(void);
+
+#ifdef HX_TP_PROC_REGISTER
+ #define HIMAX_PROC_REGISTER_FILE "register"
+ struct proc_dir_entry *himax_proc_register_file;
+ 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;
+ #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr"
+ struct proc_dir_entry *himax_proc_diag_arrange_file;
+
+#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 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 coordinate_dump_enable = 0;
+ struct file *coordinate_fn;
+#endif
+
+#ifdef HX_TP_PROC_DEBUG
+ #define HIMAX_PROC_DEBUG_FILE "debug"
+ struct proc_dir_entry *himax_proc_debug_file = NULL;
+
+ bool fw_update_complete = false;
+ int handshaking_result = 0;
+ unsigned char debug_level_cmd = 0;
+ unsigned char upgrade_fw[128*1024];
+#endif
+
+#ifdef HX_TP_PROC_FLASH_DUMP
+ #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump"
+ 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 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);
+
+ void setFlashBuffer(void);
+ uint8_t getSysOperation(void);
+
+ static void setFlashCommand(uint8_t command);
+ static void setFlashReadStep(uint8_t step);
+ static void setFlashDumpComplete(uint8_t complete);
+ static void setFlashDumpFail(uint8_t fail);
+ static void setFlashDumpProgress(uint8_t progress);
+ void setSysOperation(uint8_t operation);
+ static void setFlashDumpSector(uint8_t sector);
+ static void setFlashDumpPage(uint8_t page);
+ static void setFlashDumpGoing(bool going);
+
+#endif
+
+#ifdef HX_TP_PROC_SELF_TEST
+ #define HIMAX_PROC_SELF_TEST_FILE "self_test"
+ struct proc_dir_entry *himax_proc_self_test_file = NULL;
+ uint32_t **raw_data_array;
+ uint8_t X_NUM = 0, Y_NUM = 0;
+ uint8_t sel_type = 0x0D;
+#endif
+
+#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;
+#endif
+
+#ifdef HX_HIGH_SENSE
+ #define HIMAX_PROC_HSEN_FILE "HSEN"
+ struct proc_dir_entry *himax_proc_HSEN_file = NULL;
+#endif
+
+#ifdef HX_TP_PROC_SENSE_ON_OFF
+ #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff"
+ struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL;
+#endif
+
+#ifdef HX_RST_PIN_FUNC
+ 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;
+#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;
+#endif
+
+#endif
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c
new file mode 100644
index 0000000..6ad8dc0
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_ic.c
@@ -0,0 +1,2118 @@
+/* Himax Android Driver Sample Code for HMX83100 chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_ic.h"
+
+static unsigned char i_TP_CRC_FW_128K[]=
+{
+ #include "HX_CRC_128.i"
+};
+static unsigned char i_TP_CRC_FW_64K[]=
+{
+ #include "HX_CRC_64.i"
+};
+static unsigned char i_TP_CRC_FW_124K[]=
+{
+ #include "HX_CRC_124.i"
+};
+static unsigned char i_TP_CRC_FW_60K[]=
+{
+ #include "HX_CRC_60.i"
+};
+
+
+unsigned long FW_VER_MAJ_FLASH_ADDR;
+unsigned long FW_VER_MAJ_FLASH_LENG;
+unsigned long FW_VER_MIN_FLASH_ADDR;
+unsigned long FW_VER_MIN_FLASH_LENG;
+unsigned long CFG_VER_MAJ_FLASH_ADDR;
+unsigned long CFG_VER_MAJ_FLASH_LENG;
+unsigned long CFG_VER_MIN_FLASH_ADDR;
+unsigned long CFG_VER_MIN_FLASH_LENG;
+
+unsigned char IC_TYPE = 0;
+unsigned char IC_CHECKSUM = 0;
+
+extern struct himax_ic_data* ic_data;
+
+int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail
+{
+ 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;
+
+ memset(hw_reset_check, 0x00, sizeof(hw_reset_check));
+ memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2));
+
+ buf0[0] = 0xF2;
+ if (IC_STATUS_CHECK == 0xAA) {
+ buf0[1] = 0xAA;
+ IC_STATUS_CHECK = 0x55;
+ } else {
+ buf0[1] = 0x55;
+ IC_STATUS_CHECK = 0xAA;
+ }
+
+ ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES);
+ if (ret < 0) {
+ E("[Himax]:write 0xF2 failed line: %d \n",__LINE__);
+ goto work_func_send_i2c_msg_fail;
+ }
+ msleep(50);
+
+ buf0[0] = 0xF2;
+ buf0[1] = 0x00;
+ ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES);
+ if (ret < 0) {
+ 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);
+ if (ret < 0) {
+ 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 (ret < 0) {
+ 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;
+ }
+ } else {
+ result = 0;
+ }
+
+ return result;
+
+work_func_send_i2c_msg_fail:
+ return 2;
+}
+
+void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+
+ if(diag_command != 0)
+ 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;
+ 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)
+{
+ //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};
+ 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;
+ 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;
+ 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_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] = 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
+ //==================================
+ 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);
+
+ //==================================
+ // Read access : 0x0C ==> 0x00
+ //==================================
+ out_buffer[0] = 0x00;
+ 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];
+
+ 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);
+ /*
+ for( i=0 ; i<8 ;i++)
+ {
+ for(j=0 ; j<64 ; j++)
+ {
+ setFlashDumpProgress(i*32 + j);
+ }
+ }
+ */
+ himax_sense_on(client, 0x01);
+
+ return;
+
+}
+
+int himax_chip_self_test(struct i2c_client *client)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[128];
+ int pf_value=0x00;
+ uint8_t test_result_id = 0;
+ int j;
+
+ memset(tmp_addr, 0x00, sizeof(tmp_addr));
+ memset(tmp_data, 0x00, sizeof(tmp_data));
+
+ himax_interface_on(client);
+ himax_sense_off(client);
+
+ //Set criteria
+ himax_burst_enable(client, 1);
+
+ tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94;
+ tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+ tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99;
+
+ himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8);
+
+ //start selftest
+ // 0x9008_805C ==> 0x0000_0001
+ tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C;
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+ himax_sense_on(client, 1);
+
+ msleep(2000);
+
+ 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;
+ 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]);
+
+ if (test_result_id==0xF) {
+ I("[Himax]: self-test pass\n");
+ pf_value = 0x1;
+ } else {
+ E("[Himax]: self-test fail\n");
+ pf_value = 0x0;
+ }
+ 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;
+ 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{
+ break;
+ }
+ }
+
+ himax_sense_on(client, 1);
+ msleep(120);
+
+ return pf_value;
+}
+
+void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable)
+{
+ uint8_t tmp_addr[4];
+ 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;
+ himax_flash_write_burst(client, tmp_addr, 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;
+ himax_register_read(client, tmp_addr, 1, tmp_data);
+}
+
+void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+
+ tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54;
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable;
+ himax_flash_write_burst(client, tmp_addr, 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;
+ 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];
+
+ tmp_data[0] = 0x31;
+ if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+ E("%s: i2c access fail!\n", __func__);
+ return -EBUSY;
+ }
+
+ tmp_data[0] = (0x10 | auto_add_4_byte);
+ if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+ E("%s: i2c access fail!\n", __func__);
+ return -EBUSY;
+ }
+ return 0;
+
+}
+
+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)
+ {
+ 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];
+ 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;
+ }
+ 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)
+{
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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) {
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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
+
+ if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }// idle state
+
+}
+
+void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data)
+{
+ 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;
+ }
+
+}
+
+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;
+ }
+
+ 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;
+
+ 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
+ {
+ ret = himax_burst_enable(client, 0);
+ if(ret)
+ return ret;
+ }
+ ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4);
+ if(ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+void himax_sense_off(struct i2c_client *client)
+{
+ uint8_t wdt_off = 0x00;
+ uint8_t tmp_addr[4];
+ 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;
+ 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;
+ 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)
+ 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;
+ 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;
+ 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;
+ 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]);
+
+}
+
+void himax_interface_on(struct i2c_client *client)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[5];
+
+ //===========================================
+ // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000
+ //===========================================
+ tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00;
+ himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail
+}
+
+bool wait_wip(struct i2c_client *client, int Timing)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+ uint8_t in_buffer[10];
+ //uint8_t out_buffer[20];
+ 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;
+ 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;
+ 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;
+ 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;
+ 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)
+ {
+ E("%s: Wait wip error!\n", __func__);
+ return false;
+ }
+ msleep(Timing);
+ }while ((in_buffer[0] & 0x01) == 0x01);
+ return true;
+}
+
+void himax_sense_on(struct i2c_client *client, uint8_t FlashMode)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[128];
+
+ 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;
+ 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;
+ 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]);
+
+ // 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;
+ himax_register_read(client, tmp_addr, 1, tmp_data);
+
+ I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__
+ ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]);
+
+ //=====================================
+ // Reset TCON
+ //=====================================
+ tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0;
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+ usleep_range(10000, 20000);
+ tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0;
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+ if (FlashMode == 0x00) //SRAM
+ {
+ //=====================================
+ // Re-map
+ //=====================================
+ tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00;
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1;
+ himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4);
+ I("%s: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);
+ 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);
+
+}
+
+void himax_chip_erase(struct i2c_client *client)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+
+ 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;
+ 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;
+ 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);
+
+ //=====================================
+ // 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__);
+
+}
+
+bool himax_block_erase(struct i2c_client *client)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+
+ 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;
+ 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;
+ 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);
+
+ //=====================================
+ // 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;
+ 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;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+ msleep(1000);
+
+ if (!wait_wip(client, 100))
+ {
+ E("%s:83100_Erase Fail\n", __func__);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+
+}
+
+bool himax_sector_erase(struct i2c_client *client, int start_addr)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+ int page_prog_start = 0;
+
+ 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;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+ for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000)
+ {
+ //=====================================
+ // Chip Erase
+ // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000
+ // 2. 0x8000_0024 ==> 0x0000_0006
+ //=====================================
+ tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20;
+ tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+ tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24;
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+ //=====================================
+ // Sector Erase
+ // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr
+ // 0x8000_0020 ==> 0x6700_0000 //control
+ // 0x8000_0024 ==> 0x0000_0020 //SE
+ //=====================================
+ tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28;
+ if (page_prog_start < 0x100)
+ {
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start;
+ }
+ else if (page_prog_start >= 0x100 && page_prog_start < 0x10000)
+ {
+ tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start;
+ }
+ else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000)
+ {
+ tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start;
+ }
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+
+ 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);
+
+ msleep(200);
+
+ if (!wait_wip(client, 100))
+ {
+ E("%s:83100_Erase Fail\n", __func__);
+ return false;
+ }
+ }
+ return true;
+}
+
+void himax_sram_write(struct i2c_client *client, uint8_t *FW_content)
+{
+ int i = 0;
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[128];
+ int FW_length = 0x4000; // 0x4000 = 16K bin file
+
+ //himax_sense_off(client);
+
+ for (i = 0; i < FW_length; i = i + 128)
+ {
+ himax_burst_enable(client, 1);
+
+ 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);
+ tmp_addr[0] = i;
+ }
+
+ memcpy(&tmp_data[0], &FW_content[i], 128);
+ himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128);
+
+ }
+
+ if (!wait_wip(client, 100))
+ E("%s:83100_Sram_Write Fail\n", __func__);
+}
+
+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;
+
+ 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;
+ out_buffer[0] = i;
+ }
+ 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) {
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return false;
+ }
+
+ 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;
+ }
+ }
+
+ kfree(get_fw_content);
+
+ return true;
+}
+
+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
+
+ //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;
+ 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;
+ 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);
+
+ //=================================
+ // 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
+
+ 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);
+
+
+ //=================================
+ // 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
+ {
+ buring_data[j + 4] = FW_content[i];
+ }
+
+
+ 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;
+ himax_flash_write_burst(client, tmp_addr, tmp_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;
+ }
+
+ if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ }
+
+ if (!wait_wip(client, 1))
+ E("%s:83100_Flash_Programming Fail\n", __func__);
+ }
+}
+
+bool himax_check_chip_version(struct i2c_client *client)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+ 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;
+ ret = himax_register_write(client, tmp_addr, 1, tmp_data);
+ 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;
+ ret = himax_register_write(client, tmp_addr, 1, tmp_data);
+ 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;
+ 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)
+ {
+ IC_TYPE = HX_83100_SERIES_PWON;
+ //himax_sense_on(client, 0x01);
+ ret_data = true;
+ break;
+ }
+ 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;
+ himax_register_write(client, tmp_addr, 1, tmp_data);
+ //himax_sense_on(client, 0x01);
+ return ret_data;
+}
+
+#if 1
+int himax_check_CRC(struct i2c_client *client, int mode)
+{
+ bool burnFW_success = false;
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+ int tmp_value;
+ int CRC_value = 0;
+
+ memset(tmp_data, 0x00, sizeof(tmp_data));
+
+ if (1)
+ {
+ if(mode == fw_image_60k)
+ {
+ himax_sram_write(client, (i_TP_CRC_FW_60K));
+ burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000);
+ }
+ else if(mode == fw_image_64k)
+ {
+ himax_sram_write(client, (i_TP_CRC_FW_64K));
+ burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000);
+ }
+ else if(mode == fw_image_124k)
+ {
+ himax_sram_write(client, (i_TP_CRC_FW_124K));
+ burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000);
+ }
+ 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
+
+ while(true)
+ {
+ msleep(100);
+
+ tmp_addr[3] = 0x90;
+ tmp_addr[2] = 0x08;
+ tmp_addr[1] = 0x80;
+ tmp_addr[0] = 0x94;
+ himax_register_read(client, tmp_addr, 1, tmp_data);
+
+ I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3],
+ tmp_data[2],tmp_data[1],tmp_data[0]);
+
+ if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF)
+ {
+ }
+ else
+ break;
+ }
+
+ CRC_value = tmp_data[3];
+
+ tmp_value = tmp_data[2] << 8;
+ CRC_value += tmp_value;
+
+ tmp_value = tmp_data[1] << 16;
+ CRC_value += tmp_value;
+
+ tmp_value = tmp_data[0] << 24;
+ CRC_value += tmp_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
+ {
+ E("%s: SRAM write fail\n", __func__);
+ return 0;
+ }
+ }
+ 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)
+{
+ uint8_t tmp_data[4];
+ int i, j;
+ int fw_data;
+ int fw_data_2;
+ 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)
+ length = 0x3C00;
+
+ 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++)
+ {
+ if ((CRC % 2) != 0)
+ {
+ CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial;
+ }
+ else
+ {
+ CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF);
+ }
+ }
+ }
+
+ 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);
+ tmp_data[2] = (uint8_t)(CRC >> 8);
+ tmp_data[3] = (uint8_t) CRC;
+
+ CRC = tmp_data[0];
+ 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);
+ if (CRC_from_FW == CRC)
+ return true;
+ else
+ return false;
+}
+#endif
+
+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;
+ }
+ 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;
+ }
+ himax_flash_programming(client, fw, 0x0F000);
+
+ //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);
+ 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 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;
+ }
+ himax_sense_off(client);
+ msleep(500);
+ himax_interface_on(client);
+ himax_chip_erase(client);
+ himax_flash_programming(client, fw, len);
+
+ //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);
+ 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 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;
+ }
+ 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;
+ }
+ himax_flash_programming(client, fw, 0x1F000);
+
+
+ //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);
+ 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 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;
+ }
+ himax_sense_off(client);
+ msleep(500);
+ himax_interface_on(client);
+ himax_chip_erase(client);
+
+ himax_flash_programming(client, fw, len);
+
+ //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);
+ return burnFW_success;
+}
+
+void himax_touch_information(struct i2c_client *client)
+{
+ uint8_t cmd[4];
+ char data[12] = {0};
+
+ I("%s:IC_TYPE =%d\n", __func__,IC_TYPE);
+
+ 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);
+
+ ic_data->HX_RX_NUM = data[1];
+ ic_data->HX_TX_NUM = data[2];
+ ic_data->HX_MAX_PT = data[3];
+
+ cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC;
+ himax_register_read(client, cmd, 1, data);
+
+ if((data[1] & 0x04) == 0x04) {
+ ic_data->HX_XY_REVERSE = true;
+ } 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);
+ ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0];
+ 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) {
+ ic_data->HX_INT_IS_EDGE = true;
+ } else {
+ ic_data->HX_INT_IS_EDGE = false;
+ }
+ if (ic_data->HX_RX_NUM > 40)
+ ic_data->HX_RX_NUM = 29;
+ if (ic_data->HX_TX_NUM > 20)
+ ic_data->HX_TX_NUM = 16;
+ if (ic_data->HX_MAX_PT > 10)
+ ic_data->HX_MAX_PT = 10;
+ if (ic_data->HX_Y_RES > 2000)
+ ic_data->HX_Y_RES = 1280;
+ 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
+ {
+ ic_data->HX_RX_NUM = 0;
+ ic_data->HX_TX_NUM = 0;
+ ic_data->HX_BT_NUM = 0;
+ ic_data->HX_X_RES = 0;
+ ic_data->HX_Y_RES = 0;
+ ic_data->HX_MAX_PT = 0;
+ ic_data->HX_XY_REVERSE = false;
+ ic_data->HX_INT_IS_EDGE = false;
+ }
+}
+
+void himax_read_FW_ver(struct i2c_client *client)
+{
+ uint8_t cmd[4];
+ uint8_t data[64] = {0};
+
+ //=====================================
+ // 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;
+
+ 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);
+
+ 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);
+
+
+ return;
+}
+
+bool himax_ic_package_check(struct i2c_client *client)
+{
+#if 0
+ uint8_t cmd[3];
+ uint8_t data[3];
+
+ memset(cmd, 0x00, sizeof(cmd));
+ memset(data, 0x00, sizeof(data));
+
+ if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0)
+ 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
+ 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
+ CFG_VER_MAJ_FLASH_LENG = 12;
+ 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))) {
+ 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
+ CFG_VER_MAJ_FLASH_LENG = 3;
+ 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)) {
+ 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;
+ 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)
+{
+ 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[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);
+}
+
+#if 0
+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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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) {
+ 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) {
+ 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) {
+ 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) {
+ 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)
+{
+ //uint8_t tmpbyte[2];
+ int i = 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ return;
+ }
+
+ // Write 256 bytes with continue burst mode
+ for (i = 0; i < 256; i = i + 4)
+ {
+ if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) {
+ 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;
+ // }
+ //}
+
+}
+#endif
+
+#if 0
+static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size)
+{
+ uint8_t tmp_addr[4];
+ uint8_t tmp_data[4];
+ uint8_t out_buffer[20];
+ uint8_t in_buffer[260];
+
+ 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;
+ 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;
+ 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_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_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;
+ himax_83100_Flash_Write(tmp_addr, tmp_data);
+
+ //==================================
+ // 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);
+
+ //==================================
+ // Read access : 0x0C ==> 0x00
+ //==================================
+ out_buffer[0] = 0x00;
+ i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES);
+
+ //==================================
+ // Read 128 bytes two times
+ //==================================
+ i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES);
+ 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);
+ for (i = 0; i < 128; i++)
+ flash_buffer[(i + 128) + page_prog_start] = in_buffer[i];
+
+ //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C;
+ //himax_register_read(tmp_addr, 32, out in_buffer);
+ //for (int i = 0; i < 128; i++)
+ // flash_buffer[i + page_prog_start] = in_buffer[i];
+ //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C;
+ //himax_register_read(tmp_addr, 32, out in_buffer);
+ //for (int i = 0; i < 128; i++)
+ // flash_buffer[i + page_prog_start] = in_buffer[i];
+
+ 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])
+ {
+ if (fail_cnt == 0)
+ fail_addr = i;
+
+ fail_cnt++;
+ //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);
+ return false;
+ }
+
+ I("%s:Byte read verify pass.\n", __func__);
+ return true;
+
+}
+#endif
+
+void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data)
+{
+ int i;
+ int cnt = 0;
+ unsigned char tmp_addr[4];
+ unsigned char tmp_data[4];
+ 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;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+ do
+ {
+ cnt++;
+ himax_register_read(client, tmp_addr, 1, tmp_data);
+ usleep_range(10000, 20000);
+ } 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)
+ {
+ 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]);
+ 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]);
+ }
+ address += max_i2c_size*4;
+ tmp_addr[1] = (uint8_t)((address>>8)&0x00FF);
+ tmp_addr[0] = (uint8_t)((address)&0x00FF);
+ }
+ tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64;
+ tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44;
+ himax_flash_write_burst(client, tmp_addr, tmp_data);
+}
+//ts_work
+int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){
+ 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;
+ }
+ return RawDataLen;
+}
+
+bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length)
+{
+ uint8_t cmd[4];
+
+ if(length > 56)
+ length = 124;
+ //=====================
+ //AHB I2C Burst Read
+ //=====================
+ cmd[0] = 0x31;
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ goto err_workqueue_out;
+ }
+ //=====================
+ //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) {
+ 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) {
+ E("%s: i2c access fail!\n", __func__);
+ goto err_workqueue_out;
+ }
+ i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES);
+ return 1;
+
+ err_workqueue_out:
+ return 0;
+}
+
+bool post_read_event_stack(struct i2c_client *client)
+{
+ return 1;
+}
+bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value
+{
+ 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);
+ 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)
+{
+ 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++)
+ {
+ 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
+ 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];
+ }
+ }
+ }
+ 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);
+ }
+}
diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h
new file mode 100644
index 0000000..18cd12b
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_ic.h
@@ -0,0 +1,82 @@
+/* Himax Android Driver Sample Code for HMX83100 chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_platform.h"
+#include "himax_common.h"
+
+#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
+#define HX_85XX_D_SERIES_PWON 4
+#define HX_85XX_E_SERIES_PWON 5
+#define HX_85XX_ES_SERIES_PWON 6
+#define HX_85XX_F_SERIES_PWON 7
+#define HX_83100_SERIES_PWON 8
+
+#define HX_TP_BIN_CHECKSUM_SW 1
+#define HX_TP_BIN_CHECKSUM_HW 2
+#define HX_TP_BIN_CHECKSUM_CRC 3
+
+enum fw_image_type {
+ fw_image_60k = 0x01,
+ fw_image_64k,
+ fw_image_124k,
+ fw_image_128k,
+};
+
+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_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);
+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
+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);
+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);
+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
diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c
new file mode 100644
index 0000000..7e8a1d6
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_platform.c
@@ -0,0 +1,796 @@
+/* Himax Android Driver Sample Code for HIMAX chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#include "himax_platform.h"
+#include "himax_common.h"
+
+int irq_enable_count = 0;
+#ifdef HX_SMART_WAKEUP
+#define TS_WAKE_LOCK_TIMEOUT (2 * HZ)
+#endif
+
+#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
+#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
+
+void himax_vk_parser(struct device_node *dt,
+ struct himax_i2c_platform_data *pdata)
+{
+ u32 data = 0;
+ uint8_t cnt = 0, i = 0;
+ uint32_t coords[4] = {0};
+ struct device_node *node, *pp = NULL;
+ struct himax_virtual_key *vk;
+
+ node = of_parse_phandle(dt, "virtualkey", 0);
+ 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;
+ 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];
+ } 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);
+ }
+}
+
+int himax_parse_dt(struct himax_ts_data *ts,
+ struct himax_i2c_platform_data *pdata)
+{
+ int rc, coords_size = 0;
+ uint32_t coords[4] = {0};
+ struct property *prop;
+ struct device_node *dt = ts->client->dev.of_node;
+ u32 data = 0;
+
+ prop = of_find_property(dt, "himax,panel-coords", NULL);
+ if (prop) {
+ coords_size = prop->length / sizeof(u32);
+ if (coords_size != 4)
+ D(" %s:Invalid panel coords size %d", __func__, coords_size);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+ 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);
+ return rc;
+ }
+ pdata->screenWidth = coords[1];
+ pdata->screenHeight = coords[3];
+ I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth,
+ pdata->screenHeight);
+
+ pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0);
+ 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)) {
+ 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)) {
+ 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);
+
+ if (of_property_read_u32(dt, "report_type", &data) == 0) {
+ pdata->protocol_type = data;
+ I(" DT:protocol_type=%d", pdata->protocol_type);
+ }
+
+ himax_vk_parser(dt, pdata);
+
+ return 0;
+}
+
+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[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &command,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = data,
+ }
+ };
+
+ for (retry = 0; retry < toRetry; retry++) {
+ if (i2c_transfer(client->adapter, msg, 2) == 2)
+ break;
+ msleep(20);
+ }
+ if (retry == toRetry) {
+ E("%s: i2c_read_block retry over %d\n",
+ __func__, toRetry);
+ return -EIO;
+ }
+ return 0;
+
+}
+
+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];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = length + 1,
+ .buf = buf,
+ }
+ };
+
+ buf[0] = command;
+ memcpy(buf+1, data, length);
+
+ for (retry = 0; retry < toRetry; retry++) {
+ if (i2c_transfer(client->adapter, msg, 1) == 1)
+ break;
+ msleep(20);
+ }
+
+ if (retry == toRetry) {
+ E("%s: i2c_write_block retry over %d\n",
+ __func__, toRetry);
+ return -EIO;
+ }
+ return 0;
+
+}
+
+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[] = {
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = data,
+ }
+ };
+
+ for (retry = 0; retry < toRetry; retry++) {
+ if (i2c_transfer(client->adapter, msg, 1) == 1)
+ break;
+ msleep(20);
+ }
+ if (retry == toRetry) {
+ E("%s: i2c_read_block retry over %d\n",
+ __func__, toRetry);
+ return -EIO;
+ }
+ return 0;
+}
+
+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 retry/*, loop_i*/;
+ uint8_t buf[length];
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = length,
+ .buf = buf,
+ }
+ };
+
+ memcpy(buf, data, length);
+
+ for (retry = 0; retry < toRetry; retry++) {
+ if (i2c_transfer(client->adapter, msg, 1) == 1)
+ break;
+ msleep(20);
+ }
+
+ if (retry == toRetry) {
+ E("%s: i2c_write_block retry over %d\n",
+ __func__, toRetry);
+ return -EIO;
+ }
+ return 0;
+}
+
+void himax_int_enable(int irqnum, int enable)
+{
+ if (enable == 1 && irq_enable_count == 0) {
+ enable_irq(irqnum);
+ irq_enable_count++;
+ } else if (enable == 0 && irq_enable_count == 1) {
+ disable_irq_nosync(irqnum);
+ irq_enable_count--;
+ }
+ I("irq_enable_count = %d", irq_enable_count);
+}
+
+void himax_rst_gpio_set(int pinnum, uint8_t value)
+{
+ gpio_direction_output(pinnum, value);
+}
+
+uint8_t himax_int_gpio_read(int pinnum)
+{
+ return gpio_get_value(pinnum);
+}
+
+#if defined(CONFIG_HMX_DB)
+static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata)
+{
+ int retval;
+ pdata->vcc_dig = regulator_get(&client->dev,
+ "vdd");
+ if (IS_ERR(pdata->vcc_dig))
+ {
+ E("%s: Failed to get regulator vdd\n",
+ __func__);
+ retval = PTR_ERR(pdata->vcc_dig);
+ return retval;
+ }
+ pdata->vcc_ana = regulator_get(&client->dev,
+ "avdd");
+ if (IS_ERR(pdata->vcc_ana))
+ {
+ E("%s: Failed to get regulator avdd\n",
+ __func__);
+ retval = PTR_ERR(pdata->vcc_ana);
+ regulator_put(pdata->vcc_ana);
+ return retval;
+ }
+
+ return 0;
+};
+
+static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on)
+{
+ int retval;
+
+ if (on)
+ {
+ retval = regulator_enable(pdata->vcc_dig);
+ if (retval)
+ {
+ E("%s: Failed to enable regulator vdd\n",
+ __func__);
+ return retval;
+ }
+ msleep(100);
+ retval = regulator_enable(pdata->vcc_ana);
+ if (retval)
+ {
+ E("%s: Failed to enable regulator avdd\n",
+ __func__);
+ regulator_disable(pdata->vcc_dig);
+ return retval;
+ }
+ }
+ else
+ {
+ regulator_disable(pdata->vcc_dig);
+ regulator_disable(pdata->vcc_ana);
+ }
+
+ return 0;
+}
+
+int himax_ts_pinctrl_init(struct himax_ts_data *ts)
+{
+ int retval;
+
+ /* Get pinctrl if target uses pinctrl */
+ 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);
+ goto err_pinctrl_get;
+ }
+
+ 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);
+ goto err_pinctrl_lookup;
+ }
+
+ 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);
+ goto err_pinctrl_lookup;
+ }
+
+ 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);
+ }
+
+ return 0;
+
+err_pinctrl_lookup:
+ devm_pinctrl_put(ts->ts_pinctrl);
+err_pinctrl_get:
+ ts->ts_pinctrl = NULL;
+ return retval;
+}
+
+int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata)
+{
+ int error;
+
+ error = himax_regulator_configure(client, pdata);
+ if (error)
+ {
+ E("Failed to intialize 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;
+ }
+ }
+#endif
+
+ 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;
+ }
+#endif
+
+ 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;
+ }
+ }
+#endif
+ return 0;
+#ifdef HX_RST_PIN_FUNC
+ 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:
+#endif
+ 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:
+#endif
+ err_regulator_not_on:
+
+ return error;
+}
+
+#else
+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));
+ }
+
+#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);
+}
+
+irqreturn_t himax_ts_thread(int irq, void *ptr)
+{
+ uint8_t diag_cmd;
+ struct himax_ts_data *ts = ptr;
+ struct timespec timeStart, timeEnd, timeDelta;
+
+ diag_cmd = getDiagCommand();
+
+ 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);
+ }
+
+#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);
+ 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);
+ }
+ 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);
+ himax_ts_work(ts);
+}
+
+int tp_irq = -1;
+
+int himax_ts_register_interrupt(struct i2c_client *client)
+{
+ struct himax_ts_data *ts = i2c_get_clientdata(client);
+ int ret = 0;
+
+ ts->irq_enabled = 0;
+ //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 (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);
+#ifdef HX_SMART_WAKEUP
+ irq_set_irq_wake(client->irq, 1);
+#endif
+ } else {
+ ts->use_irq = 0;
+ E("%s: request_irq failed\n", __func__);
+ }
+ } 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*/
+ ts->himax_wq = create_singlethread_workqueue("himax_touch");
+
+ INIT_WORK(&ts->work, himax_ts_work_func);
+
+ hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ts->timer.function = himax_ts_timer_func;
+ hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL);
+ I("%s: polling mode enabled\n", __func__);
+ }
+ return ret;
+}
+
+static int himax_common_suspend(struct device *dev)
+{
+ struct himax_ts_data *ts = dev_get_drvdata(dev);
+
+ I("%s: enter \n", __func__);
+
+ himax_chip_common_suspend(ts);
+ return 0;
+}
+
+static int himax_common_resume(struct device *dev)
+{
+ struct himax_ts_data *ts = dev_get_drvdata(dev);
+
+ I("%s: enter \n", __func__);
+
+ himax_chip_common_resume(ts);
+ return 0;
+}
+
+#if defined(CONFIG_FB)
+int fb_notifier_callback(struct notifier_block *self,
+ unsigned long event, void *data)
+{
+ struct fb_event *evdata = data;
+ int *blank;
+ struct himax_ts_data *ts=
+ container_of(self, struct himax_ts_data, fb_notif);
+
+ I(" %s\n", __func__);
+ 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 {
+ himax_common_resume(&ts->client->dev);
+ }
+ break;
+
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ himax_common_suspend(&ts->client->dev);
+ break;
+ }
+ mutex_unlock(&ts->fb_mutex);
+ }
+
+ return 0;
+}
+#endif
+
+static const struct i2c_device_id himax_common_ts_id[] = {
+ {HIMAX_common_NAME, 0 },
+ {}
+};
+
+static const struct dev_pm_ops himax_common_pm_ops = {
+#if (!defined(CONFIG_FB))
+ .suspend = himax_common_suspend,
+ .resume = himax_common_resume,
+#endif
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id himax_match_table[] = {
+ {.compatible = "himax,hxcommon" },
+ {},
+};
+#else
+#define himax_match_table NULL
+#endif
+
+static struct i2c_driver himax_common_driver = {
+ .id_table = himax_common_ts_id,
+ .probe = himax_chip_common_probe,
+ .remove = himax_chip_common_remove,
+ .driver = {
+ .name = HIMAX_common_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = himax_match_table,
+#ifdef CONFIG_PM
+ .pm = &himax_common_pm_ops,
+#endif
+ },
+};
+
+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);
+ return 0;
+}
+
+static void __exit himax_common_exit(void)
+{
+ i2c_del_driver(&himax_common_driver);
+}
+
+module_init(himax_common_init);
+module_exit(himax_common_exit);
+
+MODULE_DESCRIPTION("Himax_common driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h
new file mode 100644
index 0000000..1223685
--- /dev/null
+++ b/drivers/input/touchscreen/hxchipset/himax_platform.h
@@ -0,0 +1,135 @@
+/* Himax Android Driver Sample Code for Himax chipset
+*
+* Copyright (C) 2015 Himax Corporation.
+*
+* This software is licensed under the terms of the GNU General Public
+* License version 2, as published by the Free Software Foundation, and
+* may be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+*/
+
+#ifndef HIMAX_PLATFORM_H
+#define HIMAX_PLATFORM_H
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#if defined(CONFIG_HMX_DB)
+#include <linux/regulator/consumer.h>
+#endif
+
+#define QCT
+
+#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)
+#else
+#define D(x...)
+#define I(x...)
+#define W(x...)
+#define E(x...)
+#define DIF(x...)
+#endif
+
+#if defined(CONFIG_HMX_DB)
+/* Analog voltage @2.7 V */
+#define HX_VTG_MIN_UV 2700000
+#define HX_VTG_MAX_UV 3300000
+#define HX_ACTIVE_LOAD_UA 15000
+#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_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
+#endif
+
+#define HIMAX_common_NAME "himax_tp"
+#define HIMAX_I2C_ADDR 0x48
+#define INPUT_DEV_NAME "himax-touchscreen"
+
+struct himax_i2c_platform_data {
+ int abs_x_min;
+ int abs_x_max;
+ int abs_x_fuzz;
+ int abs_y_min;
+ int abs_y_max;
+ int abs_y_fuzz;
+ int abs_pressure_min;
+ int abs_pressure_max;
+ int abs_pressure_fuzz;
+ int abs_width_min;
+ int abs_width_max;
+ int screenWidth;
+ int screenHeight;
+ uint8_t fw_version;
+ uint8_t tw_id;
+ uint8_t powerOff3V3;
+ uint8_t cable_config[2];
+ uint8_t protocol_type;
+ int gpio_irq;
+ int gpio_reset;
+ int gpio_3v3_en;
+ int (*power)(int on);
+ void (*reset)(void);
+ struct himax_virtual_key *virtual_key;
+ struct kobject *vk_obj;
+ struct kobj_attribute *vk2Use;
+
+ struct himax_config *hx_config;
+ int hx_config_size;
+#if defined(CONFIG_HMX_DB)
+ bool i2c_pull_up;
+ bool digital_pwr_regulator;
+ int reset_gpio;
+ u32 reset_gpio_flags;
+ 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
+};
+
+
+extern int irq_enable_count;
+extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry);
+extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry);
+extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry);
+extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry);
+extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry);
+extern void himax_int_enable(int irqnum, int enable);
+extern int himax_ts_register_interrupt(struct i2c_client *client);
+extern void himax_rst_gpio_set(int pinnum, uint8_t value);
+extern uint8_t himax_int_gpio_read(int pinnum);
+
+extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata);
+
+#if defined(CONFIG_FB)
+extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data);
+#endif
+
+#endif
diff --git a/drivers/iommu/arm-smmu-errata.c b/drivers/iommu/arm-smmu-errata.c
index 2ee2028..e1cb1a4 100644
--- a/drivers/iommu/arm-smmu-errata.c
+++ b/drivers/iommu/arm-smmu-errata.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -41,7 +41,7 @@
ret = hyp_assign_phys(page_to_phys(page), PAGE_ALIGN(size),
&source_vm, 1,
&dest_vm, &dest_perm, 1);
- if (ret) {
+ if (ret && (ret != -EIO)) {
__free_pages(page, get_order(size));
page = NULL;
}
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index 3a1c406..f846f01 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -389,6 +389,7 @@
pasid_max - 1, GFP_KERNEL);
if (ret < 0) {
kfree(svm);
+ kfree(sdev);
goto out;
}
svm->pasid = ret;
diff --git a/drivers/iommu/io-pgtable-msm-secure.c b/drivers/iommu/io-pgtable-msm-secure.c
index d0a8a79..e0314f9 100644
--- a/drivers/iommu/io-pgtable-msm-secure.c
+++ b/drivers/iommu/io-pgtable-msm-secure.c
@@ -47,6 +47,11 @@
int msm_iommu_sec_pgtbl_init(void)
{
+ struct msm_scm_ptbl_init {
+ unsigned int paddr;
+ unsigned int size;
+ unsigned int spare;
+ } pinit = {0};
int psize[2] = {0, 0};
unsigned int spare = 0;
int ret, ptbl_ret = 0;
@@ -55,7 +60,12 @@
dma_addr_t paddr;
unsigned long attrs = 0;
- if (is_scm_armv8()) {
+ struct scm_desc desc = {0};
+
+ if (!is_scm_armv8()) {
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &spare,
+ sizeof(spare), psize, sizeof(psize));
+ } else {
struct scm_desc desc = {0};
desc.args[0] = spare;
@@ -64,12 +74,11 @@
IOMMU_SECURE_PTBL_SIZE), &desc);
psize[0] = desc.ret[0];
psize[1] = desc.ret[1];
- if (ret || psize[1]) {
- pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n");
- return ret;
- }
}
-
+ if (ret || psize[1]) {
+ pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n");
+ goto fail;
+ }
/* Now allocate memory for the secure page tables */
attrs = DMA_ATTR_NO_KERNEL_MAPPING;
dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
@@ -78,34 +87,42 @@
if (!cpu_addr) {
pr_err("%s: Failed to allocate %d bytes for PTBL\n",
__func__, psize[0]);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
- if (is_scm_armv8()) {
- struct scm_desc desc = {0};
+ pinit.paddr = (unsigned int)paddr;
+ /* paddr may be a physical address > 4GB */
+ desc.args[0] = paddr;
+ desc.args[1] = pinit.size = psize[0];
+ desc.args[2] = pinit.spare;
+ desc.arginfo = SCM_ARGS(3, SCM_RW, SCM_VAL, SCM_VAL);
- desc.args[0] = paddr;
- desc.args[1] = psize[0];
- desc.args[2] = 0;
- desc.arginfo = SCM_ARGS(3, SCM_RW, SCM_VAL, SCM_VAL);
-
+ if (!is_scm_armv8()) {
+ ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &pinit,
+ sizeof(pinit), &ptbl_ret, sizeof(ptbl_ret));
+ } else {
ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP,
IOMMU_SECURE_PTBL_INIT), &desc);
ptbl_ret = desc.ret[0];
-
- if (ret) {
- pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n");
- return ret;
- }
-
- if (ptbl_ret) {
- pr_err("scm call IOMMU_SECURE_PTBL_INIT extended ret fail\n");
- return ret;
- }
+ }
+ if (ret) {
+ pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n");
+ goto fail_mem;
+ }
+ if (ptbl_ret) {
+ pr_err("scm call IOMMU_SECURE_PTBL_INIT extended ret fail\n");
+ goto fail_mem;
}
return 0;
+
+fail_mem:
+ dma_free_attrs(&dev, psize[0], cpu_addr, paddr, attrs);
+fail:
+ return ret;
}
+
EXPORT_SYMBOL(msm_iommu_sec_pgtbl_init);
static int msm_secure_map(struct io_pgtable_ops *ops, unsigned long iova,
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 9ae7180..1c2ca8d 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -21,6 +21,8 @@
#include "irq-gic-common.h"
+static DEFINE_RAW_SPINLOCK(irq_controller_lock);
+
static const struct gic_kvm_info *gic_kvm_info;
const struct gic_kvm_info *gic_get_kvm_info(void)
@@ -52,11 +54,13 @@
u32 confoff = (irq / 16) * 4;
u32 val, oldval;
int ret = 0;
+ unsigned long flags;
/*
* Read current configuration register, and insert the config
* for "irq", depending on "type".
*/
+ raw_spin_lock_irqsave(&irq_controller_lock, flags);
val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask;
@@ -64,8 +68,10 @@
val |= confmask;
/* If the current configuration is the same, then we are done */
- if (val == oldval)
+ if (val == oldval) {
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
return 0;
+ }
/*
* Write back the new configuration, and possibly re-enable
@@ -83,6 +89,7 @@
pr_warn("GIC: PPI%d is secure or misconfigured\n",
irq - 16);
}
+ raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
if (sync_access)
sync_access();
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 307d545..2f0f448 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -1359,6 +1359,10 @@
u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2;
void __iomem *redist_base;
+ /* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */
+ if (!(gicc->flags & ACPI_MADT_ENABLED))
+ return 0;
+
redist_base = ioremap(gicc->gicr_base_address, size);
if (!redist_base)
return -ENOMEM;
@@ -1408,6 +1412,13 @@
if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address)
return 0;
+ /*
+ * It's perfectly valid firmware can pass disabled GICC entry, driver
+ * should not treat as errors, skip the entry instead of probe fail.
+ */
+ if (!(gicc->flags & ACPI_MADT_ENABLED))
+ return 0;
+
return -ENODEV;
}
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
index 03b79b0..05d87f6 100644
--- a/drivers/irqchip/irq-mbigen.c
+++ b/drivers/irqchip/irq-mbigen.c
@@ -105,10 +105,7 @@
static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
u32 *mask, u32 *addr)
{
- unsigned int ofst;
-
- hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
- ofst = hwirq / 32 * 4;
+ unsigned int ofst = (hwirq / 32) * 4;
*mask = 1 << (hwirq % 32);
*addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c
index 9cb4b62..b92a19a 100644
--- a/drivers/isdn/mISDN/stack.c
+++ b/drivers/isdn/mISDN/stack.c
@@ -72,7 +72,7 @@
if (sk->sk_state != MISDN_BOUND)
continue;
if (!cskb)
- cskb = skb_copy(skb, GFP_KERNEL);
+ cskb = skb_copy(skb, GFP_ATOMIC);
if (!cskb) {
printk(KERN_WARNING "%s no skb\n", __func__);
break;
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 840401a..f672648 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -266,7 +266,7 @@
"slave address 0x%02x\n",
id->name, chip->bits, client->addr);
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
if (pdata) {
diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c
index 764657a..8a850c5 100644
--- a/drivers/leds/leds-qpnp-haptics.c
+++ b/drivers/leds/leds-qpnp-haptics.c
@@ -24,6 +24,7 @@
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/qpnp/qpnp-misc.h>
#include <linux/qpnp/qpnp-revid.h>
@@ -321,6 +322,7 @@
int sc_irq;
struct pwm_param pwm_data;
struct hap_lra_ares_param ares_cfg;
+ struct regulator *vcc_pon;
u32 play_time_ms;
u32 max_play_time_ms;
u32 vmax_mv;
@@ -355,6 +357,7 @@
bool lra_auto_mode;
bool play_irq_en;
bool auto_res_err_recovery_hw;
+ bool vcc_pon_enabled;
};
static int qpnp_haptics_parse_buffer_dt(struct hap_chip *chip);
@@ -801,10 +804,29 @@
enable = atomic_read(&chip->state);
pr_debug("state: %d\n", enable);
+
+ if (chip->vcc_pon && enable && !chip->vcc_pon_enabled) {
+ rc = regulator_enable(chip->vcc_pon);
+ if (rc < 0)
+ pr_err("%s: could not enable vcc_pon regulator rc=%d\n",
+ __func__, rc);
+ else
+ chip->vcc_pon_enabled = true;
+ }
+
rc = qpnp_haptics_play(chip, enable);
if (rc < 0)
pr_err("Error in %sing haptics, rc=%d\n",
enable ? "play" : "stopp", rc);
+
+ if (chip->vcc_pon && !enable && chip->vcc_pon_enabled) {
+ rc = regulator_disable(chip->vcc_pon);
+ if (rc)
+ pr_err("%s: could not disable vcc_pon regulator rc=%d\n",
+ __func__, rc);
+ else
+ chip->vcc_pon_enabled = false;
+ }
}
static enum hrtimer_restart hap_stop_timer(struct hrtimer *timer)
@@ -2054,6 +2076,7 @@
struct device_node *revid_node, *misc_node;
const char *temp_str;
int rc, temp;
+ struct regulator *vcc_pon;
rc = of_property_read_u32(node, "reg", &temp);
if (rc < 0) {
@@ -2381,6 +2404,16 @@
else if (chip->play_mode == HAP_PWM)
rc = qpnp_haptics_parse_pwm_dt(chip);
+ if (of_find_property(node, "vcc_pon-supply", NULL)) {
+ vcc_pon = regulator_get(&chip->pdev->dev, "vcc_pon");
+ if (IS_ERR(vcc_pon)) {
+ rc = PTR_ERR(vcc_pon);
+ dev_err(&chip->pdev->dev,
+ "regulator get failed vcc_pon rc=%d\n", rc);
+ }
+ chip->vcc_pon = vcc_pon;
+ }
+
return rc;
}
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c
index 537903b..d23337e 100644
--- a/drivers/md/bcache/alloc.c
+++ b/drivers/md/bcache/alloc.c
@@ -512,15 +512,21 @@
/*
* We keep multiple buckets open for writes, and try to segregate different
- * write streams for better cache utilization: first we look for a bucket where
- * the last write to it was sequential with the current write, and failing that
- * we look for a bucket that was last used by the same task.
+ * write streams for better cache utilization: first we try to segregate flash
+ * only volume write streams from cached devices, secondly we look for a bucket
+ * where the last write to it was sequential with the current write, and
+ * failing that we look for a bucket that was last used by the same task.
*
* The ideas is if you've got multiple tasks pulling data into the cache at the
* same time, you'll get better cache utilization if you try to segregate their
* data and preserve locality.
*
- * For example, say you've starting Firefox at the same time you're copying a
+ * For example, dirty sectors of flash only volume is not reclaimable, if their
+ * dirty sectors mixed with dirty sectors of cached device, such buckets will
+ * be marked as dirty and won't be reclaimed, though the dirty data of cached
+ * device have been written back to backend device.
+ *
+ * And say you've starting Firefox at the same time you're copying a
* bunch of files. Firefox will likely end up being fairly hot and stay in the
* cache awhile, but the data you copied might not be; if you wrote all that
* data to the same buckets it'd get invalidated at the same time.
@@ -537,7 +543,10 @@
struct open_bucket *ret, *ret_task = NULL;
list_for_each_entry_reverse(ret, &c->data_buckets, list)
- if (!bkey_cmp(&ret->key, search))
+ if (UUID_FLASH_ONLY(&c->uuids[KEY_INODE(&ret->key)]) !=
+ UUID_FLASH_ONLY(&c->uuids[KEY_INODE(search)]))
+ continue;
+ else if (!bkey_cmp(&ret->key, search))
goto found;
else if (ret->last_write_point == write_point)
ret_task = ret;
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index 28864ad..e4c2d5d 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -892,6 +892,12 @@
mutex_lock(&bch_register_lock);
+ cancel_delayed_work_sync(&dc->writeback_rate_update);
+ if (!IS_ERR_OR_NULL(dc->writeback_thread)) {
+ kthread_stop(dc->writeback_thread);
+ dc->writeback_thread = NULL;
+ }
+
memset(&dc->sb.set_uuid, 0, 16);
SET_BDEV_STATE(&dc->sb, BDEV_STATE_NONE);
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index be13ebf..f688bfe 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1777,12 +1777,12 @@
cmd == DM_LIST_VERSIONS_CMD)
return 0;
- if ((cmd == DM_DEV_CREATE_CMD)) {
+ if (cmd == DM_DEV_CREATE_CMD) {
if (!*param->name) {
DMWARN("name not supplied when creating device");
return -EINVAL;
}
- } else if ((*param->uuid && *param->name)) {
+ } else if (*param->uuid && *param->name) {
DMWARN("only supply one of name or uuid, cmd(%u)", cmd);
return -EINVAL;
}
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 5d0a996..d96aa84 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/reboot.h>
+#include <linux/vmalloc.h>
#define DM_MSG_PREFIX "verity"
@@ -32,6 +33,7 @@
#define DM_VERITY_OPT_LOGGING "ignore_corruption"
#define DM_VERITY_OPT_RESTART "restart_on_corruption"
#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
+#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once"
#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC)
@@ -395,6 +397,18 @@
}
/*
+ * Moves the bio iter one data block forward.
+ */
+static inline void verity_bv_skip_block(struct dm_verity *v,
+ struct dm_verity_io *io,
+ struct bvec_iter *iter)
+{
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size);
+
+ bio_advance_iter(bio, iter, 1 << v->data_dev_block_bits);
+}
+
+/*
* Verify one "dm_verity_io" structure.
*/
static int verity_verify_io(struct dm_verity_io *io)
@@ -406,9 +420,16 @@
for (b = 0; b < io->n_blocks; b++) {
int r;
+ sector_t cur_block = io->block + b;
struct shash_desc *desc = verity_io_hash_desc(v, io);
- r = verity_hash_for_block(v, io, io->block + b,
+ if (v->validated_blocks &&
+ likely(test_bit(cur_block, v->validated_blocks))) {
+ verity_bv_skip_block(v, io, &io->iter);
+ continue;
+ }
+
+ r = verity_hash_for_block(v, io, cur_block,
verity_io_want_digest(v, io),
&is_zero);
if (unlikely(r < 0))
@@ -441,13 +462,16 @@
return r;
if (likely(memcmp(verity_io_real_digest(v, io),
- verity_io_want_digest(v, io), v->digest_size) == 0))
+ verity_io_want_digest(v, io), v->digest_size) == 0)) {
+ if (v->validated_blocks)
+ set_bit(cur_block, v->validated_blocks);
continue;
+ }
else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
- io->block + b, NULL, &start) == 0)
+ cur_block, NULL, &start) == 0)
continue;
else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
- io->block + b))
+ cur_block))
return -EIO;
}
@@ -641,6 +665,8 @@
args += DM_VERITY_OPTS_FEC;
if (v->zero_digest)
args++;
+ if (v->validated_blocks)
+ args++;
if (!args)
return;
DMEMIT(" %u", args);
@@ -659,6 +685,8 @@
}
if (v->zero_digest)
DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
+ if (v->validated_blocks)
+ DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE);
sz = verity_fec_status_table(v, sz, result, maxlen);
break;
}
@@ -712,6 +740,7 @@
if (v->bufio)
dm_bufio_client_destroy(v->bufio);
+ vfree(v->validated_blocks);
kfree(v->salt);
kfree(v->root_digest);
kfree(v->zero_digest);
@@ -733,6 +762,26 @@
}
EXPORT_SYMBOL_GPL(verity_dtr);
+static int verity_alloc_most_once(struct dm_verity *v)
+{
+ struct dm_target *ti = v->ti;
+
+ /* the bitset can only handle INT_MAX blocks */
+ if (v->data_blocks > INT_MAX) {
+ ti->error = "device too large to use check_at_most_once";
+ return -E2BIG;
+ }
+
+ v->validated_blocks = vzalloc(BITS_TO_LONGS(v->data_blocks) *
+ sizeof(unsigned long));
+ if (!v->validated_blocks) {
+ ti->error = "failed to allocate bitset for check_at_most_once";
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static int verity_alloc_zero_digest(struct dm_verity *v)
{
int r = -ENOMEM;
@@ -802,6 +851,12 @@
}
continue;
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_AT_MOST_ONCE)) {
+ r = verity_alloc_most_once(v);
+ if (r)
+ return r;
+ continue;
+
} else if (verity_is_fec_opt_arg(arg_name)) {
r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
if (r)
@@ -1070,7 +1125,7 @@
static struct target_type verity_target = {
.name = "verity",
- .version = {1, 3, 0},
+ .version = {1, 4, 0},
.module = THIS_MODULE,
.ctr = verity_ctr,
.dtr = verity_dtr,
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
index 75effca..6d6d8df 100644
--- a/drivers/md/dm-verity.h
+++ b/drivers/md/dm-verity.h
@@ -63,6 +63,7 @@
sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
struct dm_verity_fec *fec; /* forward error correction */
+ unsigned long *validated_blocks; /* bitset blocks validated */
};
struct dm_verity_io {
diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index ba7edcd..fcc2b57 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -1122,8 +1122,10 @@
cmsg.raid_slot = cpu_to_le32(rdev->desc_nr);
lock_comm(cinfo);
ret = __sendmsg(cinfo, &cmsg);
- if (ret)
+ if (ret) {
+ unlock_comm(cinfo);
return ret;
+ }
cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE;
ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX);
cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index c17c882..2b04c720 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3681,6 +3681,7 @@
if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
discard_supported = true;
+ first = 0;
}
if (mddev->queue) {
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index edf37fd..a7549a4 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -110,8 +110,7 @@
static inline void lock_all_device_hash_locks_irq(struct r5conf *conf)
{
int i;
- local_irq_disable();
- spin_lock(conf->hash_locks);
+ spin_lock_irq(conf->hash_locks);
for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++)
spin_lock_nest_lock(conf->hash_locks + i, conf->hash_locks);
spin_lock(&conf->device_lock);
@@ -121,9 +120,9 @@
{
int i;
spin_unlock(&conf->device_lock);
- for (i = NR_STRIPE_HASH_LOCKS; i; i--)
- spin_unlock(conf->hash_locks + i - 1);
- local_irq_enable();
+ for (i = NR_STRIPE_HASH_LOCKS - 1; i; i--)
+ spin_unlock(conf->hash_locks + i);
+ spin_unlock_irq(conf->hash_locks);
}
/* bio's attached to a stripe+device for I/O are linked together in bi_sector
@@ -732,12 +731,11 @@
static void lock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
{
- local_irq_disable();
if (sh1 > sh2) {
- spin_lock(&sh2->stripe_lock);
+ spin_lock_irq(&sh2->stripe_lock);
spin_lock_nested(&sh1->stripe_lock, 1);
} else {
- spin_lock(&sh1->stripe_lock);
+ spin_lock_irq(&sh1->stripe_lock);
spin_lock_nested(&sh2->stripe_lock, 1);
}
}
@@ -745,8 +743,7 @@
static void unlock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2)
{
spin_unlock(&sh1->stripe_lock);
- spin_unlock(&sh2->stripe_lock);
- local_irq_enable();
+ spin_unlock_irq(&sh2->stripe_lock);
}
/* Only freshly new full stripe normal write stripe can be added to a batch list */
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 142ae28..d558ed3 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -420,11 +420,13 @@
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw");
- prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
- queue_work(q, &state->fw_work);
- schedule();
- finish_wait(&state->fw_wait, &wait);
- destroy_workqueue(q);
+ if (q) {
+ prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+ queue_work(q, &state->fw_work);
+ schedule();
+ finish_wait(&state->fw_wait, &wait);
+ destroy_workqueue(q);
+ }
/* 6. */
cx25840_write(client, 0x115, 0x8c);
@@ -634,11 +636,13 @@
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw");
- prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
- queue_work(q, &state->fw_work);
- schedule();
- finish_wait(&state->fw_wait, &wait);
- destroy_workqueue(q);
+ if (q) {
+ prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+ queue_work(q, &state->fw_work);
+ schedule();
+ finish_wait(&state->fw_wait, &wait);
+ destroy_workqueue(q);
+ }
/* Call the cx23888 specific std setup func, we no longer rely on
* the generic cx24840 func.
@@ -752,11 +756,13 @@
INIT_WORK(&state->fw_work, cx25840_work_handler);
init_waitqueue_head(&state->fw_wait);
q = create_singlethread_workqueue("cx25840_fw");
- prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
- queue_work(q, &state->fw_work);
- schedule();
- finish_wait(&state->fw_wait, &wait);
- destroy_workqueue(q);
+ if (q) {
+ prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE);
+ queue_work(q, &state->fw_work);
+ schedule();
+ finish_wait(&state->fw_wait, &wait);
+ destroy_workqueue(q);
+ }
cx25840_std_setup(client);
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
index ba32526..dfcb73a 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csid/msm_csid.c
@@ -229,7 +229,9 @@
static int msm_csid_reset(struct csid_device *csid_dev)
{
int32_t rc = 0;
+ uint32_t irq = 0, irq_bitshift;
+ irq_bitshift = csid_dev->ctrl_reg->csid_reg.csid_rst_done_irq_bitshift;
msm_camera_io_w(csid_dev->ctrl_reg->csid_reg.csid_rst_stb_all,
csid_dev->base +
csid_dev->ctrl_reg->csid_reg.csid_rst_cmd_addr);
@@ -238,8 +240,23 @@
if (rc < 0) {
pr_err("wait_for_completion in msm_csid_reset fail rc = %d\n",
rc);
+ } else if (rc == 0) {
+ irq = msm_camera_io_r(csid_dev->base +
+ csid_dev->ctrl_reg->csid_reg.csid_irq_status_addr);
+ pr_err_ratelimited("%s CSID%d_IRQ_STATUS_ADDR = 0x%x\n",
+ __func__, csid_dev->pdev->id, irq);
+ if (irq & (0x1 << irq_bitshift)) {
+ rc = 1;
+ CDBG("%s succeeded", __func__);
+ } else {
+ rc = 0;
+ pr_err("%s reset csid_irq_status failed = 0x%x\n",
+ __func__, irq);
+ }
if (rc == 0)
rc = -ETIMEDOUT;
+ } else {
+ CDBG("%s succeeded", __func__);
}
return rc;
}
diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
index 72586fa..6fc8e1e 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
+++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c
@@ -293,10 +293,18 @@
void __iomem *csiphybase;
enum snps_csiphy_mode mode = INVALID_MODE;
uint32_t value, num_tries, num_lanes, offset;
+ uint32_t clk_mux_reg = 0;
csiphybase = csiphy_dev->base;
+ if (csiphy_dev->clk_mux_base != NULL)
+ clk_mux_reg = msm_camera_io_r(csiphy_dev->clk_mux_base);
+ else {
+ pr_err("%s: invalid clk_mux_base\n", __func__);
+ return -EINVAL;
+ }
+
/* lane mask usage
- * BIT LANE
+ * BIT LANE
* 0(LSB) PHY A data 0
* 1 PHY A data 1
* 2 PHY B data 0
@@ -318,6 +326,9 @@
return -EINVAL;
}
csiphy_dev->snps_state = CONFIGURED_AGGREGATE_MODE;
+ clk_mux_reg &= ~0xff;
+ clk_mux_reg |= csiphy_params->csid_core << 4;
+ clk_mux_reg |= (uint32_t)csiphy_params->csid_core;
} else if (lane_mask == LANE_MASK_PHY_A) { /* PHY A */
/* 2 lane config */
num_lanes = 2;
@@ -333,6 +344,8 @@
pr_err("%s: invalid request\n", __func__);
return -EINVAL;
}
+ clk_mux_reg &= ~0xf;
+ clk_mux_reg |= (uint32_t)csiphy_params->csid_core;
} else if (lane_mask == LANE_MASK_PHY_B) { /* PHY B */
/* 2 lane config */
num_lanes = 2;
@@ -348,11 +361,17 @@
pr_err("%s: invalid request\n", __func__);
return -EINVAL;
}
+ clk_mux_reg &= ~0xf0;
+ clk_mux_reg |= csiphy_params->csid_core << 4;
} else { /* None of available configurations */
pr_err("%s: invalid configuration requested\n", __func__);
return -EINVAL;
}
+ msm_camera_io_w(clk_mux_reg, csiphy_dev->clk_mux_base);
+ /* ensure write is done */
+ mb();
+
if (mode == AGGREGATE_MODE || mode == TWO_LANE_PHY_A) {
ret = msm_csiphy_snps_2_lane_config(csiphy_dev,
csiphy_params, TWO_LANE_PHY_A, num_lanes);
diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c
index 9a7d272..3679c59 100644
--- a/drivers/media/platform/msm/vidc/msm_venc.c
+++ b/drivers/media/platform/msm/vidc/msm_venc.c
@@ -2275,6 +2275,7 @@
enable.enable = 0;
pdata = &enable;
inst->clk_data.low_latency_mode = (bool) enable.enable;
+ msm_dcvs_try_enable(inst);
break;
}
case V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8:
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
index 4a0aa58..a665978 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c
@@ -114,14 +114,18 @@
{
struct recon_buf *binfo, *nextb;
struct vidc_input_cr_data *temp, *next;
- u32 min_cf = 0, max_cf = 0;
- u32 min_input_cr = 0, max_input_cr = 0, min_cr = 0, max_cr = 0;
+ u32 max_cr = 0, max_cf = 0, max_input_cr = 0;
+ u32 min_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO;
+ u32 min_input_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO;
+ u32 min_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR;
mutex_lock(&inst->reconbufs.lock);
list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.list, list) {
- min_cr = min(min_cr, binfo->CR);
+ if (binfo->CR)
+ min_cr = min(min_cr, binfo->CR);
+ if (binfo->CF)
+ min_cf = min(min_cf, binfo->CF);
max_cr = max(max_cr, binfo->CR);
- min_cf = min(min_cf, binfo->CF);
max_cf = max(max_cf, binfo->CF);
}
mutex_unlock(&inst->reconbufs.lock);
@@ -605,6 +609,7 @@
struct allowed_clock_rates_table *allowed_clks_tbl = NULL;
u64 rate = 0;
struct clock_data *dcvs = NULL;
+ u32 operating_rate, vsp_factor_num = 10, vsp_factor_den = 7;
core = inst->core;
dcvs = &inst->clk_data;
@@ -627,8 +632,19 @@
vsp_cycles = mbs_per_second * inst->clk_data.entry->vsp_cycles;
- /* 10 / 7 is overhead factor */
- vsp_cycles += (inst->clk_data.bitrate * 10) / 7;
+ operating_rate = inst->clk_data.operating_rate >> 16;
+ if (operating_rate > inst->prop.fps && inst->prop.fps) {
+ vsp_factor_num *= operating_rate;
+ vsp_factor_den *= inst->prop.fps;
+ }
+ //adjust factor for 2 core case, due to workload is not
+ //equally distributed on 2 cores, use 0.65 instead of 0.5
+ if (inst->clk_data.core_id == VIDC_CORE_ID_3) {
+ 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;
} else if (inst->session_type == MSM_VIDC_DECODER) {
vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles;
diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c
index b392610..f9bc79c 100644
--- a/drivers/media/platform/msm/vidc/msm_vidc_common.c
+++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c
@@ -2035,6 +2035,7 @@
struct msm_vidc_cb_cmd_done *response = data;
struct msm_vidc_inst *inst;
struct v4l2_event flush_event = {0};
+ struct recon_buf *binfo;
u32 *ptr = NULL;
enum hal_flush flush_type;
int rc;
@@ -2089,6 +2090,13 @@
goto exit;
}
+ mutex_lock(&inst->reconbufs.lock);
+ list_for_each_entry(binfo, &inst->reconbufs.list, list) {
+ binfo->CR = 0;
+ binfo->CF = 0;
+ }
+ mutex_unlock(&inst->reconbufs.lock);
+
dprintk(VIDC_DBG,
"Notify flush complete, flush_type: %x\n", flush_type);
v4l2_event_queue_fh(&inst->event_handler, &flush_event);
diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c
index 7e7ed47..ade04e3 100644
--- a/drivers/media/platform/msm/vidc/venus_hfi.c
+++ b/drivers/media/platform/msm/vidc/venus_hfi.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
@@ -60,6 +60,9 @@
/* Poll interval in uS */
#define POLL_INTERVAL_US 50
+#define VENUS_AXI_HALT_ACK_TIMEOUT_US 500000
+
+
enum tzbsp_video_state {
TZBSP_VIDEO_STATE_SUSPEND = 0,
TZBSP_VIDEO_STATE_RESUME = 1,
@@ -2850,12 +2853,52 @@
mutex_unlock(&device->lock);
}
+static int __halt_axi(struct venus_hfi_device *device)
+{
+ u32 reg;
+ int rc = 0;
+
+ if (!device) {
+ dprintk(VIDC_ERR, "Invalid input\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Driver needs to make sure that clocks are enabled to read Venus AXI
+ * registers. If not skip AXI HALT.
+ */
+ if (!device->power_enabled) {
+ dprintk(VIDC_WARN,
+ "Clocks are OFF, skipping AXI HALT\n");
+ return -EINVAL;
+ }
+
+ /* Halt AXI and AXI IMEM VBIF Access */
+ reg = __read_register(device, VENUS_WRAPPER_AXI_HALT);
+ reg |= BRIC_AXI_HALT;
+ __write_register(device, VENUS_WRAPPER_AXI_HALT, reg);
+
+ /* Request for AXI bus port halt */
+ rc = readl_poll_timeout(device->hal_data->register_base
+ + VENUS_WRAPPER_AXI_HALT_STATUS,
+ reg, reg & BRIC_AXI_HALT_ACK,
+ POLL_INTERVAL_US,
+ VENUS_AXI_HALT_ACK_TIMEOUT_US);
+ if (rc)
+ dprintk(VIDC_WARN, "AXI bus port halt timeout\n");
+
+ return rc;
+}
+
static void __process_sys_error(struct venus_hfi_device *device)
{
struct hfi_sfr_struct *vsfr = NULL;
__set_state(device, VENUS_STATE_DEINIT);
+ if (__halt_axi(device))
+ dprintk(VIDC_WARN, "Failed to halt AXI after SYS_ERROR\n");
+
vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr;
if (vsfr) {
void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize);
diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
index 3433483..3ddd633 100644
--- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h
+++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h
@@ -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
@@ -148,6 +148,12 @@
#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
+#define VENUS_WRAPPER_AXI_HALT 0x000E2008
+#define VENUS_WRAPPER_AXI_HALT_STATUS 0x000E200C
+
+#define BRIC_AXI_HALT BIT(16)
+#define BRIC_AXI_HALT_ACK BIT(16)
+
#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \
(VIDC_WRAPPER_BASE_OFFS + 0x20)
#define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index c12209c..390d708 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -2169,6 +2169,12 @@
pxa_dma_stop_channels(pcdev);
pxa_camera_destroy_formats(pcdev);
+
+ if (pcdev->mclk_clk) {
+ v4l2_clk_unregister(pcdev->mclk_clk);
+ pcdev->mclk_clk = NULL;
+ }
+
video_unregister_device(&pcdev->vdev);
pcdev->sensor = NULL;
@@ -2495,7 +2501,13 @@
dma_release_channel(pcdev->dma_chans[1]);
dma_release_channel(pcdev->dma_chans[2]);
- v4l2_clk_unregister(pcdev->mclk_clk);
+ v4l2_async_notifier_unregister(&pcdev->notifier);
+
+ if (pcdev->mclk_clk) {
+ v4l2_clk_unregister(pcdev->mclk_clk);
+ pcdev->mclk_clk = NULL;
+ }
+
v4l2_device_unregister(&pcdev->v4l2_dev);
dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index db525cd..d9f88a4 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1381,8 +1381,13 @@
goto rc_dev_fail;
/* wire up inbound data handler */
- usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
- mceusb_dev_recv, ir, ep_in->bInterval);
+ if (usb_endpoint_xfer_int(ep_in))
+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+ mceusb_dev_recv, ir, ep_in->bInterval);
+ else
+ usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp,
+ mceusb_dev_recv, ir);
+
ir->urb_in->transfer_dma = ir->dma_in;
ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index 0324633..e56a49a 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -109,6 +109,8 @@
return 0;
usbtv_audio_fail:
+ /* we must not free at this point */
+ usb_get_dev(usbtv->udev);
usbtv_video_free(usbtv);
usbtv_video_fail:
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 9eaab98..d4e93f1 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -101,7 +101,7 @@
static int put_v4l2_window32(struct v4l2_window __user *kp,
struct v4l2_window32 __user *up)
{
- struct v4l2_clip __user *kclips = kp->clips;
+ struct v4l2_clip __user *kclips;
struct v4l2_clip32 __user *uclips;
compat_caddr_t p;
u32 clipcount;
@@ -116,6 +116,8 @@
if (!clipcount)
return 0;
+ if (get_user(kclips, &kp->clips))
+ return -EFAULT;
if (get_user(p, &up->clips))
return -EFAULT;
uclips = compat_ptr(p);
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 9ccf7f5..4299ce0 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -334,6 +334,10 @@
struct vb2_buffer *vb;
int ret;
+ /* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */
+ num_buffers = min_t(unsigned int, num_buffers,
+ VB2_MAX_FRAME - q->num_buffers);
+
for (buffer = 0; buffer < num_buffers; ++buffer) {
/* Allocate videobuf buffer structures */
vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c
index c63d61e..381a9a1 100644
--- a/drivers/misc/cxl/flash.c
+++ b/drivers/misc/cxl/flash.c
@@ -401,8 +401,10 @@
if (down_interruptible(&sem) != 0)
return -EPERM;
- if (!(adapter = get_cxl_adapter(adapter_num)))
- return -ENODEV;
+ if (!(adapter = get_cxl_adapter(adapter_num))) {
+ rc = -ENODEV;
+ goto err_unlock;
+ }
file->private_data = adapter;
continue_token = 0;
@@ -446,6 +448,8 @@
free_page((unsigned long) le);
err:
put_device(&adapter->dev);
+err_unlock:
+ up(&sem);
return rc;
}
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index 41f3186..60f5a8d 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -551,7 +551,6 @@
break;
default:
- dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd);
rets = -ENOIOCTLCMD;
}
diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c
index 728c65a..a940f97 100644
--- a/drivers/misc/uid_sys_stats.c
+++ b/drivers/misc/uid_sys_stats.c
@@ -14,6 +14,7 @@
*/
#include <linux/atomic.h>
+#include <linux/cpufreq_times.h>
#include <linux/err.h>
#include <linux/hashtable.h>
#include <linux/init.h>
@@ -422,6 +423,10 @@
kstrtol(end_uid, 10, &uid_end) != 0) {
return -EINVAL;
}
+
+ /* Also remove uids from /proc/uid_time_in_state */
+ cpufreq_task_times_remove_uids(uid_start, uid_end);
+
rt_mutex_lock(&uid_lock);
for (; uid_start <= uid_end; uid_start++) {
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index f84a427..f735ab4 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -298,8 +298,11 @@
size_t pas_size;
size_t vas_size;
size_t queue_size = sizeof(*queue) + sizeof(*queue->kernel_if);
- const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+ u64 num_pages;
+ if (size > SIZE_MAX - PAGE_SIZE)
+ return NULL;
+ num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
if (num_pages >
(SIZE_MAX - queue_size) /
(sizeof(*queue->kernel_if->u.g.pas) +
@@ -624,9 +627,12 @@
{
struct vmci_queue *queue;
size_t queue_page_size;
- const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
+ u64 num_pages;
const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if));
+ if (size > SIZE_MAX - PAGE_SIZE)
+ return NULL;
+ num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1;
if (num_pages > (SIZE_MAX - queue_size) /
sizeof(*queue->kernel_if->u.h.page))
return NULL;
diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c
index 684087d..1752007 100644
--- a/drivers/mmc/host/jz4740_mmc.c
+++ b/drivers/mmc/host/jz4740_mmc.c
@@ -368,9 +368,9 @@
host->irq_mask &= ~irq;
else
host->irq_mask |= irq;
- spin_unlock_irqrestore(&host->lock, flags);
writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK);
+ spin_unlock_irqrestore(&host->lock, flags);
}
static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host,
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index b0b9ceb..cfb7947 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -492,6 +492,8 @@
slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
break;
case INTEL_MRFLD_SDIO:
+ /* Advertise 2.0v for compatibility with the SDIO card's OCR */
+ slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195;
slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE |
MMC_CAP_POWER_OFF_CARD;
break;
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b674b38..36aecd2 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1575,6 +1575,13 @@
if (mode != MMC_POWER_OFF) {
switch (1 << vdd) {
case MMC_VDD_165_195:
+ /*
+ * Without a regulator, SDHCI does not support 2.0v
+ * so we only get here if the driver deliberately
+ * added the 2.0v range to ocr_avail. Map it to 1.8v
+ * for the purpose of turning on the power.
+ */
+ case MMC_VDD_20_21:
pwr = SDHCI_POWER_180;
break;
case MMC_VDD_29_30:
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 7c0b27d..b479bd8 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -1889,6 +1889,8 @@
do {
uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi);
mask = (1 << (cfi->device_type * 8)) - 1;
+ if (ofs >= map->size)
+ return 0;
result = map_read(map, base + ofs);
bank++;
} while ((result.x[0] & mask) == CFI_MFR_CONTINUATION);
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 427039b..d9dab42 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -2047,18 +2047,20 @@
ret = nand_boot_init(this);
if (ret)
- goto err_out;
+ goto err_nand_cleanup;
ret = chip->scan_bbt(mtd);
if (ret)
- goto err_out;
+ goto err_nand_cleanup;
ret = mtd_device_register(mtd, NULL, 0);
if (ret)
- goto err_out;
+ goto err_nand_cleanup;
return 0;
+err_nand_cleanup:
+ nand_cleanup(chip);
err_out:
- gpmi_nand_exit(this);
+ gpmi_free_dma_buffer(this);
return ret;
}
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a3e86e5..5fb4516 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -4785,6 +4785,11 @@
goto err_free;
}
ecc->total = ecc->steps * ecc->bytes;
+ if (ecc->total > mtd->oobsize) {
+ WARN(1, "Total number of ECC bytes exceeded oobsize\n");
+ ret = -EINVAL;
+ goto err_free;
+ }
/*
* The number of bytes available for a client to place data into
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c
index 1cb3f77..766b2c3 100644
--- a/drivers/mtd/tests/oobtest.c
+++ b/drivers/mtd/tests/oobtest.c
@@ -193,6 +193,9 @@
ops.datbuf = NULL;
ops.oobbuf = readbuf;
err = mtd_read_oob(mtd, addr, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err || ops.oobretlen != use_len) {
pr_err("error: readoob failed at %#llx\n",
(long long)addr);
@@ -227,6 +230,9 @@
ops.datbuf = NULL;
ops.oobbuf = readbuf;
err = mtd_read_oob(mtd, addr, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err || ops.oobretlen != mtd->oobavail) {
pr_err("error: readoob failed at %#llx\n",
(long long)addr);
@@ -286,6 +292,9 @@
/* read entire block's OOB at one go */
err = mtd_read_oob(mtd, addr, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err || ops.oobretlen != len) {
pr_err("error: readoob failed at %#llx\n",
(long long)addr);
@@ -527,6 +536,9 @@
pr_info("attempting to start read past end of OOB\n");
pr_info("an error is expected...\n");
err = mtd_read_oob(mtd, addr0, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err) {
pr_info("error occurred as expected\n");
err = 0;
@@ -571,6 +583,9 @@
pr_info("attempting to read past end of device\n");
pr_info("an error is expected...\n");
err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err) {
pr_info("error occurred as expected\n");
err = 0;
@@ -615,6 +630,9 @@
pr_info("attempting to read past end of device\n");
pr_info("an error is expected...\n");
err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err) {
pr_info("error occurred as expected\n");
err = 0;
@@ -684,6 +702,9 @@
ops.datbuf = NULL;
ops.oobbuf = readbuf;
err = mtd_read_oob(mtd, addr, &ops);
+ if (mtd_is_bitflip(err))
+ err = 0;
+
if (err)
goto out;
if (memcmpshow(addr, readbuf, writebuf,
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 46913ef2..479a5f0 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -244,7 +244,7 @@
* in any case.
*/
if (mode & FMODE_WRITE) {
- ret = -EPERM;
+ ret = -EROFS;
goto out_unlock;
}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index e1da78f..68902b8 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -894,6 +894,17 @@
return -EINVAL;
}
+ /*
+ * Both UBI and UBIFS have been designed for SLC NAND and NOR flashes.
+ * MLC NAND is different and needs special care, otherwise UBI or UBIFS
+ * will die soon and you will lose all your data.
+ */
+ if (mtd->type == MTD_MLCNANDFLASH) {
+ pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n",
+ mtd->index);
+ return -EINVAL;
+ }
+
if (ubi_num == UBI_DEV_NUM_AUTO) {
/* Search for an empty slot in the @ubi_devices array */
for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++)
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index 4f0bd6b..69dd216 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -362,7 +362,6 @@
{
int i;
- flush_work(&ubi->fm_work);
return_unused_pool_pebs(ubi, &ubi->fm_pool);
return_unused_pool_pebs(ubi, &ubi->fm_wl_pool);
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index c1f5c29..b44c8d3 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -828,6 +828,24 @@
return ret;
}
+static struct ubi_ainf_peb *clone_aeb(struct ubi_attach_info *ai,
+ struct ubi_ainf_peb *old)
+{
+ struct ubi_ainf_peb *new;
+
+ new = ubi_alloc_aeb(ai, old->pnum, old->ec);
+ if (!new)
+ return NULL;
+
+ new->vol_id = old->vol_id;
+ new->sqnum = old->sqnum;
+ new->lnum = old->lnum;
+ new->scrub = old->scrub;
+ new->copy_flag = old->copy_flag;
+
+ return new;
+}
+
/**
* ubi_scan_fastmap - scan the fastmap.
* @ubi: UBI device object
@@ -847,7 +865,7 @@
struct ubi_vid_hdr *vh;
struct ubi_ec_hdr *ech;
struct ubi_fastmap_layout *fm;
- struct ubi_ainf_peb *tmp_aeb, *aeb;
+ struct ubi_ainf_peb *aeb;
int i, used_blocks, pnum, fm_anchor, ret = 0;
size_t fm_size;
__be32 crc, tmp_crc;
@@ -857,9 +875,16 @@
if (fm_anchor < 0)
return UBI_NO_FASTMAP;
- /* Move all (possible) fastmap blocks into our new attach structure. */
- list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list)
- list_move_tail(&aeb->u.list, &ai->fastmap);
+ /* Copy all (possible) fastmap blocks into our new attach structure. */
+ list_for_each_entry(aeb, &scan_ai->fastmap, u.list) {
+ struct ubi_ainf_peb *new;
+
+ new = clone_aeb(ai, aeb);
+ if (!new)
+ return -ENOMEM;
+
+ list_add(&new->u.list, &ai->fastmap);
+ }
down_write(&ubi->fm_protect);
memset(ubi->fm_buf, 0, ubi->fm_size);
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 4907c9b..513457a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1524,39 +1524,6 @@
goto err_close;
}
- /* If the mode uses primary, then the following is handled by
- * bond_change_active_slave().
- */
- if (!bond_uses_primary(bond)) {
- /* set promiscuity level to new slave */
- if (bond_dev->flags & IFF_PROMISC) {
- res = dev_set_promiscuity(slave_dev, 1);
- if (res)
- goto err_close;
- }
-
- /* set allmulti level to new slave */
- if (bond_dev->flags & IFF_ALLMULTI) {
- res = dev_set_allmulti(slave_dev, 1);
- if (res)
- goto err_close;
- }
-
- netif_addr_lock_bh(bond_dev);
-
- dev_mc_sync_multiple(slave_dev, bond_dev);
- dev_uc_sync_multiple(slave_dev, bond_dev);
-
- netif_addr_unlock_bh(bond_dev);
- }
-
- if (BOND_MODE(bond) == BOND_MODE_8023AD) {
- /* add lacpdu mc addr to mc list */
- u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
-
- dev_mc_add(slave_dev, lacpdu_multicast);
- }
-
res = vlan_vids_add_by_dev(slave_dev, bond_dev);
if (res) {
netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n",
@@ -1719,6 +1686,40 @@
goto err_upper_unlink;
}
+ /* If the mode uses primary, then the following is handled by
+ * bond_change_active_slave().
+ */
+ if (!bond_uses_primary(bond)) {
+ /* set promiscuity level to new slave */
+ if (bond_dev->flags & IFF_PROMISC) {
+ res = dev_set_promiscuity(slave_dev, 1);
+ if (res)
+ goto err_sysfs_del;
+ }
+
+ /* set allmulti level to new slave */
+ if (bond_dev->flags & IFF_ALLMULTI) {
+ res = dev_set_allmulti(slave_dev, 1);
+ if (res) {
+ if (bond_dev->flags & IFF_PROMISC)
+ dev_set_promiscuity(slave_dev, -1);
+ goto err_sysfs_del;
+ }
+ }
+
+ netif_addr_lock_bh(bond_dev);
+ dev_mc_sync_multiple(slave_dev, bond_dev);
+ dev_uc_sync_multiple(slave_dev, bond_dev);
+ netif_addr_unlock_bh(bond_dev);
+
+ if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+ /* add lacpdu mc addr to mc list */
+ u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
+
+ dev_mc_add(slave_dev, lacpdu_multicast);
+ }
+ }
+
bond->slave_cnt++;
bond_compute_features(bond);
bond_set_carrier(bond);
@@ -1742,6 +1743,9 @@
return 0;
/* Undo stages on error */
+err_sysfs_del:
+ bond_sysfs_slave_del(new_slave);
+
err_upper_unlink:
bond_upper_dev_unlink(bond, new_slave);
@@ -1749,9 +1753,6 @@
netdev_rx_handler_unregister(slave_dev);
err_detach:
- if (!bond_uses_primary(bond))
- bond_hw_addr_flush(bond_dev, slave_dev);
-
vlan_vids_del_by_dev(slave_dev, bond_dev);
if (rcu_access_pointer(bond->primary_slave) == new_slave)
RCU_INIT_POINTER(bond->primary_slave, NULL);
@@ -2605,11 +2606,13 @@
bond_for_each_slave_rcu(bond, slave, iter) {
unsigned long trans_start = dev_trans_start(slave->dev);
+ slave->new_link = BOND_LINK_NOCHANGE;
+
if (slave->link != BOND_LINK_UP) {
if (bond_time_in_interval(bond, trans_start, 1) &&
bond_time_in_interval(bond, slave->last_rx, 1)) {
- slave->link = BOND_LINK_UP;
+ slave->new_link = BOND_LINK_UP;
slave_state_changed = 1;
/* primary_slave has no meaning in round-robin
@@ -2636,7 +2639,7 @@
if (!bond_time_in_interval(bond, trans_start, 2) ||
!bond_time_in_interval(bond, slave->last_rx, 2)) {
- slave->link = BOND_LINK_DOWN;
+ slave->new_link = BOND_LINK_DOWN;
slave_state_changed = 1;
if (slave->link_failure_count < UINT_MAX)
@@ -2667,6 +2670,11 @@
if (!rtnl_trylock())
goto re_arm;
+ bond_for_each_slave(bond, slave, iter) {
+ if (slave->new_link != BOND_LINK_NOCHANGE)
+ slave->link = slave->new_link;
+ }
+
if (slave_state_changed) {
bond_slave_state_change(bond);
if (BOND_MODE(bond) == BOND_MODE_XOR)
diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c
index e2512ab..e13c9cd 100644
--- a/drivers/net/ethernet/amazon/ena/ena_com.c
+++ b/drivers/net/ethernet/amazon/ena/ena_com.c
@@ -61,6 +61,8 @@
#define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF
+#define ENA_REGS_ADMIN_INTR_MASK 1
+
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
@@ -232,11 +234,9 @@
tail_masked = admin_queue->sq.tail & queue_size_mask;
/* In case of queue FULL */
- cnt = admin_queue->sq.tail - admin_queue->sq.head;
+ cnt = atomic_read(&admin_queue->outstanding_cmds);
if (cnt >= admin_queue->q_depth) {
- pr_debug("admin queue is FULL (tail %d head %d depth: %d)\n",
- admin_queue->sq.tail, admin_queue->sq.head,
- admin_queue->q_depth);
+ pr_debug("admin queue is full.\n");
admin_queue->stats.out_of_space++;
return ERR_PTR(-ENOSPC);
}
@@ -508,15 +508,20 @@
static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx,
struct ena_com_admin_queue *admin_queue)
{
- unsigned long flags;
- u32 start_time;
+ unsigned long flags, timeout;
int ret;
- start_time = ((u32)jiffies_to_usecs(jiffies));
+ timeout = jiffies + ADMIN_CMD_TIMEOUT_US;
- while (comp_ctx->status == ENA_CMD_SUBMITTED) {
- if ((((u32)jiffies_to_usecs(jiffies)) - start_time) >
- ADMIN_CMD_TIMEOUT_US) {
+ while (1) {
+ spin_lock_irqsave(&admin_queue->q_lock, flags);
+ ena_com_handle_admin_completion(admin_queue);
+ spin_unlock_irqrestore(&admin_queue->q_lock, flags);
+
+ if (comp_ctx->status != ENA_CMD_SUBMITTED)
+ break;
+
+ if (time_is_before_jiffies(timeout)) {
pr_err("Wait for completion (polling) timeout\n");
/* ENA didn't have any completion */
spin_lock_irqsave(&admin_queue->q_lock, flags);
@@ -528,10 +533,6 @@
goto err;
}
- spin_lock_irqsave(&admin_queue->q_lock, flags);
- ena_com_handle_admin_completion(admin_queue);
- spin_unlock_irqrestore(&admin_queue->q_lock, flags);
-
msleep(100);
}
@@ -1449,6 +1450,12 @@
void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling)
{
+ u32 mask_value = 0;
+
+ if (polling)
+ mask_value = ENA_REGS_ADMIN_INTR_MASK;
+
+ writel(mask_value, ena_dev->reg_bar + ENA_REGS_INTR_MASK_OFF);
ena_dev->admin_queue.polling = polling;
}
diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c
index bfeaec5..0d9ce08 100644
--- a/drivers/net/ethernet/amazon/ena/ena_netdev.c
+++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c
@@ -1542,6 +1542,7 @@
"Failed to get TX queue handlers. TX queue num %d rc: %d\n",
qid, rc);
ena_com_destroy_io_queue(ena_dev, ena_qid);
+ return rc;
}
ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node);
@@ -1606,6 +1607,7 @@
"Failed to get RX queue handlers. RX queue num %d rc: %d\n",
qid, rc);
ena_com_destroy_io_queue(ena_dev, ena_qid);
+ return rc;
}
ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node);
@@ -2806,6 +2808,11 @@
{
int release_bars;
+ if (ena_dev->mem_bar)
+ devm_iounmap(&pdev->dev, ena_dev->mem_bar);
+
+ devm_iounmap(&pdev->dev, ena_dev->reg_bar);
+
release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK;
pci_release_selected_regions(pdev, release_bars);
}
@@ -2893,8 +2900,9 @@
goto err_free_ena_dev;
}
- ena_dev->reg_bar = ioremap(pci_resource_start(pdev, ENA_REG_BAR),
- pci_resource_len(pdev, ENA_REG_BAR));
+ ena_dev->reg_bar = devm_ioremap(&pdev->dev,
+ pci_resource_start(pdev, ENA_REG_BAR),
+ pci_resource_len(pdev, ENA_REG_BAR));
if (!ena_dev->reg_bar) {
dev_err(&pdev->dev, "failed to remap regs bar\n");
rc = -EFAULT;
@@ -2914,8 +2922,9 @@
ena_set_push_mode(pdev, ena_dev, &get_feat_ctx);
if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) {
- ena_dev->mem_bar = ioremap_wc(pci_resource_start(pdev, ENA_MEM_BAR),
- pci_resource_len(pdev, ENA_MEM_BAR));
+ ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev,
+ pci_resource_start(pdev, ENA_MEM_BAR),
+ pci_resource_len(pdev, ENA_MEM_BAR));
if (!ena_dev->mem_bar) {
rc = -EFAULT;
goto err_device_destroy;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index 651f308..fca2e42 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -1680,6 +1680,30 @@
}
}
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_enet_acpi_match[] = {
+ { "APMC0D05", XGENE_ENET1},
+ { "APMC0D30", XGENE_ENET1},
+ { "APMC0D31", XGENE_ENET1},
+ { "APMC0D3F", XGENE_ENET1},
+ { "APMC0D26", XGENE_ENET2},
+ { "APMC0D25", XGENE_ENET2},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
+#endif
+
+static const struct of_device_id xgene_enet_of_match[] = {
+ {.compatible = "apm,xgene-enet", .data = (void *)XGENE_ENET1},
+ {.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1},
+ {.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1},
+ {.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2},
+ {.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, xgene_enet_of_match);
+
static int xgene_enet_probe(struct platform_device *pdev)
{
struct net_device *ndev;
@@ -1826,32 +1850,6 @@
xgene_enet_remove(pdev);
}
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_enet_acpi_match[] = {
- { "APMC0D05", XGENE_ENET1},
- { "APMC0D30", XGENE_ENET1},
- { "APMC0D31", XGENE_ENET1},
- { "APMC0D3F", XGENE_ENET1},
- { "APMC0D26", XGENE_ENET2},
- { "APMC0D25", XGENE_ENET2},
- { }
-};
-MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
-#endif
-
-#ifdef CONFIG_OF
-static const struct of_device_id xgene_enet_of_match[] = {
- {.compatible = "apm,xgene-enet", .data = (void *)XGENE_ENET1},
- {.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1},
- {.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1},
- {.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2},
- {.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2},
- {},
-};
-
-MODULE_DEVICE_TABLE(of, xgene_enet_of_match);
-#endif
-
static struct platform_driver xgene_enet_driver = {
.driver = {
.name = "xgene-enet",
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index ca6c471..31287ce 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -3887,15 +3887,26 @@
/* when transmitting in a vf, start bd must hold the ethertype
* for fw to enforce it
*/
+ u16 vlan_tci = 0;
#ifndef BNX2X_STOP_ON_ERROR
- if (IS_VF(bp))
+ if (IS_VF(bp)) {
#endif
- tx_start_bd->vlan_or_ethertype =
- cpu_to_le16(ntohs(eth->h_proto));
+ /* Still need to consider inband vlan for enforced */
+ if (__vlan_get_tag(skb, &vlan_tci)) {
+ tx_start_bd->vlan_or_ethertype =
+ cpu_to_le16(ntohs(eth->h_proto));
+ } else {
+ tx_start_bd->bd_flags.as_bitfield |=
+ (X_ETH_INBAND_VLAN <<
+ ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
+ tx_start_bd->vlan_or_ethertype =
+ cpu_to_le16(vlan_tci);
+ }
#ifndef BNX2X_STOP_ON_ERROR
- else
+ } else {
/* used by FW for packet accounting */
tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod);
+ }
#endif
}
diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
index 0f68118..a36e386 100644
--- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c
+++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c
@@ -2845,7 +2845,7 @@
static void
bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer)
{
- memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
+ strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN);
}
static void
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 0c2a32a..3ec32d7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -2742,6 +2742,16 @@
return -EOPNOTSUPP;
}
+static netdev_features_t cxgb_fix_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ /* Disable GRO, if RX_CSUM is disabled */
+ if (!(features & NETIF_F_RXCSUM))
+ features &= ~NETIF_F_GRO;
+
+ return features;
+}
+
static const struct net_device_ops cxgb4_netdev_ops = {
.ndo_open = cxgb_open,
.ndo_stop = cxgb_close,
@@ -2766,6 +2776,7 @@
#endif
.ndo_set_tx_maxrate = cxgb_set_tx_maxrate,
.ndo_setup_tc = cxgb_setup_tc,
+ .ndo_fix_features = cxgb_fix_features,
};
#ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index 6fd3be6..ebeeb35 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -6185,13 +6185,18 @@
if (!t4_fw_matches_chip(adap, fw_hdr))
return -EINVAL;
+ /* Disable FW_OK flag so that mbox commands with FW_OK flag set
+ * wont be sent when we are flashing FW.
+ */
+ adap->flags &= ~FW_OK;
+
ret = t4_fw_halt(adap, mbox, force);
if (ret < 0 && !force)
- return ret;
+ goto out;
ret = t4_load_fw(adap, fw_data, size);
if (ret < 0)
- return ret;
+ goto out;
/*
* Older versions of the firmware don't understand the new
@@ -6202,7 +6207,17 @@
* its header flags to see if it advertises the capability.
*/
reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0);
- return t4_fw_restart(adap, mbox, reset);
+ ret = t4_fw_restart(adap, mbox, reset);
+
+ /* Grab potentially new Firmware Device Log parameters so we can see
+ * how healthy the new Firmware is. It's okay to contact the new
+ * Firmware for these parameters even though, as far as it's
+ * concerned, we've never said "HELLO" to it ...
+ */
+ (void)t4_init_devlog_params(adap);
+out:
+ adap->flags |= FW_OK;
+ return ret;
}
/**
@@ -8073,7 +8088,16 @@
ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]);
if (ret)
break;
- idx = (idx + 1) & UPDBGLARDPTR_M;
+
+ /* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to
+ * identify the 32-bit portion of the full 312-bit data
+ */
+ if (is_t6(adap->params.chip) && (idx & 0xf) >= 9)
+ idx = (idx & 0xff0) + 0x10;
+ else
+ idx++;
+ /* address can't exceed 0xfff */
+ idx &= UPDBGLARDPTR_M;
}
restart:
if (cfg & UPDBGLAEN_F) {
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index f3ed9ce..9d64e8e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -2616,8 +2616,8 @@
int t4vf_sge_init(struct adapter *adapter)
{
struct sge_params *sge_params = &adapter->params.sge;
- u32 fl0 = sge_params->sge_fl_buffer_size[0];
- u32 fl1 = sge_params->sge_fl_buffer_size[1];
+ u32 fl_small_pg = sge_params->sge_fl_buffer_size[0];
+ u32 fl_large_pg = sge_params->sge_fl_buffer_size[1];
struct sge *s = &adapter->sge;
/*
@@ -2625,9 +2625,20 @@
* the Physical Function Driver. Ideally we should be able to deal
* with _any_ configuration. Practice is different ...
*/
- if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) {
+
+ /* We only bother using the Large Page logic if the Large Page Buffer
+ * is larger than our Page Size Buffer.
+ */
+ if (fl_large_pg <= fl_small_pg)
+ fl_large_pg = 0;
+
+ /* The Page Size Buffer must be exactly equal to our Page Size and the
+ * Large Page Size Buffer should be 0 (per above) or a power of 2.
+ */
+ if (fl_small_pg != PAGE_SIZE ||
+ (fl_large_pg & (fl_large_pg - 1)) != 0) {
dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n",
- fl0, fl1);
+ fl_small_pg, fl_large_pg);
return -EINVAL;
}
if ((sge_params->sge_control & RXPKTCPLMODE_F) !=
@@ -2639,8 +2650,8 @@
/*
* Now translate the adapter parameters into our internal forms.
*/
- if (fl1)
- s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT;
+ if (fl_large_pg)
+ s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT;
s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F)
? 128 : 64);
s->pktshift = PKTSHIFT_G(sge_params->sge_control);
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 05e5b38..fe00f71 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -2371,6 +2371,10 @@
static inline void fec_enet_update_ethtool_stats(struct net_device *dev)
{
}
+
+static inline void fec_enet_clear_ethtool_stats(struct net_device *dev)
+{
+}
#endif /* !defined(CONFIG_M5272) */
static int fec_enet_nway_reset(struct net_device *dev)
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 446c7b3..a10de1e 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -381,7 +381,7 @@
{
const struct of_device_id *id =
of_match_device(fsl_pq_mdio_match, &pdev->dev);
- const struct fsl_pq_mdio_data *data = id->data;
+ const struct fsl_pq_mdio_data *data;
struct device_node *np = pdev->dev.of_node;
struct resource res;
struct device_node *tbi;
@@ -389,6 +389,13 @@
struct mii_bus *new_bus;
int err;
+ if (!id) {
+ dev_err(&pdev->dev, "Failed to match device\n");
+ return -ENODEV;
+ }
+
+ data = id->data;
+
dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible);
new_bus = mdiobus_alloc_size(sizeof(*priv));
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
index 34b5e69..02a03bc 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
@@ -671,7 +671,7 @@
static int hns_gmac_get_sset_count(int stringset)
{
- if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+ if (stringset == ETH_SS_STATS)
return ARRAY_SIZE(g_gmac_stats_string);
return 0;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
index 4ecb809..6ea8722 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
@@ -422,7 +422,7 @@
int hns_ppe_get_sset_count(int stringset)
{
- if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+ if (stringset == ETH_SS_STATS)
return ETH_PPE_STATIC_NUM;
return 0;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
index fbbbbff..f3be9ac 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
@@ -798,7 +798,7 @@
*/
int hns_rcb_get_ring_sset_count(int stringset)
{
- if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+ if (stringset == ETH_SS_STATS)
return HNS_RING_STATIC_REG_NUM;
return 0;
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
index 86a496d..6be0cae 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
@@ -1017,8 +1017,10 @@
cnt--;
return cnt;
- } else {
+ } else if (stringset == ETH_SS_STATS) {
return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset));
+ } else {
+ return -EOPNOTSUPP;
}
}
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 8f13919..5977b69 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -342,6 +342,7 @@
{
struct emac_regs __iomem *p = dev->emacp;
int n = 20;
+ bool __maybe_unused try_internal_clock = false;
DBG(dev, "reset" NL);
@@ -354,6 +355,7 @@
}
#ifdef CONFIG_PPC_DCR_NATIVE
+do_retry:
/*
* PPC460EX/GT Embedded Processor Advanced User's Manual
* section 28.10.1 Mode Register 0 (EMACx_MR0) states:
@@ -361,10 +363,19 @@
* of the EMAC. If none is present, select the internal clock
* (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1).
* After a soft reset, select the external clock.
+ *
+ * The AR8035-A PHY Meraki MR24 does not provide a TX Clk if the
+ * ethernet cable is not attached. This causes the reset to timeout
+ * and the PHY detection code in emac_init_phy() is unable to
+ * communicate and detect the AR8035-A PHY. As a result, the emac
+ * driver bails out early and the user has no ethernet.
+ * In order to stay compatible with existing configurations, the
+ * driver will temporarily switch to the internal clock, after
+ * the first reset fails.
*/
if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
- if (dev->phy_address == 0xffffffff &&
- dev->phy_map == 0xffffffff) {
+ if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+ dev->phy_map == 0xffffffff)) {
/* No PHY: select internal loop clock before reset */
dcri_clrset(SDR0, SDR0_ETH_CFG,
0, SDR0_ETH_CFG_ECS << dev->cell_index);
@@ -382,8 +393,15 @@
#ifdef CONFIG_PPC_DCR_NATIVE
if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) {
- if (dev->phy_address == 0xffffffff &&
- dev->phy_map == 0xffffffff) {
+ if (!n && !try_internal_clock) {
+ /* first attempt has timed out. */
+ n = 20;
+ try_internal_clock = true;
+ goto do_retry;
+ }
+
+ if (try_internal_clock || (dev->phy_address == 0xffffffff &&
+ dev->phy_map == 0xffffffff)) {
/* No PHY: restore external clock source after reset */
dcri_clrset(SDR0, SDR0_ETH_CFG,
SDR0_ETH_CFG_ECS << dev->cell_index, 0);
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 528a926..825ec8f 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -1182,6 +1182,7 @@
struct e1000_hw *hw = &adapter->hw;
if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) {
+ struct sk_buff *skb = adapter->tx_hwtstamp_skb;
struct skb_shared_hwtstamps shhwtstamps;
u64 txstmp;
@@ -1190,9 +1191,14 @@
e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp);
- skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps);
- dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
+ /* Clear the global tx_hwtstamp_skb pointer and force writes
+ * prior to notifying the stack of a Tx timestamp.
+ */
adapter->tx_hwtstamp_skb = NULL;
+ wmb(); /* force write prior to skb_tstamp_tx */
+
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
} else if (time_after(jiffies, adapter->tx_hwtstamp_start
+ adapter->tx_timeout_factor * HZ)) {
dev_kfree_skb_any(adapter->tx_hwtstamp_skb);
@@ -6645,12 +6651,17 @@
static int e1000e_pm_suspend(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ int rc;
e1000e_flush_lpic(pdev);
e1000e_pm_freeze(dev);
- return __e1000_shutdown(pdev, false);
+ rc = __e1000_shutdown(pdev, false);
+ if (rc)
+ e1000e_pm_thaw(dev);
+
+ return rc;
}
static int e1000e_pm_resume(struct device *dev)
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index ddf478d..614f93e 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -154,6 +154,7 @@
adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES;
adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG;
caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 |
+ I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF |
I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ |
I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG |
I40E_VIRTCHNL_VF_OFFLOAD_VLAN |
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index a7895c4..9eb9b68 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -721,6 +721,7 @@
**/
static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter)
{
+ struct sk_buff *skb = adapter->ptp_tx_skb;
struct e1000_hw *hw = &adapter->hw;
struct skb_shared_hwtstamps shhwtstamps;
u64 regval;
@@ -748,10 +749,17 @@
shhwtstamps.hwtstamp =
ktime_add_ns(shhwtstamps.hwtstamp, adjust);
- skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps);
- dev_kfree_skb_any(adapter->ptp_tx_skb);
+ /* Clear the lock early before calling skb_tstamp_tx so that
+ * applications are not woken up before the lock bit is clear. We use
+ * a copy of the skb pointer to ensure other threads can't change it
+ * while we're notifying the stack.
+ */
adapter->ptp_tx_skb = NULL;
clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state);
+
+ /* Notify the stack and free the skb after we've unlocked */
+ skb_tstamp_tx(skb, &shhwtstamps);
+ dev_kfree_skb_any(skb);
}
/**
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 941c8e2..93ab0b3 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -5079,7 +5079,7 @@
INIT_WORK(&hw->restart_work, sky2_restart);
pci_set_drvdata(pdev, hw);
- pdev->d3_delay = 150;
+ pdev->d3_delay = 200;
return 0;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
index b04760a..af2e6ea 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
@@ -156,57 +156,63 @@
static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev)
{
struct mlx4_en_priv *priv = netdev_priv(netdev);
+ struct mlx4_en_port_profile *prof = priv->prof;
struct mlx4_en_dev *mdev = priv->mdev;
+ u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
if (!(priv->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
return 1;
if (priv->cee_config.pfc_state) {
int tc;
+ rx_ppp = prof->rx_ppp;
+ tx_ppp = prof->tx_ppp;
- priv->prof->rx_pause = 0;
- priv->prof->tx_pause = 0;
for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) {
u8 tc_mask = 1 << tc;
switch (priv->cee_config.dcb_pfc[tc]) {
case pfc_disabled:
- priv->prof->tx_ppp &= ~tc_mask;
- priv->prof->rx_ppp &= ~tc_mask;
+ tx_ppp &= ~tc_mask;
+ rx_ppp &= ~tc_mask;
break;
case pfc_enabled_full:
- priv->prof->tx_ppp |= tc_mask;
- priv->prof->rx_ppp |= tc_mask;
+ tx_ppp |= tc_mask;
+ rx_ppp |= tc_mask;
break;
case pfc_enabled_tx:
- priv->prof->tx_ppp |= tc_mask;
- priv->prof->rx_ppp &= ~tc_mask;
+ tx_ppp |= tc_mask;
+ rx_ppp &= ~tc_mask;
break;
case pfc_enabled_rx:
- priv->prof->tx_ppp &= ~tc_mask;
- priv->prof->rx_ppp |= tc_mask;
+ tx_ppp &= ~tc_mask;
+ rx_ppp |= tc_mask;
break;
default:
break;
}
}
- en_dbg(DRV, priv, "Set pfc on\n");
+ rx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->rx_pause;
+ tx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->tx_pause;
} else {
- priv->prof->rx_pause = 1;
- priv->prof->tx_pause = 1;
- en_dbg(DRV, priv, "Set pfc off\n");
+ rx_ppp = 0;
+ tx_ppp = 0;
+ rx_pause = prof->rx_pause;
+ tx_pause = prof->tx_pause;
}
if (mlx4_SET_PORT_general(mdev->dev, priv->port,
priv->rx_skb_size + ETH_FCS_LEN,
- priv->prof->tx_pause,
- priv->prof->tx_ppp,
- priv->prof->rx_pause,
- priv->prof->rx_ppp)) {
+ tx_pause, tx_ppp, rx_pause, rx_ppp)) {
en_err(priv, "Failed setting pause params\n");
return 1;
}
+ prof->tx_ppp = tx_ppp;
+ prof->rx_ppp = rx_ppp;
+ prof->tx_pause = tx_pause;
+ prof->rx_pause = rx_pause;
+
return 0;
}
@@ -310,6 +316,7 @@
}
switch (ets->tc_tsa[i]) {
+ case IEEE_8021QAZ_TSA_VENDOR:
case IEEE_8021QAZ_TSA_STRICT:
break;
case IEEE_8021QAZ_TSA_ETS:
@@ -347,6 +354,10 @@
/* higher TC means higher priority => lower pg */
for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) {
switch (ets->tc_tsa[i]) {
+ case IEEE_8021QAZ_TSA_VENDOR:
+ pg[i] = MLX4_EN_TC_VENDOR;
+ tc_tx_bw[i] = MLX4_EN_BW_MAX;
+ break;
case IEEE_8021QAZ_TSA_STRICT:
pg[i] = num_strict++;
tc_tx_bw[i] = MLX4_EN_BW_MAX;
@@ -403,6 +414,7 @@
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_port_profile *prof = priv->prof;
struct mlx4_en_dev *mdev = priv->mdev;
+ u32 tx_pause, tx_ppp, rx_pause, rx_ppp;
int err;
en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n",
@@ -411,23 +423,26 @@
pfc->mbc,
pfc->delay);
- prof->rx_pause = !pfc->pfc_en;
- prof->tx_pause = !pfc->pfc_en;
- prof->rx_ppp = pfc->pfc_en;
- prof->tx_ppp = pfc->pfc_en;
+ rx_pause = prof->rx_pause && !pfc->pfc_en;
+ tx_pause = prof->tx_pause && !pfc->pfc_en;
+ rx_ppp = pfc->pfc_en;
+ tx_ppp = pfc->pfc_en;
err = mlx4_SET_PORT_general(mdev->dev, priv->port,
priv->rx_skb_size + ETH_FCS_LEN,
- prof->tx_pause,
- prof->tx_ppp,
- prof->rx_pause,
- prof->rx_ppp);
- if (err)
+ tx_pause, tx_ppp, rx_pause, rx_ppp);
+ if (err) {
en_err(priv, "Failed setting pause params\n");
- else
- mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
- prof->rx_ppp, prof->rx_pause,
- prof->tx_ppp, prof->tx_pause);
+ return err;
+ }
+
+ mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+ rx_ppp, rx_pause, tx_ppp, tx_pause);
+
+ prof->tx_ppp = tx_ppp;
+ prof->rx_ppp = rx_ppp;
+ prof->rx_pause = rx_pause;
+ prof->tx_pause = tx_pause;
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index bdda17d..24977cc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -1003,27 +1003,32 @@
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
+ u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
int err;
if (pause->autoneg)
return -EINVAL;
- priv->prof->tx_pause = pause->tx_pause != 0;
- priv->prof->rx_pause = pause->rx_pause != 0;
+ tx_pause = !!(pause->tx_pause);
+ rx_pause = !!(pause->rx_pause);
+ rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause);
+ tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause);
+
err = mlx4_SET_PORT_general(mdev->dev, priv->port,
priv->rx_skb_size + ETH_FCS_LEN,
- priv->prof->tx_pause,
- priv->prof->tx_ppp,
- priv->prof->rx_pause,
- priv->prof->rx_ppp);
- if (err)
- en_err(priv, "Failed setting pause params\n");
- else
- mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
- priv->prof->rx_ppp,
- priv->prof->rx_pause,
- priv->prof->tx_ppp,
- priv->prof->tx_pause);
+ tx_pause, tx_ppp, rx_pause, rx_ppp);
+ if (err) {
+ en_err(priv, "Failed setting pause params, err = %d\n", err);
+ return err;
+ }
+
+ mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+ rx_ppp, rx_pause, tx_ppp, tx_pause);
+
+ priv->prof->tx_pause = tx_pause;
+ priv->prof->rx_pause = rx_pause;
+ priv->prof->tx_ppp = tx_ppp;
+ priv->prof->rx_ppp = rx_ppp;
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index bf7628d..22c3fdd 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -163,9 +163,9 @@
params->udp_rss = 0;
}
for (i = 1; i <= MLX4_MAX_PORTS; i++) {
- params->prof[i].rx_pause = 1;
+ params->prof[i].rx_pause = !(pfcrx || pfctx);
params->prof[i].rx_ppp = pfcrx;
- params->prof[i].tx_pause = 1;
+ params->prof[i].tx_pause = !(pfcrx || pfctx);
params->prof[i].tx_ppp = pfctx;
params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index d223e7c..0160c93 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -3125,6 +3125,13 @@
priv->msg_enable = MLX4_EN_MSG_LEVEL;
#ifdef CONFIG_MLX4_EN_DCB
if (!mlx4_is_slave(priv->mdev->dev)) {
+ u8 prio;
+
+ for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; ++prio) {
+ priv->ets.prio_tc[prio] = prio;
+ priv->ets.tc_tsa[prio] = IEEE_8021QAZ_TSA_VENDOR;
+ }
+
priv->dcbx_cap = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_HOST |
DCB_CAP_DCBX_VER_IEEE;
priv->flags |= MLX4_EN_DCB_ENABLED;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index 1a670b6..0710b36 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -35,6 +35,7 @@
#include <linux/etherdevice.h>
#include <linux/mlx4/cmd.h>
+#include <linux/mlx4/qp.h>
#include <linux/export.h>
#include "mlx4.h"
@@ -985,16 +986,21 @@
if (IS_ERR(mailbox))
return PTR_ERR(mailbox);
+ if (!mlx4_qp_lookup(dev, rule->qpn)) {
+ mlx4_err_rule(dev, "QP doesn't exist\n", rule);
+ ret = -EINVAL;
+ goto out;
+ }
+
trans_rule_ctrl_to_hw(rule, mailbox->buf);
size += sizeof(struct mlx4_net_trans_rule_hw_ctrl);
list_for_each_entry(cur, &rule->list, list) {
ret = parse_trans_rule(dev, cur, mailbox->buf + size);
- if (ret < 0) {
- mlx4_free_cmd_mailbox(dev, mailbox);
- return ret;
- }
+ if (ret < 0)
+ goto out;
+
size += ret;
}
@@ -1021,6 +1027,7 @@
}
}
+out:
mlx4_free_cmd_mailbox(dev, mailbox);
return ret;
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index df0f396..18f221d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -472,6 +472,7 @@
#define MLX4_EN_BW_MIN 1
#define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */
+#define MLX4_EN_TC_VENDOR 0
#define MLX4_EN_TC_ETS 7
enum dcb_pfc_type {
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index 6143113..474ff36 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -387,6 +387,19 @@
__mlx4_qp_free_icm(dev, qpn);
}
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn)
+{
+ struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table;
+ struct mlx4_qp *qp;
+
+ spin_lock(&qp_table->lock);
+
+ qp = __mlx4_qp_lookup(dev, qpn);
+
+ spin_unlock(&qp_table->lock);
+ return qp;
+}
+
int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -474,6 +487,12 @@
}
if (attr & MLX4_UPDATE_QP_QOS_VPORT) {
+ if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) {
+ mlx4_warn(dev, "Granular QoS per VF is not enabled\n");
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
qp_mask |= 1ULL << MLX4_UPD_QP_MASK_QOS_VPP;
cmd->qp_context.qos_vport = params->qos_vport;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 1822382..d6b06be 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -5048,6 +5048,7 @@
&tracker->res_tree[RES_FS_RULE]);
list_del(&fs_rule->com.list);
spin_unlock_irq(mlx4_tlock(dev));
+ kfree(fs_rule->mirr_mbox);
kfree(fs_rule);
state = 0;
break;
@@ -5214,6 +5215,13 @@
mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex);
}
+static void update_qos_vpp(struct mlx4_update_qp_context *ctx,
+ struct mlx4_vf_immed_vlan_work *work)
+{
+ ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP);
+ ctx->qp_context.qos_vport = work->qos_vport;
+}
+
void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work)
{
struct mlx4_vf_immed_vlan_work *work =
@@ -5328,11 +5336,10 @@
qp->sched_queue & 0xC7;
upd_context->qp_context.pri_path.sched_queue |=
((work->qos & 0x7) << 3);
- upd_context->qp_mask |=
- cpu_to_be64(1ULL <<
- MLX4_UPD_QP_MASK_QOS_VPP);
- upd_context->qp_context.qos_vport =
- work->qos_vport;
+
+ if (dev->caps.flags2 &
+ MLX4_DEV_CAP_FLAG2_QOS_VPP)
+ update_qos_vpp(upd_context, work);
}
err = mlx4_cmd(dev, mailbox->dma,
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 38981db..2d235e8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -2741,6 +2741,9 @@
mutex_unlock(&priv->state_lock);
+ if (mlx5e_vxlan_allowed(priv->mdev))
+ udp_tunnel_get_rx_info(netdev);
+
return err;
}
@@ -3785,13 +3788,6 @@
if (netdev->reg_state != NETREG_REGISTERED)
return;
- /* Device already registered: sync netdev system state */
- if (mlx5e_vxlan_allowed(mdev)) {
- rtnl_lock();
- udp_tunnel_get_rx_info(netdev);
- rtnl_unlock();
- }
-
queue_work(priv->wq, &priv->set_rx_mode_work);
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 981cd1d..3c183b8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -548,7 +548,6 @@
struct mlx5_priv *priv = &mdev->priv;
struct msix_entry *msix = priv->msix_arr;
int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector;
- int err;
if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) {
mlx5_core_warn(mdev, "zalloc_cpumask_var failed");
@@ -558,18 +557,11 @@
cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node),
priv->irq_info[i].mask);
- err = irq_set_affinity_hint(irq, priv->irq_info[i].mask);
- if (err) {
- mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x",
- irq);
- goto err_clear_mask;
- }
+ if (IS_ENABLED(CONFIG_SMP) &&
+ irq_set_affinity_hint(irq, priv->irq_info[i].mask))
+ mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq);
return 0;
-
-err_clear_mask:
- free_cpumask_var(priv->irq_info[i].mask);
- return err;
}
static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index bea9ae3..60e1edc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -1448,8 +1448,7 @@
err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid,
adding, true);
if (err) {
- if (net_ratelimit())
- netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n");
+ dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
return;
}
@@ -1509,8 +1508,7 @@
err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid,
adding, true);
if (err) {
- if (net_ratelimit())
- netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n");
+ dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n");
return;
}
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
index b8d5270..e306765 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c
@@ -247,7 +247,7 @@
cmd.req.arg3 = 0;
if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE)
- netxen_issue_cmd(adapter, &cmd);
+ rcode = netxen_issue_cmd(adapter, &cmd);
if (rcode != NX_RCODE_SUCCESS)
return -EIO;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index afe5e57..d023137 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -850,7 +850,7 @@
NULL) +
qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH,
NULL);
- norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, 4096);
+ norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE);
min_addr_reg1 = norm_regsize / 4096;
pwm_regsize = db_bar_size - norm_regsize;
@@ -1628,6 +1628,9 @@
DP_NOTICE(p_hwfn, "Unknown Speed in 0x%08x\n", link_temp);
}
+ p_hwfn->mcp_info->link_capabilities.default_speed_autoneg =
+ link->speed.autoneg;
+
link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK;
link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET;
link->pause.autoneg = !!(link_temp &
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index dba3fbe..0b949c6 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -1240,7 +1240,7 @@
/* TODO - at the moment assume supported and advertised speed equal */
if_link->supported_caps = QED_LM_FIBRE_BIT;
- if (params.speed.autoneg)
+ if (link_caps.default_speed_autoneg)
if_link->supported_caps |= QED_LM_Autoneg_BIT;
if (params.pause.autoneg ||
(params.pause.forced_rx && params.pause.forced_tx))
@@ -1250,6 +1250,10 @@
if_link->supported_caps |= QED_LM_Pause_BIT;
if_link->advertised_caps = if_link->supported_caps;
+ if (params.speed.autoneg)
+ if_link->advertised_caps |= QED_LM_Autoneg_BIT;
+ else
+ if_link->advertised_caps &= ~QED_LM_Autoneg_BIT;
if (params.speed.advertised_speeds &
NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G)
if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT |
diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
index dff520e..7b7a84d 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
@@ -35,6 +35,7 @@
struct qed_mcp_link_capabilities {
u32 speed_capabilities;
+ bool default_speed_autoneg;
};
struct qed_mcp_link_state {
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 509b596..bd1ec70 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -341,7 +341,7 @@
}
return -EIO;
}
- usleep_range(1000, 1500);
+ udelay(1200);
}
if (id_reg)
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
index be258d9..e3223f2 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c
@@ -765,7 +765,7 @@
sizeof(struct mpi_coredump_global_header);
mpi_coredump->mpi_global_header.imageSize =
sizeof(struct ql_mpi_coredump);
- memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+ strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
sizeof(mpi_coredump->mpi_global_header.idString));
/* Get generic NIC reg dump */
@@ -1255,7 +1255,7 @@
sizeof(struct mpi_coredump_global_header);
mpi_coredump->mpi_global_header.imageSize =
sizeof(struct ql_reg_dump);
- memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
+ strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump",
sizeof(mpi_coredump->mpi_global_header.idString));
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index 6e2add9..8bbb55f 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -296,8 +296,9 @@
/* Allocate rx SKB if we don't have one available. */
if (!qca->rx_skb) {
- qca->rx_skb = netdev_alloc_skb(net_dev,
- net_dev->mtu + VLAN_ETH_HLEN);
+ qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
+ net_dev->mtu +
+ VLAN_ETH_HLEN);
if (!qca->rx_skb) {
netdev_dbg(net_dev, "out of RX resources\n");
qca->stats.out_of_mem++;
@@ -377,7 +378,7 @@
qca->rx_skb, qca->rx_skb->dev);
qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx_ni(qca->rx_skb);
- qca->rx_skb = netdev_alloc_skb(net_dev,
+ qca->rx_skb = netdev_alloc_skb_ip_align(net_dev,
net_dev->mtu + VLAN_ETH_HLEN);
if (!qca->rx_skb) {
netdev_dbg(net_dev, "out of RX resources\n");
@@ -759,7 +760,8 @@
if (!qca->rx_buffer)
return -ENOBUFS;
- qca->rx_skb = netdev_alloc_skb(dev, qca->net_dev->mtu + VLAN_ETH_HLEN);
+ qca->rx_skb = netdev_alloc_skb_ip_align(dev, qca->net_dev->mtu +
+ VLAN_ETH_HLEN);
if (!qca->rx_skb) {
kfree(qca->rx_buffer);
netdev_info(qca->net_dev, "Failed to allocate RX sk_buff.\n");
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 18e68c9..dbb6364 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -8446,12 +8446,12 @@
goto err_out_msi_5;
}
+ pci_set_drvdata(pdev, dev);
+
rc = register_netdev(dev);
if (rc < 0)
goto err_out_cnt_6;
- pci_set_drvdata(pdev, dev);
-
netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
(u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index b6816ae..c8fd99b 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -3133,7 +3133,7 @@
/* MDIO bus init */
ret = sh_mdio_init(mdp, pd);
if (ret) {
- dev_err(&ndev->dev, "failed to initialise MDIO\n");
+ dev_err(&pdev->dev, "failed to initialise MDIO\n");
goto out_release;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 98bbb91..c212d1d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -478,7 +478,10 @@
/* PTP v1, UDP, any kind of event packet */
config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
/* take time stamp for all event messages */
- snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+ if (priv->plat->has_gmac4)
+ snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1;
+ else
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
@@ -510,7 +513,10 @@
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for all event messages */
- snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+ if (priv->plat->has_gmac4)
+ snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1;
+ else
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
@@ -544,7 +550,10 @@
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
ptp_v2 = PTP_TCR_TSVER2ENA;
/* take time stamp for all event messages */
- snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
+ if (priv->plat->has_gmac4)
+ snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1;
+ else
+ snap_type_sel = PTP_TCR_SNAPTYPSEL_1;
ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA;
ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index c06938c..174777c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -63,7 +63,8 @@
/* Enable Snapshot for Messages Relevant to Master */
#define PTP_TCR_TSMSTRENA BIT(15)
/* Select PTP packets for Taking Snapshots */
-#define PTP_TCR_SNAPTYPSEL_1 GENMASK(17, 16)
+#define PTP_TCR_SNAPTYPSEL_1 BIT(16)
+#define PTP_GMAC4_TCR_SNAPTYPSEL_1 GENMASK(17, 16)
/* Enable MAC address for PTP Frame Filtering */
#define PTP_TCR_TSENMACADDR BIT(18)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 2bd1282..552de9c 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -282,6 +282,10 @@
/* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */
#define CPSW_V1_SEQ_ID_OFS_SHIFT 16
+#define CPSW_MAX_BLKS_TX 15
+#define CPSW_MAX_BLKS_TX_SHIFT 4
+#define CPSW_MAX_BLKS_RX 5
+
struct cpsw_host_regs {
u32 max_blks;
u32 blk_cnt;
@@ -1160,11 +1164,23 @@
switch (cpsw->version) {
case CPSW_VERSION_1:
slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP);
+ /* Increase RX FIFO size to 5 for supporting fullduplex
+ * flow control mode
+ */
+ slave_write(slave,
+ (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) |
+ CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS);
break;
case CPSW_VERSION_2:
case CPSW_VERSION_3:
case CPSW_VERSION_4:
slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP);
+ /* Increase RX FIFO size to 5 for supporting fullduplex
+ * flow control mode
+ */
+ slave_write(slave,
+ (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) |
+ CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS);
break;
}
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 3c1f89a..92ad43e 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -209,6 +209,7 @@
struct genevehdr *gnvh = geneve_hdr(skb);
struct metadata_dst *tun_dst = NULL;
struct pcpu_sw_netstats *stats;
+ unsigned int len;
int err = 0;
void *oiph;
@@ -222,8 +223,10 @@
tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags,
vni_to_tunnel_id(gnvh->vni),
gnvh->opt_len * 4);
- if (!tun_dst)
+ if (!tun_dst) {
+ geneve->dev->stats.rx_dropped++;
goto drop;
+ }
/* Update tunnel dst according to Geneve options. */
ip_tunnel_info_opts_set(&tun_dst->u.tun_info,
gnvh->options, gnvh->opt_len * 4);
@@ -231,8 +234,11 @@
/* Drop packets w/ critical options,
* since we don't support any...
*/
- if (gnvh->critical)
+ if (gnvh->critical) {
+ geneve->dev->stats.rx_frame_errors++;
+ geneve->dev->stats.rx_errors++;
goto drop;
+ }
}
skb_reset_mac_header(skb);
@@ -243,8 +249,10 @@
skb_dst_set(skb, &tun_dst->dst);
/* Ignore packet loops (and multicast echo) */
- if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr))
+ if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) {
+ geneve->dev->stats.rx_errors++;
goto drop;
+ }
oiph = skb_network_header(skb);
skb_reset_network_header(skb);
@@ -276,13 +284,15 @@
}
}
- stats = this_cpu_ptr(geneve->dev->tstats);
- u64_stats_update_begin(&stats->syncp);
- stats->rx_packets++;
- stats->rx_bytes += skb->len;
- u64_stats_update_end(&stats->syncp);
-
- gro_cells_receive(&geneve->gro_cells, skb);
+ len = skb->len;
+ err = gro_cells_receive(&geneve->gro_cells, skb);
+ if (likely(err == NET_RX_SUCCESS)) {
+ stats = this_cpu_ptr(geneve->dev->tstats);
+ u64_stats_update_begin(&stats->syncp);
+ stats->rx_packets++;
+ stats->rx_bytes += len;
+ u64_stats_update_end(&stats->syncp);
+ }
return;
drop:
/* Consume bad packet */
@@ -332,7 +342,7 @@
struct geneve_sock *gs;
int opts_len;
- /* Need Geneve and inner Ethernet header to be present */
+ /* Need UDP and Geneve header to be present */
if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN)))
goto drop;
@@ -355,8 +365,10 @@
opts_len = geneveh->opt_len * 4;
if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len,
htons(ETH_P_TEB),
- !net_eq(geneve->net, dev_net(geneve->dev))))
+ !net_eq(geneve->net, dev_net(geneve->dev)))) {
+ geneve->dev->stats.rx_dropped++;
goto drop;
+ }
geneve_rx(geneve, gs, skb);
return 0;
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 4bad0b8..27160d1 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -576,6 +576,8 @@
case HDLCDRVCTL_CALIBRATE:
if(!capable(CAP_SYS_RAWIO))
return -EPERM;
+ if (s->par.bitrate <= 0)
+ return -EINVAL;
if (bi.data.calibrate > INT_MAX / s->par.bitrate)
return -EINVAL;
s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16;
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index 2caac0c..365a48c 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -742,7 +742,12 @@
macsec_fill_iv(iv, secy->sci, pn);
sg_init_table(sg, ret);
- skb_to_sgvec(skb, sg, 0, skb->len);
+ ret = skb_to_sgvec(skb, sg, 0, skb->len);
+ if (unlikely(ret < 0)) {
+ macsec_txsa_put(tx_sa);
+ kfree_skb(skb);
+ return ERR_PTR(ret);
+ }
if (tx_sc->encrypt) {
int len = skb->len - macsec_hdr_len(sci_present) -
@@ -949,7 +954,11 @@
macsec_fill_iv(iv, sci, ntohl(hdr->packet_number));
sg_init_table(sg, ret);
- skb_to_sgvec(skb, sg, 0, skb->len);
+ ret = skb_to_sgvec(skb, sg, 0, skb->len);
+ if (unlikely(ret < 0)) {
+ kfree_skb(skb);
+ return ERR_PTR(ret);
+ }
if (hdr->tci_an & MACSEC_TCI_E) {
/* confidentiality: ethernet + macsec header
diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c
index 963838d..599ce24 100644
--- a/drivers/net/phy/mdio-mux.c
+++ b/drivers/net/phy/mdio-mux.c
@@ -122,10 +122,9 @@
pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
if (pb == NULL) {
ret_val = -ENOMEM;
- goto err_parent_bus;
+ goto err_pb_kz;
}
-
pb->switch_data = data;
pb->switch_fn = switch_fn;
pb->current_child = -1;
@@ -154,6 +153,7 @@
cb->mii_bus = mdiobus_alloc();
if (!cb->mii_bus) {
ret_val = -ENOMEM;
+ devm_kfree(dev, cb);
of_node_put(child_bus_node);
break;
}
@@ -170,7 +170,6 @@
mdiobus_free(cb->mii_bus);
devm_kfree(dev, cb);
} else {
- of_node_get(child_bus_node);
cb->next = pb->children;
pb->children = cb;
}
@@ -181,9 +180,11 @@
return 0;
}
+ devm_kfree(dev, pb);
+err_pb_kz:
/* balance the reference of_mdio_find_bus() took */
- put_device(&pb->mii_bus->dev);
-
+ if (!mux_bus)
+ put_device(&parent_bus->dev);
err_parent_bus:
of_node_put(parent_bus_node);
return ret_val;
diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c
index 39be3b8..20fbcc9 100644
--- a/drivers/net/phy/mdio-xgene.c
+++ b/drivers/net/phy/mdio-xgene.c
@@ -314,6 +314,30 @@
}
#endif
+static const struct of_device_id xgene_mdio_of_match[] = {
+ {
+ .compatible = "apm,xgene-mdio-rgmii",
+ .data = (void *)XGENE_MDIO_RGMII
+ },
+ {
+ .compatible = "apm,xgene-mdio-xfi",
+ .data = (void *)XGENE_MDIO_XFI
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_mdio_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_mdio_acpi_match[] = {
+ { "APMC0D65", XGENE_MDIO_RGMII },
+ { "APMC0D66", XGENE_MDIO_XFI },
+ { }
+};
+
+MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match);
+#endif
+
+
static int xgene_mdio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -439,32 +463,6 @@
return 0;
}
-#ifdef CONFIG_OF
-static const struct of_device_id xgene_mdio_of_match[] = {
- {
- .compatible = "apm,xgene-mdio-rgmii",
- .data = (void *)XGENE_MDIO_RGMII
- },
- {
- .compatible = "apm,xgene-mdio-xfi",
- .data = (void *)XGENE_MDIO_XFI
- },
- {},
-};
-
-MODULE_DEVICE_TABLE(of, xgene_mdio_of_match);
-#endif
-
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_mdio_acpi_match[] = {
- { "APMC0D65", XGENE_MDIO_RGMII },
- { "APMC0D66", XGENE_MDIO_XFI },
- { }
-};
-
-MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match);
-#endif
-
static struct platform_driver xgene_mdio_driver = {
.driver = {
.name = "xgene-mdio",
diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h
index 354241b..594a11d 100644
--- a/drivers/net/phy/mdio-xgene.h
+++ b/drivers/net/phy/mdio-xgene.h
@@ -132,10 +132,6 @@
#define GET_BIT(field, src) \
xgene_enet_get_field_value(field ## _POS, 1, src)
-static const struct of_device_id xgene_mdio_of_match[];
-#ifdef CONFIG_ACPI
-static const struct acpi_device_id xgene_mdio_acpi_match[];
-#endif
int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg);
int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data);
struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e2d9ca6..4d21764 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -148,6 +148,12 @@
if (phydev->drv->aneg_done)
return phydev->drv->aneg_done(phydev);
+ /* Avoid genphy_aneg_done() if the Clause 45 PHY does not
+ * implement Clause 22 registers
+ */
+ if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0)))
+ return -EINVAL;
+
return genphy_aneg_done(phydev);
}
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index 1951b10..3045c96 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -465,7 +465,6 @@
po->chan.mtu = dst_mtu(&rt->dst);
if (!po->chan.mtu)
po->chan.mtu = PPP_MRU;
- ip_rt_put(rt);
po->chan.mtu -= PPTP_HEADER_OVERHEAD;
po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c
index 27ed252..cfd81eb 100644
--- a/drivers/net/slip/slhc.c
+++ b/drivers/net/slip/slhc.c
@@ -509,6 +509,10 @@
if(x < 0 || x > comp->rslot_limit)
goto bad;
+ /* Check if the cstate is initialized */
+ if (!comp->rstate[x].initialized)
+ goto bad;
+
comp->flags &=~ SLF_TOSS;
comp->recv_current = x;
} else {
@@ -673,6 +677,7 @@
if (cs->cs_tcp.doff > 5)
memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4);
cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2;
+ cs->initialized = true;
/* Put headers back on packet
* Neither header checksum is recalculated
*/
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index a0a9c9d..8673ef3 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -1203,11 +1203,6 @@
goto err_dev_open;
}
- netif_addr_lock_bh(dev);
- dev_uc_sync_multiple(port_dev, dev);
- dev_mc_sync_multiple(port_dev, dev);
- netif_addr_unlock_bh(dev);
-
err = vlan_vids_add_by_dev(port_dev, dev);
if (err) {
netdev_err(dev, "Failed to add vlan ids to device %s\n",
@@ -1247,6 +1242,11 @@
goto err_option_port_add;
}
+ netif_addr_lock_bh(dev);
+ dev_uc_sync_multiple(port_dev, dev);
+ dev_mc_sync_multiple(port_dev, dev);
+ netif_addr_unlock_bh(dev);
+
port->index = -1;
list_add_tail_rcu(&port->list, &team->port_list);
team_port_enable(team, port);
@@ -1271,8 +1271,6 @@
vlan_vids_del_by_dev(port_dev, dev);
err_vids_add:
- dev_uc_unsync(port_dev, dev);
- dev_mc_unsync(port_dev, dev);
dev_close(port_dev);
err_dev_open:
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index 1fca002..4fb4686 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -774,6 +774,12 @@
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&wwan_info,
}, {
+ /* Cinterion AHS3 modem by GEMALTO */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0055, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&wwan_info,
+}, {
/* Telit modules */
USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM,
USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index dc6d3b0..feb61ea 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1118,6 +1118,7 @@
u16 n = 0, index, ndplen;
u8 ready2send = 0;
u32 delayed_ndp_size;
+ size_t padding_count;
/* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
* accordingly. Otherwise, we should check here.
@@ -1274,11 +1275,13 @@
* a ZLP after full sized NTBs.
*/
if (!(dev->driver_info->flags & FLAG_SEND_ZLP) &&
- skb_out->len > ctx->min_tx_pkt)
- memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0,
- ctx->tx_max - skb_out->len);
- else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0)
+ skb_out->len > ctx->min_tx_pkt) {
+ padding_count = ctx->tx_max - skb_out->len;
+ memset(skb_put(skb_out, padding_count), 0, padding_count);
+ } else if (skb_out->len < ctx->tx_max &&
+ (skb_out->len % dev->maxpacket) == 0) {
*skb_put(skb_out, 1) = 0; /* force short packet */
+ }
/* set final frame length */
nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c
index c53385a..f5a9667 100644
--- a/drivers/net/usb/lan78xx.c
+++ b/drivers/net/usb/lan78xx.c
@@ -873,7 +873,8 @@
offset += 0x100;
else
ret = -EINVAL;
- ret = lan78xx_read_raw_otp(dev, offset, length, data);
+ if (!ret)
+ ret = lan78xx_read_raw_otp(dev, offset, length, data);
}
return ret;
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 1568aed..472ed6d 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -529,7 +529,12 @@
hdr = skb_vnet_hdr(skb);
sg_init_table(rq->sg, 2);
sg_set_buf(rq->sg, hdr, vi->hdr_len);
- skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
+
+ err = skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
+ if (unlikely(err < 0)) {
+ dev_kfree_skb(skb);
+ return err;
+ }
err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp);
if (err < 0)
@@ -831,7 +836,7 @@
struct virtio_net_hdr_mrg_rxbuf *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
struct virtnet_info *vi = sq->vq->vdev->priv;
- unsigned num_sg;
+ int num_sg;
unsigned hdr_len = vi->hdr_len;
bool can_push;
@@ -858,11 +863,16 @@
if (can_push) {
__skb_push(skb, hdr_len);
num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len);
+ if (unlikely(num_sg < 0))
+ return num_sg;
/* Pull header back to avoid skew in tx bytes calculations. */
__skb_pull(skb, hdr_len);
} else {
sg_set_buf(sq->sg, hdr, hdr_len);
- num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1;
+ num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len);
+ if (unlikely(num_sg < 0))
+ return num_sg;
+ num_sg++;
}
return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC);
}
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 4afba17..f809eed 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -2962,6 +2962,11 @@
/* we need to enable NAPI, otherwise dev_close will deadlock */
for (i = 0; i < adapter->num_rx_queues; i++)
napi_enable(&adapter->rx_queue[i].napi);
+ /*
+ * Need to clear the quiesce bit to ensure that vmxnet3_close
+ * can quiesce the device properly
+ */
+ clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
dev_close(adapter->netdev);
}
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 346e486..42c9480 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -585,13 +585,15 @@
neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
if (unlikely(!neigh))
neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
- if (!IS_ERR(neigh))
+ if (!IS_ERR(neigh)) {
ret = dst_neigh_output(dst, neigh, skb);
+ rcu_read_unlock_bh();
+ return ret;
+ }
rcu_read_unlock_bh();
err:
- if (unlikely(ret < 0))
- vrf_tx_error(skb->dev, skb);
+ vrf_tx_error(skb->dev, skb);
return ret;
}
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 0f5dfb8..28afdf2 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -930,7 +930,7 @@
return false;
/* Don't migrate static entries, drop packets */
- if (f->state & NUD_NOARP)
+ if (f->state & (NUD_PERMANENT | NUD_NOARP))
return true;
if (net_ratelimit())
diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c
index 6564753..a8bd68f 100644
--- a/drivers/net/wan/fsl_ucc_hdlc.c
+++ b/drivers/net/wan/fsl_ucc_hdlc.c
@@ -137,7 +137,7 @@
priv->tx_ring_size = TX_BD_RING_LEN;
/* Alloc Rx BD */
priv->rx_bd_base = dma_alloc_coherent(priv->dev,
- RX_BD_RING_LEN * sizeof(struct qe_bd *),
+ RX_BD_RING_LEN * sizeof(struct qe_bd),
&priv->dma_rx_bd, GFP_KERNEL);
if (!priv->rx_bd_base) {
@@ -148,7 +148,7 @@
/* Alloc Tx BD */
priv->tx_bd_base = dma_alloc_coherent(priv->dev,
- TX_BD_RING_LEN * sizeof(struct qe_bd *),
+ TX_BD_RING_LEN * sizeof(struct qe_bd),
&priv->dma_tx_bd, GFP_KERNEL);
if (!priv->tx_bd_base) {
@@ -158,7 +158,7 @@
}
/* Alloc parameter ram for ucc hdlc */
- priv->ucc_pram_offset = qe_muram_alloc(sizeof(priv->ucc_pram),
+ priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param),
ALIGNMENT_OF_UCC_HDLC_PRAM);
if (priv->ucc_pram_offset < 0) {
@@ -295,11 +295,11 @@
qe_muram_free(priv->ucc_pram_offset);
free_tx_bd:
dma_free_coherent(priv->dev,
- TX_BD_RING_LEN * sizeof(struct qe_bd *),
+ TX_BD_RING_LEN * sizeof(struct qe_bd),
priv->tx_bd_base, priv->dma_tx_bd);
free_rx_bd:
dma_free_coherent(priv->dev,
- RX_BD_RING_LEN * sizeof(struct qe_bd *),
+ RX_BD_RING_LEN * sizeof(struct qe_bd),
priv->rx_bd_base, priv->dma_rx_bd);
free_uccf:
ucc_fast_free(priv->uccf);
@@ -454,7 +454,7 @@
static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit)
{
struct net_device *dev = priv->ndev;
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
hdlc_device *hdlc = dev_to_hdlc(dev);
struct qe_bd *bd;
u32 bd_status;
@@ -688,7 +688,7 @@
if (priv->rx_bd_base) {
dma_free_coherent(priv->dev,
- RX_BD_RING_LEN * sizeof(struct qe_bd *),
+ RX_BD_RING_LEN * sizeof(struct qe_bd),
priv->rx_bd_base, priv->dma_rx_bd);
priv->rx_bd_base = NULL;
@@ -697,7 +697,7 @@
if (priv->tx_bd_base) {
dma_free_coherent(priv->dev,
- TX_BD_RING_LEN * sizeof(struct qe_bd *),
+ TX_BD_RING_LEN * sizeof(struct qe_bd),
priv->tx_bd_base, priv->dma_tx_bd);
priv->tx_bd_base = NULL;
@@ -1002,7 +1002,7 @@
struct device_node *np = pdev->dev.of_node;
struct ucc_hdlc_private *uhdlc_priv = NULL;
struct ucc_tdm_info *ut_info;
- struct ucc_tdm *utdm;
+ struct ucc_tdm *utdm = NULL;
struct resource res;
struct net_device *dev;
hdlc_device *hdlc;
diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h
index 7d3231a..82bdec7 100644
--- a/drivers/net/wireless/ath/ath10k/bmi.h
+++ b/drivers/net/wireless/ath/ath10k/bmi.h
@@ -83,6 +83,8 @@
#define BMI_NVRAM_SEG_NAME_SZ 16
#define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10
+#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000
+#define BMI_PARAM_FLASH_SECTION_ALL 0x10000
#define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00
#define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7b3017f..65ad7a1 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -652,7 +652,7 @@
{
u32 result, address;
u8 board_id, chip_id;
- int ret;
+ int ret, bmi_board_id_param;
address = ar->hw_params.patch_load_addr;
@@ -676,8 +676,13 @@
return ret;
}
- ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID,
- &result);
+ if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+ ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
+ bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;
+ else
+ bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;
+
+ ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result);
if (ret) {
ath10k_err(ar, "could not execute otp for board id check: %d\n",
ret);
@@ -739,6 +744,11 @@
return ret;
}
+ /* As of now pre-cal is valid for 10_4 variants */
+ if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
+ ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE)
+ bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
+
ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
if (ret) {
ath10k_err(ar, "could not execute otp (%d)\n", ret);
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 4f8d9ed..4a10544 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -939,7 +939,10 @@
}
for (i = 0; i < eesize; ++i) {
- AR5K_EEPROM_READ(i, val);
+ if (!ath5k_hw_nvram_read(ah, i, &val)) {
+ ret = -EIO;
+ goto freebuf;
+ }
buf[i] = val;
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 1875387..0f34c43 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -33,10 +33,8 @@
MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false");
#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
static int wil6210_pm_notify(struct notifier_block *notify_block,
unsigned long mode, void *unused);
-#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM */
static
@@ -354,7 +352,6 @@
}
#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
wil->pm_notify.notifier_call = wil6210_pm_notify;
rc = register_pm_notifier(&wil->pm_notify);
if (rc)
@@ -362,7 +359,6 @@
* be prevented in a later phase if needed
*/
wil_err(wil, "register_pm_notifier failed: %d\n", rc);
-#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM */
wil6210_debugfs_init(wil);
@@ -397,9 +393,7 @@
wil_dbg_misc(wil, "pcie_remove\n");
#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
unregister_pm_notifier(&wil->pm_notify);
-#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM */
wil_pm_runtime_forbid(wil);
@@ -428,7 +422,6 @@
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
static int wil6210_suspend(struct device *dev, bool is_runtime)
{
@@ -546,7 +539,6 @@
{
return wil6210_resume(dev, false);
}
-#endif /* CONFIG_PM_SLEEP */
static int wil6210_pm_runtime_idle(struct device *dev)
{
@@ -578,10 +570,12 @@
#endif /* CONFIG_PM */
static const struct dev_pm_ops wil6210_pm_ops = {
+#ifdef CONFIG_PM
SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend,
wil6210_pm_runtime_resume,
wil6210_pm_runtime_idle)
+#endif /* CONFIG_PM */
};
static struct pci_driver wil6210_driver = {
diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c
index 14533ed..0a96518 100644
--- a/drivers/net/wireless/ath/wil6210/pm.c
+++ b/drivers/net/wireless/ath/wil6210/pm.c
@@ -33,7 +33,11 @@
if (wmi_only || debug_fw) {
wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
wmi_only ? "wmi_only" : "debug_fw");
- rc = -EPERM;
+ rc = -EBUSY;
+ goto out;
+ }
+ if (is_runtime && !wil->platform_ops.suspend) {
+ rc = -EBUSY;
goto out;
}
if (!(ndev->flags & IFF_UP)) {
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index dcec343..d0fecd9 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -323,6 +323,8 @@
return -ENOMEM;
}
+ d->mac.pn_15_0 = 0;
+ d->mac.pn_47_16 = 0;
d->dma.d0 = RX_DMA_D0_CMD_DMA_RT | RX_DMA_D0_CMD_DMA_IT;
wil_desc_addr_set(&d->dma.addr, pa);
/* ip_length don't care */
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index 9b68663..f4476ee 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -798,9 +798,7 @@
int fw_calib_result;
#ifdef CONFIG_PM
-#ifdef CONFIG_PM_SLEEP
struct notifier_block pm_notify;
-#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM */
bool suspend_resp_rcvd;
diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c
index 4c4c761..e4efb98 100644
--- a/drivers/net/wireless/cnss2/main.c
+++ b/drivers/net/wireless/cnss2/main.c
@@ -1675,6 +1675,7 @@
static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv)
{
+ plat_priv->cal_done = true;
cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01);
cnss_shutdown(plat_priv);
clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state);
diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h
index c11b206..b62c014 100644
--- a/drivers/net/wireless/cnss2/main.h
+++ b/drivers/net/wireless/cnss2/main.h
@@ -107,6 +107,7 @@
void *va;
phys_addr_t pa;
bool valid;
+ u32 type;
};
enum cnss_fw_dump_type {
@@ -198,7 +199,8 @@
struct wlfw_rf_board_info_s_v01 board_info;
struct wlfw_soc_info_s_v01 soc_info;
struct wlfw_fw_version_info_s_v01 fw_version_info;
- struct cnss_fw_mem fw_mem;
+ u32 fw_mem_seg_len;
+ struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
struct cnss_fw_mem m3_mem;
struct cnss_pin_connect_result pin_result;
struct dentry *root_dentry;
@@ -210,6 +212,7 @@
u32 diag_reg_read_mem_type;
u32 diag_reg_read_len;
u8 *diag_reg_read_buf;
+ bool cal_done;
};
void *cnss_bus_dev_to_bus_priv(struct device *dev);
diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c
index 9d1fbf9..4726750 100644
--- a/drivers/net/wireless/cnss2/pci.c
+++ b/drivers/net/wireless/cnss2/pci.c
@@ -732,18 +732,21 @@
int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
- struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+ struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+ int i;
- if (!fw_mem->va && fw_mem->size) {
- fw_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev,
- fw_mem->size, &fw_mem->pa,
- GFP_KERNEL);
- if (!fw_mem->va) {
- cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx\n",
- fw_mem->size);
- fw_mem->size = 0;
+ for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+ if (!fw_mem[i].va && fw_mem[i].size) {
+ fw_mem[i].va =
+ dma_alloc_coherent(&pci_priv->pci_dev->dev,
+ fw_mem[i].size,
+ &fw_mem[i].pa, GFP_KERNEL);
+ if (!fw_mem[i].va) {
+ cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n",
+ fw_mem[i].size, fw_mem[i].type);
- return -ENOMEM;
+ return -ENOMEM;
+ }
}
}
@@ -753,17 +756,25 @@
static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv)
{
struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
- struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+ struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+ int i;
- if (fw_mem->va && fw_mem->size) {
- cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
- fw_mem->va, &fw_mem->pa, fw_mem->size);
- dma_free_coherent(&pci_priv->pci_dev->dev, fw_mem->size,
- fw_mem->va, fw_mem->pa);
- fw_mem->va = NULL;
- fw_mem->pa = 0;
- fw_mem->size = 0;
+ for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+ if (fw_mem[i].va && fw_mem[i].size) {
+ cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
+ fw_mem[i].va, &fw_mem[i].pa,
+ fw_mem[i].size, fw_mem[i].type);
+ dma_free_coherent(&pci_priv->pci_dev->dev,
+ fw_mem[i].size, fw_mem[i].va,
+ fw_mem[i].pa);
+ fw_mem[i].va = NULL;
+ fw_mem[i].pa = 0;
+ fw_mem[i].size = 0;
+ fw_mem[i].type = 0;
+ }
}
+
+ plat_priv->fw_mem_seg_len = 0;
}
int cnss_pci_load_m3(struct cnss_pci_data *pci_priv)
@@ -1107,7 +1118,7 @@
struct cnss_dump_seg *dump_seg =
plat_priv->ramdump_info_v2.dump_data_vaddr;
struct image_info *fw_image, *rddm_image;
- struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
+ struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
int ret, i;
ret = mhi_download_rddm_img(pci_priv->mhi_ctrl, in_panic);
@@ -1152,18 +1163,20 @@
dump_data->nentries += rddm_image->entries;
- if (fw_mem->pa && fw_mem->va && fw_mem->size) {
- cnss_pr_dbg("Collect remote heap dump segment, nentries 1\n");
+ cnss_pr_dbg("Collect remote heap dump segment\n");
- dump_seg->address = fw_mem->pa;
- dump_seg->v_address = fw_mem->va;
- dump_seg->size = fw_mem->size;
- dump_seg->type = CNSS_FW_REMOTE_HEAP;
- cnss_pr_dbg("seg-0: address 0x%lx, v_address %pK, size 0x%lx\n",
- dump_seg->address, dump_seg->v_address,
- dump_seg->size);
- dump_seg++;
- dump_data->nentries++;
+ for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+ if (fw_mem[i].type == QMI_WLFW_MEM_TYPE_DDR_V01) {
+ dump_seg->address = fw_mem[i].pa;
+ dump_seg->v_address = fw_mem[i].va;
+ dump_seg->size = fw_mem[i].size;
+ dump_seg->type = CNSS_FW_REMOTE_HEAP;
+ cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n",
+ i, dump_seg->address, dump_seg->v_address,
+ dump_seg->size);
+ dump_seg++;
+ dump_data->nentries++;
+ }
}
if (dump_data->nentries > 0)
diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c
index f4344ae..b8777c1 100644
--- a/drivers/net/wireless/cnss2/qmi.c
+++ b/drivers/net/wireless/cnss2/qmi.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -159,10 +159,9 @@
memset(&req, 0, sizeof(req));
memset(&resp, 0, sizeof(resp));
- req.daemon_support_valid = 1;
- req.daemon_support = daemon_support;
-
- cnss_pr_dbg("daemon_support is %d\n", req.daemon_support);
+ req.num_clients_valid = 1;
+ req.num_clients = daemon_support ? 2 : 1;
+ cnss_pr_dbg("Number of clients is %d\n", req.num_clients);
req.wake_msi = cnss_get_wake_msi(plat_priv);
if (req.wake_msi) {
@@ -170,6 +169,19 @@
req.wake_msi_valid = 1;
}
+ req.bdf_support_valid = 1;
+ req.bdf_support = 1;
+
+ req.m3_support_valid = 1;
+ req.m3_support = 1;
+
+ req.m3_cache_support_valid = 1;
+ req.m3_cache_support = 1;
+
+ req.cal_done_valid = 1;
+ req.cal_done = plat_priv->cal_done;
+ cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done);
+
req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01;
req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei;
@@ -221,8 +233,8 @@
req.request_mem_enable = 1;
req.fw_mem_ready_enable_valid = 1;
req.fw_mem_ready_enable = 1;
- req.cold_boot_cal_done_enable_valid = 1;
- req.cold_boot_cal_done_enable = 1;
+ req.fw_init_done_enable_valid = 1;
+ req.fw_init_done_enable = 1;
req.pin_connect_result_enable_valid = 1;
req.pin_connect_result_enable = 1;
@@ -260,27 +272,48 @@
void *msg, unsigned int msg_len)
{
struct msg_desc ind_desc;
- struct wlfw_request_mem_ind_msg_v01 ind_msg;
- struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
- int ret = 0;
+ struct wlfw_request_mem_ind_msg_v01 *ind_msg;
+ int ret = 0, i;
+
+ ind_msg = kzalloc(sizeof(*ind_msg), GFP_KERNEL);
+ if (!ind_msg)
+ return -ENOMEM;
ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01;
ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN;
ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei;
- ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len);
+ ret = qmi_kernel_decode(&ind_desc, ind_msg, msg, msg_len);
if (ret < 0) {
cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n",
ret, msg_len);
- return ret;
+ goto out;
}
- fw_mem->size = ind_msg.size;
+ if (ind_msg->mem_seg_len == 0 ||
+ ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) {
+ cnss_pr_err("Invalid memory segment length: %u\n",
+ ind_msg->mem_seg_len);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ cnss_pr_dbg("FW memory segment count is %u\n", ind_msg->mem_seg_len);
+ plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len;
+ for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
+ plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type;
+ plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size;
+ }
cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM,
0, NULL);
+ kfree(ind_msg);
return 0;
+
+out:
+ kfree(ind_msg);
+ return ret;
}
static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv,
@@ -317,30 +350,47 @@
int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv)
{
- struct wlfw_respond_mem_req_msg_v01 req;
- struct wlfw_respond_mem_resp_msg_v01 resp;
+ struct wlfw_respond_mem_req_msg_v01 *req;
+ struct wlfw_respond_mem_resp_msg_v01 *resp;
struct msg_desc req_desc, resp_desc;
- struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem;
- int ret = 0;
+ struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
+ int ret = 0, i;
cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n",
plat_priv->driver_state);
- if (!fw_mem->pa || !fw_mem->size) {
- cnss_pr_err("Memory for FW is not available!\n");
- ret = -ENOMEM;
- goto out;
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ resp = kzalloc(sizeof(*resp), GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ req->mem_seg_len = plat_priv->fw_mem_seg_len;
+ for (i = 0; i < req->mem_seg_len; i++) {
+ if (!fw_mem[i].pa || !fw_mem[i].size) {
+ if (fw_mem[i].type == 0) {
+ cnss_pr_err("Invalid memory for FW type, segment = %d\n",
+ i);
+ ret = -EINVAL;
+ goto out;
+ }
+ cnss_pr_err("Memory for FW is not available for type: %u\n",
+ fw_mem[i].type);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n",
+ fw_mem[i].va, &fw_mem[i].pa,
+ fw_mem[i].size, fw_mem[i].type);
+
+ req->mem_seg[i].addr = fw_mem[i].pa;
+ req->mem_seg[i].size = fw_mem[i].size;
+ req->mem_seg[i].type = fw_mem[i].type;
}
- cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n",
- fw_mem->va, &fw_mem->pa, fw_mem->size);
-
- memset(&req, 0, sizeof(req));
- memset(&resp, 0, sizeof(resp));
-
- req.addr = fw_mem->pa;
- req.size = fw_mem->size;
-
req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN;
req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01;
req_desc.ei_array = wlfw_respond_mem_req_msg_v01_ei;
@@ -349,8 +399,8 @@
resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01;
resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei;
- ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req,
- sizeof(req), &resp_desc, &resp, sizeof(resp),
+ ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req,
+ sizeof(*req), &resp_desc, resp, sizeof(*resp),
QMI_WLFW_TIMEOUT_MS);
if (ret < 0) {
cnss_pr_err("Failed to send respond memory request, err = %d\n",
@@ -358,16 +408,21 @@
goto out;
}
- if (resp.resp.result != QMI_RESULT_SUCCESS_V01) {
+ if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
cnss_pr_err("Respond memory request failed, result: %d, err: %d\n",
- resp.resp.result, resp.resp.error);
- ret = resp.resp.result;
+ resp->resp.result, resp->resp.error);
+ ret = resp->resp.result;
goto out;
}
+ kfree(req);
+ kfree(resp);
return 0;
+
out:
CNSS_ASSERT(0);
+ kfree(req);
+ kfree(resp);
return ret;
}
@@ -908,12 +963,12 @@
CNSS_DRIVER_EVENT_FW_MEM_READY,
0, NULL);
break;
- case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01:
+ case QMI_WLFW_FW_READY_IND_V01:
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE,
0, NULL);
break;
- case QMI_WLFW_FW_READY_IND_V01:
+ case QMI_WLFW_FW_INIT_DONE_IND_V01:
cnss_driver_event_post(plat_priv,
CNSS_DRIVER_EVENT_FW_READY,
0, NULL);
@@ -974,11 +1029,11 @@
cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n",
plat_priv->driver_state);
- ret = cnss_wlfw_host_cap_send_sync(plat_priv);
+ ret = cnss_wlfw_ind_register_send_sync(plat_priv);
if (ret < 0)
goto out;
- ret = cnss_wlfw_ind_register_send_sync(plat_priv);
+ ret = cnss_wlfw_host_cap_send_sync(plat_priv);
if (ret < 0)
goto out;
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
index 7d6a771..bbf707b 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -62,7 +62,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -97,7 +97,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -123,7 +123,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -140,7 +140,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -175,7 +175,131 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_mem_cfg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_cfg_s_v01,
+ offset),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_cfg_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_cfg_s_v01,
+ secure_flag),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_mem_seg_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_mem_type_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ type),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ mem_cfg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEM_CFG_V01,
+ .elem_size = sizeof(struct wlfw_mem_cfg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_s_v01,
+ mem_cfg),
+ .ei_array = wlfw_mem_cfg_s_v01_ei,
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+static struct elem_info wlfw_mem_seg_resp_s_v01_ei[] = {
+ {
+ .data_type = QMI_UNSIGNED_8_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u64),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ addr),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ size),
+ },
+ {
+ .data_type = QMI_SIGNED_4_BYTE_ENUM,
+ .elem_len = 1,
+ .elem_size = sizeof(enum wlfw_mem_type_enum_v01),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ type),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0,
+ .offset = offsetof(struct wlfw_mem_seg_resp_s_v01,
+ restore),
+ },
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -201,7 +325,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -218,7 +342,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -235,7 +359,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -261,7 +385,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -418,7 +542,7 @@
.is_array = NO_ARRAY,
.tlv_type = 0x18,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
- cold_boot_cal_done_enable_valid),
+ fw_init_done_enable_valid),
},
{
.data_type = QMI_UNSIGNED_1_BYTE,
@@ -427,7 +551,7 @@
.is_array = NO_ARRAY,
.tlv_type = 0x18,
.offset = offsetof(struct wlfw_ind_register_req_msg_v01,
- cold_boot_cal_done_enable),
+ fw_init_done_enable),
},
{
.data_type = QMI_OPT_FLAG,
@@ -448,9 +572,45 @@
rejuvenate_enable),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ xo_cal_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ xo_cal_enable),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1B,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ cal_done_enable_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1B,
+ .offset = offsetof(struct wlfw_ind_register_req_msg_v01,
+ cal_done_enable),
+ },
+ {
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -489,7 +649,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -497,7 +657,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -505,7 +665,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -573,7 +733,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -608,7 +768,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -626,7 +786,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -764,7 +924,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -782,7 +942,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -790,7 +950,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -920,7 +1080,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1054,7 +1214,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1073,7 +1233,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1117,7 +1277,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1135,7 +1295,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1153,7 +1313,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1269,7 +1429,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1288,7 +1448,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1316,7 +1476,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1342,7 +1502,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1459,7 +1619,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1485,7 +1645,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1522,7 +1682,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1530,7 +1690,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1548,7 +1708,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1574,7 +1734,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1592,7 +1752,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1627,7 +1787,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1676,7 +1836,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1724,7 +1884,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1743,7 +1903,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1760,7 +1920,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1778,7 +1938,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1804,7 +1964,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1822,7 +1982,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1834,16 +1994,16 @@
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct wlfw_host_cap_req_msg_v01,
- daemon_support_valid),
+ num_clients_valid),
},
{
- .data_type = QMI_UNSIGNED_1_BYTE,
+ .data_type = QMI_UNSIGNED_4_BYTE,
.elem_len = 1,
- .elem_size = sizeof(u8),
+ .elem_size = sizeof(u32),
.is_array = NO_ARRAY,
.tlv_type = 0x10,
.offset = offsetof(struct wlfw_host_cap_req_msg_v01,
- daemon_support),
+ num_clients),
},
{
.data_type = QMI_OPT_FLAG,
@@ -1864,9 +2024,216 @@
wake_msi),
},
{
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ gpios_valid),
+ },
+ {
+ .data_type = QMI_DATA_LEN,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ gpios_len),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = QMI_WLFW_MAX_NUM_GPIO_V01,
+ .elem_size = sizeof(u32),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x12,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ gpios),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ nm_modem_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x13,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ nm_modem),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ bdf_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x14,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ bdf_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ bdf_cache_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x15,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ bdf_cache_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ m3_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x16,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ m3_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ m3_cache_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x17,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ m3_cache_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_filesys_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x18,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_filesys_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_cache_support_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x19,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_cache_support),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_done_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1A,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ cal_done),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1B,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ mem_bucket_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_4_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u32),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1B,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ mem_bucket),
+ },
+ {
+ .data_type = QMI_OPT_FLAG,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1C,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ mem_cfg_mode_valid),
+ },
+ {
+ .data_type = QMI_UNSIGNED_1_BYTE,
+ .elem_len = 1,
+ .elem_size = sizeof(u8),
+ .is_array = NO_ARRAY,
+ .tlv_type = 0x1C,
+ .offset = offsetof(struct wlfw_host_cap_req_msg_v01,
+ mem_cfg_mode),
+ },
+ {
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1884,50 +2251,61 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = {
{
- .data_type = QMI_UNSIGNED_4_BYTE,
+ .data_type = QMI_DATA_LEN,
.elem_len = 1,
- .elem_size = sizeof(u32),
+ .elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct wlfw_request_mem_ind_msg_v01,
- size),
+ mem_seg_len),
+ },
+ {
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+ .elem_size = sizeof(struct wlfw_mem_seg_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
+ .offset = offsetof(struct wlfw_request_mem_ind_msg_v01,
+ mem_seg),
+ .ei_array = wlfw_mem_seg_s_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = {
{
- .data_type = QMI_UNSIGNED_8_BYTE,
+ .data_type = QMI_DATA_LEN,
.elem_len = 1,
- .elem_size = sizeof(u64),
+ .elem_size = sizeof(u8),
.is_array = NO_ARRAY,
.tlv_type = 0x01,
.offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
- addr),
+ mem_seg_len),
},
{
- .data_type = QMI_UNSIGNED_4_BYTE,
- .elem_len = 1,
- .elem_size = sizeof(u32),
- .is_array = NO_ARRAY,
- .tlv_type = 0x02,
+ .data_type = QMI_STRUCT,
+ .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01,
+ .elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01),
+ .is_array = VAR_LEN_ARRAY,
+ .tlv_type = 0x01,
.offset = offsetof(struct wlfw_respond_mem_req_msg_v01,
- size),
+ mem_seg),
+ .ei_array = wlfw_mem_seg_resp_s_v01_ei,
},
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1945,7 +2323,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -1953,15 +2331,15 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
-struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = {
+struct elem_info wlfw_fw_init_done_ind_msg_v01_ei[] = {
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2041,7 +2419,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2049,7 +2427,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2068,7 +2446,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2096,7 +2474,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2155,7 +2533,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2181,7 +2559,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2199,7 +2577,7 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
@@ -2216,6 +2594,14 @@
{
.data_type = QMI_EOTI,
.is_array = NO_ARRAY,
- .is_array = QMI_COMMON_TLV_TYPE,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
+ },
+};
+
+struct elem_info wlfw_cal_done_ind_msg_v01_ei[] = {
+ {
+ .data_type = QMI_EOTI,
+ .is_array = NO_ARRAY,
+ .tlv_type = QMI_COMMON_TLV_TYPE,
},
};
diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
index 9b56eb0..00a873d 100644
--- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
+++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -23,10 +23,12 @@
#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
#define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037
#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
+#define QMI_WLFW_CAL_DONE_IND_V01 0x003E
#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
#define QMI_WLFW_M3_INFO_REQ_V01 0x003C
#define QMI_WLFW_CAP_REQ_V01 0x0024
+#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
@@ -42,7 +44,6 @@
#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
-#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038
#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
@@ -72,13 +73,16 @@
#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
#define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2
+#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 32
#define QMI_WLFW_MAX_NUM_CAL_V01 5
#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
#define QMI_WLFW_MAX_NUM_CE_V01 12
#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
+#define QMI_WLFW_MAX_NUM_GPIO_V01 32
#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
+#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2
#define QMI_WLFW_MAX_STR_LEN_V01 16
#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
@@ -117,6 +121,17 @@
WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX,
};
+enum wlfw_mem_type_enum_v01 {
+ WLFW_MEM_TYPE_ENUM_MIN_VAL_V01 = INT_MIN,
+ QMI_WLFW_MEM_TYPE_MSA_V01 = 0,
+ QMI_WLFW_MEM_TYPE_DDR_V01 = 1,
+ QMI_WLFW_MEM_BDF_V01 = 2,
+ QMI_WLFW_MEM_M3_V01 = 3,
+ QMI_WLFW_MEM_CAL_V01 = 4,
+ QMI_WLFW_MEM_DPD_V01 = 5,
+ WLFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX,
+};
+
#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
@@ -128,6 +143,7 @@
#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
#define QMI_WLFW_FW_MEM_READY_V01 ((u64)0x08ULL)
+#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL)
#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
@@ -160,6 +176,26 @@
u8 secure_flag;
};
+struct wlfw_mem_cfg_s_v01 {
+ u64 offset;
+ u32 size;
+ u8 secure_flag;
+};
+
+struct wlfw_mem_seg_s_v01 {
+ u32 size;
+ enum wlfw_mem_type_enum_v01 type;
+ u32 mem_cfg_len;
+ struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01];
+};
+
+struct wlfw_mem_seg_resp_s_v01 {
+ u64 addr;
+ u32 size;
+ enum wlfw_mem_type_enum_v01 type;
+ u8 restore;
+};
+
struct wlfw_rf_chip_info_s_v01 {
u32 chip_id;
u32 chip_family;
@@ -195,13 +231,17 @@
u8 request_mem_enable;
u8 fw_mem_ready_enable_valid;
u8 fw_mem_ready_enable;
- u8 cold_boot_cal_done_enable_valid;
- u8 cold_boot_cal_done_enable;
+ u8 fw_init_done_enable_valid;
+ u8 fw_init_done_enable;
u8 rejuvenate_enable_valid;
u32 rejuvenate_enable;
+ u8 xo_cal_enable_valid;
+ u8 xo_cal_enable;
+ u8 cal_done_enable_valid;
+ u8 cal_done_enable;
};
-#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46
+#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 54
extern struct elem_info wlfw_ind_register_req_msg_v01_ei[];
struct wlfw_ind_register_resp_msg_v01 {
@@ -533,13 +573,36 @@
extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[];
struct wlfw_host_cap_req_msg_v01 {
- u8 daemon_support_valid;
- u8 daemon_support;
+ u8 num_clients_valid;
+ u32 num_clients;
u8 wake_msi_valid;
u32 wake_msi;
+ u8 gpios_valid;
+ u32 gpios_len;
+ u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01];
+ u8 nm_modem_valid;
+ u8 nm_modem;
+ u8 bdf_support_valid;
+ u8 bdf_support;
+ u8 bdf_cache_support_valid;
+ u8 bdf_cache_support;
+ u8 m3_support_valid;
+ u8 m3_support;
+ u8 m3_cache_support_valid;
+ u8 m3_cache_support;
+ u8 cal_filesys_support_valid;
+ u8 cal_filesys_support;
+ u8 cal_cache_support_valid;
+ u8 cal_cache_support;
+ u8 cal_done_valid;
+ u8 cal_done;
+ u8 mem_bucket_valid;
+ u32 mem_bucket;
+ u8 mem_cfg_mode_valid;
+ u8 mem_cfg_mode;
};
-#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 11
+#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
extern struct elem_info wlfw_host_cap_req_msg_v01_ei[];
struct wlfw_host_cap_resp_msg_v01 {
@@ -550,18 +613,19 @@
extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[];
struct wlfw_request_mem_ind_msg_v01 {
- u32 size;
+ u32 mem_seg_len;
+ struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
};
-#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7
+#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 1124
extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[];
struct wlfw_respond_mem_req_msg_v01 {
- u64 addr;
- u32 size;
+ u32 mem_seg_len;
+ struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
};
-#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18
+#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 548
extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[];
struct wlfw_respond_mem_resp_msg_v01 {
@@ -578,12 +642,12 @@
#define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[];
-struct wlfw_cold_boot_cal_done_ind_msg_v01 {
+struct wlfw_fw_init_done_ind_msg_v01 {
char placeholder;
};
-#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
-extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[];
+#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_fw_init_done_ind_msg_v01_ei[];
struct wlfw_rejuvenate_ind_msg_v01 {
u8 cause_for_rejuvenation_valid;
@@ -654,4 +718,11 @@
#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
extern struct elem_info wlfw_xo_cal_ind_msg_v01_ei[];
+struct wlfw_cal_done_ind_msg_v01 {
+ char placeholder;
+};
+
+#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0
+extern struct elem_info wlfw_cal_done_ind_msg_v01_ei[];
+
#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
index d4b73de..b35adbc 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c
@@ -79,8 +79,8 @@
/* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 17
#define IWL7265_UCODE_API_MIN 17
-#define IWL7265D_UCODE_API_MIN 17
-#define IWL3168_UCODE_API_MIN 20
+#define IWL7265D_UCODE_API_MIN 22
+#define IWL3168_UCODE_API_MIN 22
/* NVM versions */
#define IWL7260_NVM_VERSION 0x0a1d
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
index 8d3e53f..20d08dd 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c
@@ -74,8 +74,8 @@
#define IWL8265_UCODE_API_MAX 26
/* Lowest firmware API version supported */
-#define IWL8000_UCODE_API_MIN 17
-#define IWL8265_UCODE_API_MIN 20
+#define IWL8000_UCODE_API_MIN 22
+#define IWL8265_UCODE_API_MIN 22
/* NVM versions */
#define IWL8000_NVM_VERSION 0x0a1d
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index 406ef30..da8234b 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -369,6 +369,7 @@
#define MON_DMARB_RD_DATA_ADDR (0xa03c5c)
#define DBGC_IN_SAMPLE (0xa03c00)
+#define DBGC_OUT_CTRL (0xa03c0c)
/* enable the ID buf for read */
#define WFPM_PS_CTL_CLR 0xA0300C
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
index 700d244..2642d8e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
@@ -914,14 +914,6 @@
return 0;
}
-static inline void iwl_mvm_restart_early_start(struct iwl_mvm *mvm)
-{
- if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000)
- iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
- else
- iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 1);
-}
-
int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id)
{
u8 *ptr;
@@ -935,10 +927,8 @@
/* EARLY START - firmware's configuration is hard coded */
if ((!mvm->fw->dbg_conf_tlv[conf_id] ||
!mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) &&
- conf_id == FW_DBG_START_FROM_ALIVE) {
- iwl_mvm_restart_early_start(mvm);
+ conf_id == FW_DBG_START_FROM_ALIVE)
return 0;
- }
if (!mvm->fw->dbg_conf_tlv[conf_id])
return -EINVAL;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index c60703e..2b1c691 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -1666,8 +1666,11 @@
*/
static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
{
+ u32 cmd_queue = iwl_mvm_is_dqa_supported(mvm) ? IWL_MVM_DQA_CMD_QUEUE :
+ IWL_MVM_CMD_QUEUE;
+
return ((BIT(mvm->cfg->base_params->num_of_queues) - 1) &
- ~BIT(IWL_MVM_CMD_QUEUE));
+ ~BIT(cmd_queue));
}
static inline
@@ -1687,6 +1690,7 @@
static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
{
mvm->ucode_loaded = false;
+ mvm->fw_dbg_conf = FW_DBG_INVALID;
iwl_trans_stop_device(mvm->trans);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
index 4d35deb..6d38eec 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c
@@ -1118,22 +1118,38 @@
mutex_lock(&mvm->mutex);
- /* stop recording */
if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ /* stop recording */
iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+
+ iwl_mvm_fw_error_dump(mvm);
+
+ /* start recording again if the firmware is not crashed */
+ if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) &&
+ mvm->fw->dbg_dest_tlv)
+ iwl_clear_bits_prph(mvm->trans,
+ MON_BUFF_SAMPLE_CTL, 0x100);
} else {
+ u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE);
+ u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL);
+
+ /* stop recording */
iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
- /* wait before we collect the data till the DBGC stop */
udelay(100);
+ iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+ /* wait before we collect the data till the DBGC stop */
+ udelay(500);
+
+ iwl_mvm_fw_error_dump(mvm);
+
+ /* start recording again if the firmware is not crashed */
+ if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) &&
+ mvm->fw->dbg_dest_tlv) {
+ iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, in_sample);
+ iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, out_ctrl);
+ }
}
- iwl_mvm_fw_error_dump(mvm);
-
- /* start recording again if the firmware is not crashed */
- WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) &&
- mvm->fw->dbg_dest_tlv &&
- iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
-
mutex_unlock(&mvm->mutex);
iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index bec7d9c..c520356 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -790,11 +790,13 @@
struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata);
int ret;
- if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR))
- return -EIO;
-
mutex_lock(&mvm->mutex);
+ if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) {
+ ret = -EIO;
+ goto unlock;
+ }
+
if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) {
ret = -EINVAL;
goto unlock;
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 10ef44e..fe32de2 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -2824,7 +2824,8 @@
#ifdef CONFIG_PM_SLEEP
static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
{
- if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+ if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3 &&
+ (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3))
return iwl_pci_fw_enter_d0i3(trans);
return 0;
@@ -2832,7 +2833,8 @@
static void iwl_trans_pcie_resume(struct iwl_trans *trans)
{
- if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+ if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3 &&
+ (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3))
iwl_pci_fw_exit_d0i3(trans);
}
#endif /* CONFIG_PM_SLEEP */
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
index 13da95a..987c7c4 100644
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -142,15 +142,25 @@
if (!rt2x00dev->ops->hw->set_rts_threshold &&
(tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS |
IEEE80211_TX_RC_USE_CTS_PROTECT))) {
- if (rt2x00queue_available(queue) <= 1)
- goto exit_fail;
+ if (rt2x00queue_available(queue) <= 1) {
+ /*
+ * Recheck for full queue under lock to avoid race
+ * conditions with rt2x00lib_txdone().
+ */
+ spin_lock(&queue->tx_lock);
+ if (rt2x00queue_threshold(queue))
+ rt2x00queue_pause_queue(queue);
+ spin_unlock(&queue->tx_lock);
+
+ goto exit_free_skb;
+ }
if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb))
- goto exit_fail;
+ goto exit_free_skb;
}
if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false)))
- goto exit_fail;
+ goto exit_free_skb;
/*
* Pausing queue has to be serialized with rt2x00lib_txdone(). Note
@@ -164,10 +174,6 @@
return;
- exit_fail:
- spin_lock(&queue->tx_lock);
- rt2x00queue_pause_queue(queue);
- spin_unlock(&queue->tx_lock);
exit_free_skb:
ieee80211_free_txskb(hw, skb);
}
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 0881ba8..c78abfc 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -247,7 +247,10 @@
0x04, 0x08, /* Noise gain, limit offset */
0x28, 0x28, /* det rssi, med busy offsets */
7, /* det sync thresh */
- 0, 2, 2 /* test mode, min, max */
+ 0, 2, 2, /* test mode, min, max */
+ 0, /* rx/tx delay */
+ 0, 0, 0, 0, 0, 0, /* current BSS id */
+ 0 /* hop set */
};
/*===========================================================================*/
@@ -598,7 +601,7 @@
* a_beacon_period = hops a_beacon_period = KuS
*//* 64ms = 010000 */
if (local->fw_ver == 0x55) {
- memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms,
+ memcpy(&local->sparm.b4, b4_default_startup_parms,
sizeof(struct b4_startup_params));
/* Translate sane kus input values to old build 4/5 format */
/* i = hop time in uS truncated to 3 bytes */
diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
index 231f84d..6113624 100644
--- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
+++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c
@@ -1454,6 +1454,7 @@
goto err_free_dev;
}
mutex_init(&priv->io_mutex);
+ mutex_init(&priv->conf_mutex);
SET_IEEE80211_DEV(dev, &intf->dev);
usb_set_intfdata(intf, dev);
@@ -1627,7 +1628,6 @@
printk(KERN_ERR "rtl8187: Cannot register device\n");
goto err_free_dmabuf;
}
- mutex_init(&priv->conf_mutex);
skb_queue_head_init(&priv->b_tx_status.queue);
wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n",
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 1c539c8..5e41bf0 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1200,8 +1200,7 @@
WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
- wl1251_acx_arp_ip_filter(wl, enable, addr);
-
+ ret = wl1251_acx_arp_ip_filter(wl, enable, addr);
if (ret < 0)
goto out_sleep;
}
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index b09c81e..1b28786 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -2038,7 +2038,10 @@
case XenbusStateInitialised:
case XenbusStateReconfiguring:
case XenbusStateReconfigured:
+ break;
+
case XenbusStateUnknown:
+ wake_up_all(&module_unload_q);
break;
case XenbusStateInitWait:
@@ -2169,7 +2172,9 @@
xenbus_switch_state(dev, XenbusStateClosing);
wait_event(module_unload_q,
xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosing);
+ XenbusStateClosing ||
+ xenbus_read_driver_state(dev->otherend) ==
+ XenbusStateUnknown);
xenbus_switch_state(dev, XenbusStateClosed);
wait_event(module_unload_q,
diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c
index b8fb1ef..74257ac 100644
--- a/drivers/nvdimm/namespace_devs.c
+++ b/drivers/nvdimm/namespace_devs.c
@@ -1747,7 +1747,7 @@
}
if (i < nd_region->ndr_mappings) {
- struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]);
+ struct nvdimm *nvdimm = nd_region->mapping[i].nvdimm;
/*
* Give up if we don't find an instance of a uuid at each
@@ -1755,7 +1755,7 @@
* find a dimm with two instances of the same uuid.
*/
dev_err(&nd_region->dev, "%s missing label for %pUb\n",
- dev_name(ndd->dev), nd_label->uuid);
+ nvdimm_name(nvdimm), nd_label->uuid);
rc = -EINVAL;
goto err;
}
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index ad9d82e..c823e93 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2040,6 +2040,10 @@
struct nvme_ns *ns;
mutex_lock(&ctrl->namespaces_mutex);
+
+ /* Forcibly start all queues to avoid having stuck requests */
+ blk_mq_start_hw_queues(ctrl->admin_q);
+
list_for_each_entry(ns, &ctrl->namespaces, list) {
/*
* Revalidating a dead namespace sets capacity to 0. This will
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index e48ecb9..8cc856e 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -1263,7 +1263,7 @@
bool nssro = dev->subsystem && (csts & NVME_CSTS_NSSRO);
/* If there is a reset ongoing, we shouldn't reset again. */
- if (work_busy(&dev->reset_work))
+ if (dev->ctrl.state == NVME_CTRL_RESETTING)
return false;
/* We shouldn't reset unless the controller is on fatal error state
@@ -1755,7 +1755,7 @@
struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work);
int result = -ENODEV;
- if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING))
+ if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING))
goto out;
/*
@@ -1765,9 +1765,6 @@
if (dev->ctrl.ctrl_config & NVME_CC_ENABLE)
nvme_dev_disable(dev, false);
- if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING))
- goto out;
-
result = nvme_pci_enable(dev);
if (result)
goto out;
@@ -1841,8 +1838,8 @@
{
if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q))
return -ENODEV;
- if (work_busy(&dev->reset_work))
- return -ENODEV;
+ if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING))
+ return -EBUSY;
if (!queue_work(nvme_workq, &dev->reset_work))
return -EBUSY;
return 0;
@@ -1944,6 +1941,7 @@
if (result)
goto release_pools;
+ nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING);
dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev));
queue_work(nvme_workq, &dev->reset_work);
@@ -1987,6 +1985,7 @@
nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING);
+ cancel_work_sync(&dev->reset_work);
pci_set_drvdata(pdev, NULL);
if (!pci_device_is_present(pdev)) {
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 888fdbc..dc91a1b 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -16,6 +16,11 @@
#include "of_private.h"
+static struct device_node *kobj_to_device_node(struct kobject *kobj)
+{
+ return container_of(kobj, struct device_node, kobj);
+}
+
/**
* of_node_get() - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to simplify writing of
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index c4d7fdc..61acd6b 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -35,12 +35,6 @@
extern struct list_head aliases_lookup;
extern struct kset *of_kset;
-
-static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
-{
- return container_of(kobj, struct device_node, kobj);
-}
-
#if defined(CONFIG_OF_DYNAMIC)
extern int of_property_notify(int action, struct device_node *np,
struct property *prop, struct property *old_prop);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 4aba42f..8d8e4c5 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -502,7 +502,7 @@
}
EXPORT_SYMBOL_GPL(of_platform_default_populate);
-#ifndef CONFIG_PPC
+#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MSM8953_BOOT_ORDERING)
static int __init of_platform_default_populate_init(void)
{
struct device_node *node;
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 78530d1..bdce067 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -2646,6 +2646,7 @@
netmos_9901,
netmos_9865,
quatech_sppxp100,
+ wch_ch382l,
};
@@ -2708,6 +2709,7 @@
/* netmos_9901 */ { 1, { { 0, -1 }, } },
/* netmos_9865 */ { 1, { { 0, -1 }, } },
/* quatech_sppxp100 */ { 1, { { 0, 1 }, } },
+ /* wch_ch382l */ { 1, { { 2, -1 }, } },
};
static const struct pci_device_id parport_pc_pci_tbl[] = {
@@ -2797,6 +2799,8 @@
/* Quatech SPPXP-100 Parallel port PCI ExpressCard */
{ PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 },
+ /* WCH CH382L PCI-E single parallel port card */
+ { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l },
{ 0, } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl);
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index a46b585..d44b558 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -587,6 +587,7 @@
{
unsigned long long sta = 0;
struct acpiphp_func *func;
+ u32 dvid;
list_for_each_entry(func, &slot->funcs, sibling) {
if (func->flags & FUNC_HAS_STA) {
@@ -597,19 +598,27 @@
if (ACPI_SUCCESS(status) && sta)
break;
} else {
- u32 dvid;
-
- pci_bus_read_config_dword(slot->bus,
- PCI_DEVFN(slot->device,
- func->function),
- PCI_VENDOR_ID, &dvid);
- if (dvid != 0xffffffff) {
+ if (pci_bus_read_dev_vendor_id(slot->bus,
+ PCI_DEVFN(slot->device, func->function),
+ &dvid, 0)) {
sta = ACPI_STA_ALL;
break;
}
}
}
+ if (!sta) {
+ /*
+ * Check for the slot itself since it may be that the
+ * ACPI slot is a device below PCIe upstream port so in
+ * that case it may not even be reachable yet.
+ */
+ if (pci_bus_read_dev_vendor_id(slot->bus,
+ PCI_DEVFN(slot->device, 0), &dvid, 0)) {
+ sta = ACPI_STA_ALL;
+ }
+ }
+
return (unsigned int)sta;
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index a98be6d..56340ab 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -231,7 +231,7 @@
res->flags |= IORESOURCE_ROM_ENABLE;
l64 = l & PCI_ROM_ADDRESS_MASK;
sz64 = sz & PCI_ROM_ADDRESS_MASK;
- mask64 = (u32)PCI_ROM_ADDRESS_MASK;
+ mask64 = PCI_ROM_ADDRESS_MASK;
}
if (res->flags & IORESOURCE_MEM_64) {
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 4bc589e..85774b7 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -63,7 +63,7 @@
mask = (u32)PCI_BASE_ADDRESS_IO_MASK;
new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK;
} else if (resno == PCI_ROM_RESOURCE) {
- mask = (u32)PCI_ROM_ADDRESS_MASK;
+ mask = PCI_ROM_ADDRESS_MASK;
} else {
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK;
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 0a96502..fc5b18d 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -46,6 +46,9 @@
#define BYT_TRIG_POS BIT(25)
#define BYT_TRIG_LVL BIT(24)
#define BYT_DEBOUNCE_EN BIT(20)
+#define BYT_GLITCH_FILTER_EN BIT(19)
+#define BYT_GLITCH_F_SLOW_CLK BIT(17)
+#define BYT_GLITCH_F_FAST_CLK BIT(16)
#define BYT_PULL_STR_SHIFT 9
#define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT)
#define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT)
@@ -1579,6 +1582,9 @@
*/
value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG |
BYT_TRIG_LVL);
+ /* Enable glitch filtering */
+ value |= BYT_GLITCH_FILTER_EN | BYT_GLITCH_F_SLOW_CLK |
+ BYT_GLITCH_F_FAST_CLK;
writel(value, reg);
diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
index 7511723..257c1c2 100644
--- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
+++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c
@@ -138,7 +138,6 @@
MESON_PIN(GPIOX_19, EE_OFF),
MESON_PIN(GPIOX_20, EE_OFF),
MESON_PIN(GPIOX_21, EE_OFF),
- MESON_PIN(GPIOX_22, EE_OFF),
MESON_PIN(GPIOCLK_0, EE_OFF),
MESON_PIN(GPIOCLK_1, EE_OFF),
diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c
index dc445a0..e729c56 100644
--- a/drivers/platform/msm/gsi/gsi.c
+++ b/drivers/platform/msm/gsi/gsi.c
@@ -1572,6 +1572,10 @@
GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK) |
((props->use_db_eng << GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT) &
GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK));
+ if (gsi_ctx->per.ver >= GSI_VER_2_0)
+ val |= ((props->prefetch_mode <<
+ GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT)
+ & GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK);
gsi_writel(val, gsi_ctx->base +
GSI_EE_n_GSI_CH_k_QOS_OFFS(props->ch_id, ee));
}
diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h
index 7817613..add3876 100644
--- a/drivers/platform/msm/gsi/gsi_reg.h
+++ b/drivers/platform/msm/gsi/gsi_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -1124,6 +1124,8 @@
#define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303
#define GSI_EE_n_GSI_CH_k_QOS_MAXk 30
#define GSI_EE_n_GSI_CH_k_QOS_MAXn 3
+#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400
+#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa
#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200
#define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9
#define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index ebf1d29..d9e3ab9 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -1847,12 +1847,15 @@
}
if (ipa_pm_is_used()) {
- result = ipa_pm_set_perf_profile(
- ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
- params->max_supported_bandwidth_mbps);
- if (result) {
- IPA_USB_ERR("failed to set perf profile\n");
- return result;
+ /* perf profile is not set on USB DPL pipe */
+ if (ttype != IPA_USB_TRANSPORT_DPL) {
+ result = ipa_pm_set_perf_profile(
+ ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl,
+ params->max_supported_bandwidth_mbps);
+ if (result) {
+ IPA_USB_ERR("failed to set perf profile\n");
+ return result;
+ }
}
result = ipa_pm_activate_sync(
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
index f062ed2..953469a 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c
@@ -432,6 +432,8 @@
list_for_each_entry(entry, &ipa_ctx->hdr_tbl.head_hdr_entry_list,
link) {
+ if (entry->cookie != IPA_HDR_COOKIE)
+ continue;
nbytes = scnprintf(
dbg_buff,
IPA_MAX_MSG_LEN,
@@ -606,6 +608,14 @@
if (attrib->protocol_eq_present)
pr_err("protocol:%d ", attrib->protocol_eq);
+ if (attrib->num_ihl_offset_range_16 >
+ IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) {
+ IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS,
+ attrib->num_ihl_offset_range_16);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_ihl_offset_range_16; i++) {
pr_err(
"(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ",
@@ -614,6 +624,12 @@
attrib->ihl_offset_range_16[i].range_high);
}
+ if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) {
+ IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_offset_meq_32; i++) {
pr_err(
"(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ",
@@ -635,6 +651,12 @@
attrib->ihl_offset_eq_16.value);
}
+ if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) {
+ IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_ihl_offset_meq_32; i++) {
pr_err(
"(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ",
@@ -643,6 +665,12 @@
attrib->ihl_offset_meq_32[i].value);
}
+ if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) {
+ IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_offset_meq_128; i++) {
for (j = 0; j < 16; j++) {
addr[j] = attrib->offset_meq_128[i].value[j];
@@ -812,11 +840,14 @@
u32 rt_tbl_idx;
u32 bitmap;
bool eq;
+ int res = 0;
tbl = &ipa_ctx->glob_flt_tbl[ip];
mutex_lock(&ipa_ctx->lock);
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
+ if (entry->cookie != IPA_FLT_COOKIE)
+ continue;
if (entry->rule.eq_attrib_type) {
rt_tbl_idx = entry->rule.rt_tbl_idx;
bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
@@ -835,10 +866,14 @@
i, entry->rule.action, rt_tbl_idx);
pr_err("attrib_mask:%08x retain_hdr:%d eq:%d ",
bitmap, entry->rule.retain_hdr, eq);
- if (eq)
- ipa_attrib_dump_eq(
+ if (eq) {
+ res = ipa_attrib_dump_eq(
&entry->rule.eq_attrib);
- else
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
+ } else
ipa_attrib_dump(
&entry->rule.attrib, ip);
i++;
@@ -848,6 +883,8 @@
tbl = &ipa_ctx->flt_tbl[j][ip];
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
+ if (entry->cookie != IPA_FLT_COOKIE)
+ continue;
if (entry->rule.eq_attrib_type) {
rt_tbl_idx = entry->rule.rt_tbl_idx;
bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
@@ -867,18 +904,23 @@
pr_err("attrib_mask:%08x retain_hdr:%d ",
bitmap, entry->rule.retain_hdr);
pr_err("eq:%d ", eq);
- if (eq)
- ipa_attrib_dump_eq(
- &entry->rule.eq_attrib);
- else
+ if (eq) {
+ res = ipa_attrib_dump_eq(
+ &entry->rule.eq_attrib);
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
+ } else
ipa_attrib_dump(
&entry->rule.attrib, ip);
i++;
}
}
+bail:
mutex_unlock(&ipa_ctx->lock);
- return 0;
+ return res;
}
static ssize_t ipa_read_stats(struct file *file, char __user *ubuf,
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
index c043bad..15be5d6 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c
@@ -327,6 +327,11 @@
size_t tmp;
gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
+ if (!ipa_ctx->nat_mem.is_dev_init) {
+ IPAERR_RL("Nat table not initialized\n");
+ return -EPERM;
+ }
+
IPADBG("\n");
if (init->table_entries == 0) {
IPADBG("Table entries is zero\n");
@@ -576,6 +581,11 @@
int ret = 0;
gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
+ if (!ipa_ctx->nat_mem.is_dev_init) {
+ IPAERR_RL("Nat table not initialized\n");
+ return -EPERM;
+ }
+
IPADBG("\n");
if (dma->entries <= 0) {
IPAERR_RL("Invalid number of commands %d\n",
@@ -762,6 +772,16 @@
int result;
gfp_t flag = GFP_KERNEL | (ipa_ctx->use_dma_zone ? GFP_DMA : 0);
+ if (!ipa_ctx->nat_mem.is_dev_init) {
+ IPAERR_RL("Nat table not initialized\n");
+ return -EPERM;
+ }
+
+ if (ipa_ctx->nat_mem.public_ip_addr) {
+ IPAERR_RL("Public IP addr not assigned and trying to delete\n");
+ return -EPERM;
+ }
+
IPADBG("\n");
if (ipa_ctx->nat_mem.is_tmp_mem) {
IPAERR("using temp memory during nat del\n");
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
index 1f5d619..98f5574 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -281,7 +281,7 @@
{
}
-static int rmnet_ipa_reset_tethering_stats
+static inline int rmnet_ipa_reset_tethering_stats
(
struct wan_ioctl_reset_tether_stats *data
)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 9eb3c35..c523b3d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -3947,16 +3947,18 @@
{
u32 clk_rate;
- if (!ipa3_ctx->enable_clock_scaling)
+ IPADBG_LOW("idx = %d\n", idx);
+
+ if (!ipa3_ctx->enable_clock_scaling) {
+ ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx;
return 0;
+ }
if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) {
IPAERR("not supported in this mode\n");
return 0;
}
- IPADBG_LOW("idx = %d\n", idx);
-
if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) {
IPAERR("bad voltage\n");
return -EINVAL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index ee9c49c..dc5f5e0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -372,6 +372,8 @@
list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list,
link) {
+ if (entry->cookie != IPA_HDR_COOKIE)
+ continue;
nbytes = scnprintf(
dbg_buff,
IPA_MAX_MSG_LEN,
@@ -556,6 +558,12 @@
if (attrib->tc_eq_present)
pr_err("tc:%d ", attrib->tc_eq);
+ if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) {
+ IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_offset_meq_128; i++) {
for (j = 0; j < 16; j++) {
addr[j] = attrib->offset_meq_128[i].value[j];
@@ -567,6 +575,12 @@
mask, addr);
}
+ if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) {
+ IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_offset_meq_32; i++)
pr_err(
"(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ",
@@ -574,6 +588,12 @@
attrib->offset_meq_32[i].mask,
attrib->offset_meq_32[i].value);
+ if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) {
+ IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_ihl_offset_meq_32; i++)
pr_err(
"(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ",
@@ -588,6 +608,14 @@
attrib->metadata_meq32.mask,
attrib->metadata_meq32.value);
+ if (attrib->num_ihl_offset_range_16 >
+ IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) {
+ IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n",
+ IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS,
+ attrib->num_ihl_offset_range_16);
+ return -EPERM;
+ }
+
for (i = 0; i < attrib->num_ihl_offset_range_16; i++)
pr_err(
"(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ",
@@ -780,7 +808,11 @@
pr_err("rule_id:%u prio:%u retain_hdr:%u ",
rules[rl].id, rules[rl].priority,
rules[rl].retain_hdr);
- ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+ res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
}
pr_err("=== Routing Table %d = Non-Hashable Rules ===\n", tbl);
@@ -811,7 +843,11 @@
pr_err("rule_id:%u prio:%u retain_hdr:%u\n",
rules[rl].id, rules[rl].priority,
rules[rl].retain_hdr);
- ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+ res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib);
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
}
pr_err("\n");
}
@@ -885,6 +921,7 @@
u32 rt_tbl_idx;
u32 bitmap;
bool eq;
+ int res = 0;
mutex_lock(&ipa3_ctx->lock);
@@ -894,6 +931,8 @@
tbl = &ipa3_ctx->flt_tbl[j][ip];
i = 0;
list_for_each_entry(entry, &tbl->head_flt_rule_list, link) {
+ if (entry->cookie != IPA_FLT_COOKIE)
+ continue;
if (entry->rule.eq_attrib_type) {
rt_tbl_idx = entry->rule.rt_tbl_idx;
bitmap = entry->rule.eq_attrib.rule_eq_bitmap;
@@ -919,18 +958,23 @@
pr_err("pdn index %d, set metadata %d ",
entry->rule.pdn_idx,
entry->rule.set_metadata);
- if (eq)
- ipa3_attrib_dump_eq(
- &entry->rule.eq_attrib);
- else
+ if (eq) {
+ res = ipa3_attrib_dump_eq(
+ &entry->rule.eq_attrib);
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
+ } else
ipa3_attrib_dump(
&entry->rule.attrib, ip);
i++;
}
}
+bail:
mutex_unlock(&ipa3_ctx->lock);
- return 0;
+ return res;
}
static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf,
@@ -985,7 +1029,11 @@
pr_err("pdn: %u, set_metadata: %u ",
rules[rl].rule.pdn_idx,
rules[rl].rule.set_metadata);
- ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+ res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
}
pr_err("=== Filtering Table ep:%d = Non-Hashable Rules ===\n",
@@ -1013,7 +1061,11 @@
pr_err("pdn: %u, set_metadata: %u ",
rules[rl].rule.pdn_idx,
rules[rl].rule.set_metadata);
- ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+ res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib);
+ if (res) {
+ IPAERR_RL("failed read attrib eq\n");
+ goto bail;
+ }
}
pr_err("\n");
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
index 9a0f44a..e73349a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
@@ -646,7 +646,6 @@
atomic_set(&comp->cnt, 2);
sys = ipa3_ctx->ep[ep_idx].sys;
- IPA_ACTIVE_CLIENTS_INC_SIMPLE();
if (num_desc == 1) {
if (descr->callback || descr->user1)
@@ -685,7 +684,6 @@
kfree(comp);
bail:
- IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return result;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 29fd547..6742773 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -61,8 +61,10 @@
gen_params.rule = (const struct ipa_flt_rule *)&entry->rule;
res = ipahal_flt_generate_hw_rule(&gen_params, &entry->hw_len, buf);
- if (res)
+ if (res) {
IPAERR_RL("failed to generate flt h/w rule\n");
+ return res;
+ }
return 0;
}
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
index b48f2c4..7065e2c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_nat.c
@@ -1258,6 +1258,11 @@
goto bail;
}
+ if (!ipa3_ctx->nat_mem.dev.is_dev_init) {
+ IPAERR_RL("NAT hasn't been initialized\n");
+ return -EPERM;
+ }
+
for (cnt = 0; cnt < dma->entries; ++cnt) {
result = ipa3_table_validate_table_dma_one(&dma->dma[cnt]);
if (result) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
index 0772dde..9bc6d39 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_pm.h
@@ -16,7 +16,7 @@
#include <linux/msm_ipa.h>
/* internal to ipa */
-#define IPA_PM_MAX_CLIENTS 12 /* actual max is value -1 since we start from 1*/
+#define IPA_PM_MAX_CLIENTS 14 /* actual max is value -1 since we start from 1*/
#define IPA_PM_MAX_EX_CL 64
#define IPA_PM_THRESHOLD_MAX 5
#define IPA_PM_EXCEPTION_MAX 2
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
index f5ef141..e746229 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.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
@@ -818,6 +818,11 @@
{
u32 opcode;
+ if (ipa3_ctx->ipa_hw_type > IPA_HW_v4_0) {
+ IPADBG_LOW("not supported past IPA v4.0\n");
+ return 0;
+ }
+
/*
* If the uC interface has not been initialized yet,
* don't notify the uC on the enable/disable
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index 5d6d3cd..4b9268f 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -964,12 +964,12 @@
/* IPA_3_5_1 */
[IPA_3_5_1][IPA_CLIENT_WLAN1_PROD] = {
true, IPA_v3_5_GROUP_UL_DL, true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 7, 1, 8, 16, IPA_EE_UC } },
[IPA_3_5_1][IPA_CLIENT_USB_PROD] = {
true, IPA_v3_5_GROUP_UL_DL, true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 0, 0, 8, 16, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_APPS_LAN_PROD] = {
@@ -979,7 +979,7 @@
{ 8, 7, 8, 16, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_APPS_WAN_PROD] = {
true, IPA_v3_5_GROUP_UL_DL, true,
- IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP,
+ IPA_DPS_HPS_REP_SEQ_TYPE_2PKT_PROC_PASS_NO_DEC_UCP_DMAP,
QMB_MASTER_SELECT_DDR,
{ 2, 3, 16, 32, IPA_EE_AP } },
[IPA_3_5_1][IPA_CLIENT_APPS_CMD_PROD] = {
diff --git a/drivers/platform/msm/ipa/test/ipa_pm_ut.c b/drivers/platform/msm/ipa/test/ipa_pm_ut.c
index e07040a..83b705d 100644
--- a/drivers/platform/msm/ipa/test/ipa_pm_ut.c
+++ b/drivers/platform/msm/ipa/test/ipa_pm_ut.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
@@ -23,18 +23,32 @@
static int ipa_pm_ut_setup(void **ppriv)
{
+ int i;
IPA_UT_DBG("Start Setup\n");
/* decrement UT vote */
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT");
+ /*decouple PM from RPM */
+ ipa3_ctx->enable_clock_scaling = false;
+
+ if (ipa3_ctx->use_ipa_pm) {
+ for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) {
+ ipa_pm_deactivate_sync(i);
+ ipa_pm_deregister(i);
+ }
+
+ ipa_pm_destroy();
+ }
+
return 0;
}
static int ipa_pm_ut_teardown(void *priv)
{
IPA_UT_DBG("Start Teardown\n");
+ IPA_UT_ERR("WARNING: IPA_PM HAS BEEN DESTROYED, REBOOT TO RE_INIT\n");
/* undo UT vote */
IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT");
@@ -106,7 +120,7 @@
struct callback_param user_data;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -223,7 +237,7 @@
struct callback_param user_data;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -327,7 +341,7 @@
struct callback_param user_data;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -436,7 +450,7 @@
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -648,7 +662,7 @@
struct callback_param user_data;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -797,7 +811,7 @@
struct callback_param user_data;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -885,7 +899,7 @@
unsigned long flags;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -957,7 +971,7 @@
int i, hdl_USB, hdl_WLAN, vote;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -1095,7 +1109,7 @@
int hdl_USB, hdl_WLAN, vote, idx;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -1210,7 +1224,7 @@
int hdl_USB, hdl_WLAN, hdl_MODEM, vote, idx;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -1377,7 +1391,7 @@
int hdl_USB, hdl_WLAN, hdl_MODEM, vote, idx;
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000}
};
@@ -1542,7 +1556,7 @@
};
struct ipa_pm_init_params init_params = {
- .threshold_size = IPA_PM_THRESHOLD_MAX,
+ .threshold_size = 2,
.default_threshold = {600, 1000},
.exception_size = 1,
.exceptions[0] = exceptions,
diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c
index 1c16e5a..f06d6f3 100644
--- a/drivers/platform/msm/mhi_dev/mhi.c
+++ b/drivers/platform/msm/mhi_dev/mhi.c
@@ -1021,10 +1021,9 @@
if (rc)
pr_err("Error sending command completion event\n");
+ mhi_update_state_info(ch_id, MHI_STATE_CONNECTED);
/* Trigger callback to clients */
mhi_dev_trigger_cb();
-
- mhi_update_state_info(ch_id, MHI_STATE_CONNECTED);
if (ch_id == MHI_CLIENT_MBIM_OUT)
kobject_uevent_env(&mhi_ctx->dev->kobj,
KOBJ_CHANGE, connected);
@@ -1418,16 +1417,20 @@
union mhi_dev_ring_element_type *el;
int rc = 0;
struct mhi_req *req = (struct mhi_req *)mreq;
- struct mhi_req *local_req = NULL;
union mhi_dev_ring_element_type *compl_ev = NULL;
struct mhi_dev *mhi = NULL;
unsigned long flags;
+ size_t transfer_len;
+ u32 snd_cmpl;
+ uint32_t rd_offset;
client = req->client;
ch = client->channel;
mhi = ch->ring->mhi_dev;
el = req->el;
- local_req = req;
+ transfer_len = req->len;
+ snd_cmpl = req->snd_cmpl;
+ rd_offset = req->rd_offset;
ch->curr_ereq->context = ch;
dma_unmap_single(&mhi_ctx->pdev->dev, req->dma,
@@ -1441,14 +1444,13 @@
compl_ev->evt_tr_comp.chid = ch->ch_id;
compl_ev->evt_tr_comp.type =
MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT;
- compl_ev->evt_tr_comp.len = el->tre.len;
+ compl_ev->evt_tr_comp.len = transfer_len;
compl_ev->evt_tr_comp.code = MHI_CMD_COMPL_CODE_EOT;
compl_ev->evt_tr_comp.ptr = ch->ring->ring_ctx->generic.rbase +
- local_req->rd_offset * TR_RING_ELEMENT_SZ;
+ rd_offset * TR_RING_ELEMENT_SZ;
ch->curr_ereq->num_events++;
- if (ch->curr_ereq->num_events >= MAX_TR_EVENTS ||
- local_req->snd_cmpl){
+ if (ch->curr_ereq->num_events >= MAX_TR_EVENTS || snd_cmpl) {
mhi_log(MHI_MSG_VERBOSE,
"num of tr events %d for ch %d\n",
ch->curr_ereq->num_events, ch->ch_id);
@@ -2452,8 +2454,10 @@
* If channel is open during registration, no callback is issued.
* Instead return -EEXIST to notify the client. Clients request
* is added to the list to notify future state change notification.
+ * Channel struct may not be allocated yet if this function is called
+ * early during boot - add an explicit check for non-null "ch".
*/
- if (mhi_ctx->ch[channel].state == MHI_DEV_CH_STARTED) {
+ if (mhi_ctx->ch && (mhi_ctx->ch[channel].state == MHI_DEV_CH_STARTED)) {
mutex_unlock(&mhi_ctx->mhi_lock);
return -EEXIST;
}
@@ -2832,8 +2836,6 @@
INIT_LIST_HEAD(&mhi_ctx->event_ring_list);
INIT_LIST_HEAD(&mhi_ctx->process_ring_list);
- INIT_LIST_HEAD(&mhi_ctx->client_cb_list);
- mutex_init(&mhi_ctx->mhi_lock);
mutex_init(&mhi_ctx->mhi_event_lock);
mutex_init(&mhi_ctx->mhi_write_test);
@@ -2983,6 +2985,14 @@
dev_err(&pdev->dev,
"Failed to create IPC logging context\n");
}
+ /*
+ * The below list and mutex should be initialized
+ * before calling mhi_uci_init to avoid crash in
+ * mhi_register_state_cb when accessing these.
+ */
+ INIT_LIST_HEAD(&mhi_ctx->client_cb_list);
+ mutex_init(&mhi_ctx->mhi_lock);
+
mhi_uci_init();
mhi_update_state_info(MHI_DEV_UEVENT_CTRL,
MHI_STATE_CONFIGURED);
diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c
index 6ce2161..ed4b837 100644
--- a/drivers/platform/msm/qcom-geni-se.c
+++ b/drivers/platform/msm/qcom-geni-se.c
@@ -317,7 +317,9 @@
static int geni_se_select_dma_mode(void __iomem *base)
{
+ int proto = get_se_proto(base);
unsigned int geni_dma_mode = 0;
+ unsigned int common_geni_m_irq_en;
geni_write_reg(0, base, SE_GSI_EVENT_EN);
geni_write_reg(0xFFFFFFFF, base, SE_GENI_M_IRQ_CLEAR);
@@ -326,6 +328,12 @@
geni_write_reg(0xFFFFFFFF, base, SE_DMA_RX_IRQ_CLR);
geni_write_reg(0xFFFFFFFF, base, SE_IRQ_EN);
+ common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN);
+ if (proto != UART)
+ common_geni_m_irq_en &=
+ ~(M_TX_FIFO_WATERMARK_EN | M_RX_FIFO_WATERMARK_EN);
+
+ geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN);
geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN);
geni_dma_mode |= GENI_DMA_MODE_EN;
geni_write_reg(geni_dma_mode, base, SE_GENI_DMA_MODE_EN);
diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c
index 3dd1722..3ab93fe 100644
--- a/drivers/power/supply/power_supply_sysfs.c
+++ b/drivers/power/supply/power_supply_sysfs.c
@@ -331,6 +331,10 @@
POWER_SUPPLY_ATTR(allow_hvdcp3),
POWER_SUPPLY_ATTR(hvdcp_opti_allowed),
POWER_SUPPLY_ATTR(max_pulse_allowed),
+ POWER_SUPPLY_ATTR(ignore_false_negative_isense),
+ POWER_SUPPLY_ATTR(battery_info),
+ POWER_SUPPLY_ATTR(battery_info_id),
+ POWER_SUPPLY_ATTR(enable_jeita_detection),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile
index da20d93..ffc1ce3 100644
--- a/drivers/power/supply/qcom/Makefile
+++ b/drivers/power/supply/qcom/Makefile
@@ -7,7 +7,7 @@
obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o
obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o
obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o
-obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o
+obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o
obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o
obj-$(CONFIG_QPNP_TYPEC) += qpnp-typec.o
obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o
diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c
index 275b982..e8d91ae 100644
--- a/drivers/power/supply/qcom/battery.c
+++ b/drivers/power/supply/qcom/battery.c
@@ -78,6 +78,7 @@
struct class qcom_batt_class;
struct wakeup_source *pl_ws;
struct notifier_block nb;
+ bool pl_disable;
};
struct pl_data *the_chip;
@@ -88,6 +89,7 @@
enum {
AICL_RERUN_WA_BIT = BIT(0),
+ FORCE_INOV_DISABLE_BIT = BIT(1),
};
static int debug_mask;
@@ -848,6 +850,12 @@
chip->pl_settled_ua = 0;
}
+ /* notify parallel state change */
+ if (chip->pl_psy && (chip->pl_disable != pl_disable)) {
+ power_supply_changed(chip->pl_psy);
+ chip->pl_disable = (bool)pl_disable;
+ }
+
pl_dbg(chip, PR_PARALLEL, "parallel charging %s\n",
pl_disable ? "disabled" : "enabled");
@@ -916,7 +924,8 @@
chip->pl_mode = pval.intval;
/* Disable autonomous votage increments for USBIN-USBIN */
- if (IS_USBIN(chip->pl_mode)) {
+ if (IS_USBIN(chip->pl_mode)
+ && (chip->wa_flags & FORCE_INOV_DISABLE_BIT)) {
if (!chip->hvdcp_hw_inov_dis_votable)
chip->hvdcp_hw_inov_dis_votable =
find_votable("HVDCP_HW_INOV_DIS");
@@ -1041,7 +1050,6 @@
else
vote(chip->pl_enable_votable_indirect, USBIN_I_VOTER, true, 0);
- rerun_election(chip->fcc_votable);
if (IS_USBIN(chip->pl_mode)) {
/*
@@ -1200,7 +1208,9 @@
switch (smb_version) {
case PMI8998_SUBTYPE:
case PM660_SUBTYPE:
- chip->wa_flags = AICL_RERUN_WA_BIT;
+ chip->wa_flags = AICL_RERUN_WA_BIT | FORCE_INOV_DISABLE_BIT;
+ break;
+ case PMI632_SUBTYPE:
break;
default:
break;
@@ -1301,6 +1311,7 @@
goto unreg_notifier;
}
+ chip->pl_disable = true;
chip->qcom_batt_class.name = "qcom-battery",
chip->qcom_batt_class.owner = THIS_MODULE,
chip->qcom_batt_class.class_attrs = pl_attributes;
diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c
index 3d74f7e..129af7b 100644
--- a/drivers/power/supply/qcom/fg-alg.c
+++ b/drivers/power/supply/qcom/fg-alg.c
@@ -19,6 +19,7 @@
#include "fg-alg.h"
#define FULL_SOC_RAW 255
+#define FULL_BATT_SOC GENMASK(31, 0)
#define CAPACITY_DELTA_DECIPCT 500
/* Cycle counter APIs */
@@ -164,13 +165,13 @@
}
/**
- * get_cycle_count -
+ * get_bucket_cycle_count -
* @counter: Cycle counter object
*
* Returns the cycle counter for a SOC bucket.
*
*/
-int get_cycle_count(struct cycle_counter *counter)
+static int get_bucket_cycle_count(struct cycle_counter *counter)
{
int count;
@@ -187,6 +188,68 @@
}
/**
+ * get_cycle_counts -
+ * @counter: Cycle counter object
+ * @buf: Bucket cycle counts formatted in a string returned to the caller
+ *
+ * Get cycle count for all buckets in a string format
+ */
+int get_cycle_counts(struct cycle_counter *counter, const char **buf)
+{
+ int i, rc, len = 0;
+
+ for (i = 1; i <= BUCKET_COUNT; i++) {
+ counter->id = i;
+ rc = get_bucket_cycle_count(counter);
+ if (rc < 0) {
+ pr_err("Couldn't get cycle count rc=%d\n", rc);
+ return rc;
+ }
+
+ if (sizeof(counter->str_buf) - len < 8) {
+ pr_err("Invalid length %d\n", len);
+ return -EINVAL;
+ }
+
+ len += snprintf(counter->str_buf+len, 8, "%d ", rc);
+ }
+
+ counter->str_buf[len] = '\0';
+ *buf = counter->str_buf;
+ return 0;
+}
+
+/**
+ * get_cycle_count -
+ * @counter: Cycle counter object
+ * @count: Average cycle count returned to the caller
+ *
+ * Get average cycle count for all buckets
+ */
+int get_cycle_count(struct cycle_counter *counter, int *count)
+{
+ int i, rc, temp = 0;
+
+ for (i = 1; i <= BUCKET_COUNT; i++) {
+ counter->id = i;
+ rc = get_bucket_cycle_count(counter);
+ if (rc < 0) {
+ pr_err("Couldn't get cycle count rc=%d\n", rc);
+ return rc;
+ }
+
+ temp += rc;
+ }
+
+ /*
+ * Normalize the counter across each bucket so that we can get
+ * the overall charge cycle count.
+ */
+ *count = temp / BUCKET_COUNT;
+ return 0;
+}
+
+/**
* cycle_count_init -
* @counter: Cycle counter object
*
@@ -289,7 +352,7 @@
*/
static int cap_learning_process_full_data(struct cap_learning *cl)
{
- int rc, cc_soc_sw, cc_soc_delta_pct;
+ int rc, cc_soc_sw, cc_soc_delta_centi_pct;
int64_t delta_cap_uah;
rc = cl->get_cc_soc(cl->data, &cc_soc_sw);
@@ -298,20 +361,21 @@
return rc;
}
- cc_soc_delta_pct =
- div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 100,
+ cc_soc_delta_centi_pct =
+ div64_s64((int64_t)(cc_soc_sw - cl->init_cc_soc_sw) * 10000,
cl->cc_soc_max);
/* If the delta is < 50%, then skip processing full data */
- if (cc_soc_delta_pct < 50) {
- pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct);
+ if (cc_soc_delta_centi_pct < 5000) {
+ pr_err("cc_soc_delta_centi_pct: %d\n", cc_soc_delta_centi_pct);
return -ERANGE;
}
- delta_cap_uah = div64_s64(cl->learned_cap_uah * cc_soc_delta_pct, 100);
+ delta_cap_uah = div64_s64(cl->learned_cap_uah * cc_soc_delta_centi_pct,
+ 10000);
cl->final_cap_uah = cl->init_cap_uah + delta_cap_uah;
- pr_debug("Current cc_soc=%d cc_soc_delta_pct=%d total_cap_uah=%lld\n",
- cc_soc_sw, cc_soc_delta_pct, cl->final_cap_uah);
+ pr_debug("Current cc_soc=%d cc_soc_delta_centi_pct=%d total_cap_uah=%lld\n",
+ cc_soc_sw, cc_soc_delta_centi_pct, cl->final_cap_uah);
return 0;
}
@@ -327,18 +391,20 @@
*/
static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc)
{
- int rc, cc_soc_sw, batt_soc_msb;
+ int rc, cc_soc_sw, batt_soc_msb, batt_soc_pct;
batt_soc_msb = batt_soc >> 24;
- if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
- cl->dt.start_soc) {
- pr_debug("Battery SOC %d is high!, not starting\n",
- batt_soc_msb);
+ batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW);
+
+ if (batt_soc_pct > cl->dt.max_start_soc ||
+ batt_soc_pct < cl->dt.min_start_soc) {
+ pr_debug("Battery SOC %d is high/low, not starting\n",
+ batt_soc_pct);
return -EINVAL;
}
- cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc_msb,
- FULL_SOC_RAW);
+ cl->init_cap_uah = div64_s64(cl->learned_cap_uah * batt_soc,
+ FULL_BATT_SOC);
if (cl->prime_cc_soc) {
/*
diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h
index ff5bece..7c25007 100644
--- a/drivers/power/supply/qcom/fg-alg.h
+++ b/drivers/power/supply/qcom/fg-alg.h
@@ -21,6 +21,7 @@
bool started[BUCKET_COUNT];
u16 count[BUCKET_COUNT];
u8 last_soc[BUCKET_COUNT];
+ char str_buf[BUCKET_COUNT * 8];
int id;
int last_bucket;
struct mutex lock;
@@ -29,7 +30,8 @@
};
struct cl_params {
- int start_soc;
+ int min_start_soc;
+ int max_start_soc;
int max_temp;
int min_temp;
int max_cap_inc;
@@ -60,7 +62,8 @@
void clear_cycle_count(struct cycle_counter *counter);
void cycle_count_update(struct cycle_counter *counter, int batt_soc,
int charge_status, bool charge_done, bool input_present);
-int get_cycle_count(struct cycle_counter *counter);
+int get_cycle_count(struct cycle_counter *counter, int *count);
+int get_cycle_counts(struct cycle_counter *counter, const char **buf);
int cycle_count_init(struct cycle_counter *counter);
void cap_learning_abort(struct cap_learning *cl);
void cap_learning_update(struct cap_learning *cl, int batt_temp,
diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c
index 441c759..36edd76 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.c
+++ b/drivers/power/supply/qcom/qg-battery-profile.c
@@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <uapi/linux/qg-profile.h>
+#include "qg-battery-profile.h"
#include "qg-profile-lib.h"
#include "qg-defs.h"
@@ -410,6 +411,26 @@
return 0;
}
+int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging)
+{
+ u8 table_index = charging ? TABLE_FCC1 : TABLE_FCC2;
+ u32 fcc_mah;
+
+ if (!the_battery || !the_battery->profile) {
+ pr_err("Battery profile not loaded\n");
+ return -ENODEV;
+ }
+
+ fcc_mah = interpolate_single_row_lut(
+ &the_battery->profile[table_index],
+ batt_temp, DEGC_SCALE);
+ fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah);
+
+ *nom_cap_uah = fcc_mah * 1000;
+
+ return 0;
+}
+
int qg_batterydata_init(struct device_node *profile_node)
{
int rc = 0;
diff --git a/drivers/power/supply/qcom/qg-battery-profile.h b/drivers/power/supply/qcom/qg-battery-profile.h
index 143a4f2..1b06277 100644
--- a/drivers/power/supply/qcom/qg-battery-profile.h
+++ b/drivers/power/supply/qcom/qg-battery-profile.h
@@ -15,5 +15,6 @@
int qg_batterydata_init(struct device_node *node);
void qg_batterydata_exit(void);
int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging);
+int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging);
#endif /* __QG_BATTERY_PROFILE_H__ */
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index 6e44f33..a1aeac2 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -12,6 +12,9 @@
#ifndef __QG_CORE_H__
#define __QG_CORE_H__
+#include <linux/kernel.h>
+#include "fg-alg.h"
+
struct qg_batt_props {
const char *batt_type_str;
int float_volt_uv;
@@ -49,6 +52,8 @@
int cold_temp_threshold;
bool hold_soc_while_full;
bool linearize_soc;
+ bool cl_disable;
+ bool cl_feedback_on;
};
struct qpnp_qg {
@@ -109,12 +114,18 @@
int maint_soc;
int msoc;
int pon_soc;
+ int batt_soc;
+ int cc_soc;
struct alarm alarm_timer;
u32 sdam_data[SDAM_MAX];
/* DT */
struct qg_dt dt;
struct qg_batt_props bp;
+ /* capacity learning */
+ struct cap_learning *cl;
+ /* charge counter */
+ struct cycle_counter *counter;
};
enum ocv_type {
@@ -135,6 +146,7 @@
QG_DEBUG_PM = BIT(7),
QG_DEBUG_BUS_READ = BIT(8),
QG_DEBUG_BUS_WRITE = BIT(9),
+ QG_DEBUG_ALG_CL = BIT(10),
};
enum qg_irq {
diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h
index 6ae9aa2..2061208 100644
--- a/drivers/power/supply/qcom/qg-defs.h
+++ b/drivers/power/supply/qcom/qg-defs.h
@@ -47,4 +47,7 @@
#define CAP(min, max, value) \
((min > value) ? min : ((value > max) ? max : value))
+#define QG_SOC_FULL 10000
+#define BATT_SOC_32BIT GENMASK(31, 0)
+
#endif /* __QG_DEFS_H__ */
diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h
index 96533d4..66f9be1 100644
--- a/drivers/power/supply/qcom/qg-reg.h
+++ b/drivers/power/supply/qcom/qg-reg.h
@@ -87,6 +87,8 @@
#define QG_SDAM_OCV_OFFSET 0x4C
#define QG_SDAM_IBAT_OFFSET 0x50
#define QG_SDAM_TIME_OFFSET 0x54
+#define QG_SDAM_CYCLE_COUNT_OFFSET 0x58
+#define QG_SDAM_LEARNED_CAPACITY_OFFSET 0x68
#define QG_SDAM_PON_OCV_OFFSET 0x7C
#endif
diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c
index 54eed16..7bc4afa 100644
--- a/drivers/power/supply/qcom/qg-sdam.c
+++ b/drivers/power/supply/qcom/qg-sdam.c
@@ -130,6 +130,53 @@
return rc;
}
+int qg_sdam_multibyte_write(u32 offset, u8 *data, u32 length)
+{
+ int rc, i;
+ struct qg_sdam *chip = the_chip;
+
+ if (!chip) {
+ pr_err("Invalid sdam-chip pointer\n");
+ return -EINVAL;
+ }
+
+ offset = chip->sdam_base + offset;
+ rc = regmap_bulk_write(chip->regmap, offset, data, (size_t)length);
+ if (rc < 0) {
+ pr_err("Failed to write offset=%0x4x value=%d\n",
+ offset, *data);
+ } else {
+ for (i = 0; i < length; i++)
+ pr_debug("QG SDAM write offset=%0x4x value=%d\n",
+ offset++, data[i]);
+ }
+
+ return rc;
+}
+
+int qg_sdam_multibyte_read(u32 offset, u8 *data, u32 length)
+{
+ int rc, i;
+ struct qg_sdam *chip = the_chip;
+
+ if (!chip) {
+ pr_err("Invalid sdam-chip pointer\n");
+ return -EINVAL;
+ }
+
+ offset = chip->sdam_base + offset;
+ rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, (size_t)length);
+ if (rc < 0) {
+ pr_err("Failed to read offset=%0x4x\n", offset);
+ } else {
+ for (i = 0; i < length; i++)
+ pr_debug("QG SDAM read offset=%0x4x value=%d\n",
+ offset++, data[i]);
+ }
+
+ return rc;
+}
+
int qg_sdam_read_all(u32 *sdam_data)
{
int i, rc;
diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h
index 51af04c..10e684f 100644
--- a/drivers/power/supply/qcom/qg-sdam.h
+++ b/drivers/power/supply/qcom/qg-sdam.h
@@ -37,5 +37,7 @@
int qg_sdam_read(u8 param, u32 *data);
int qg_sdam_write_all(u32 *sdam_data);
int qg_sdam_read_all(u32 *sdam_data);
+int qg_sdam_multibyte_write(u32 offset, u8 *sdam_data, u32 length);
+int qg_sdam_multibyte_read(u32 offset, u8 *sdam_data, u32 length);
#endif
diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c
index c4d5043..af8b158 100644
--- a/drivers/power/supply/qcom/qg-soc.c
+++ b/drivers/power/supply/qcom/qg-soc.c
@@ -13,9 +13,11 @@
#define pr_fmt(fmt) "QG-K: %s: " fmt, __func__
#include <linux/alarmtimer.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/power_supply.h>
#include <uapi/linux/qg.h>
+#include "fg-alg.h"
#include "qg-sdam.h"
#include "qg-core.h"
#include "qg-reg.h"
@@ -98,11 +100,12 @@
static void update_msoc(struct qpnp_qg *chip)
{
- int rc;
+ int rc = 0, batt_temp = 0, batt_soc_32bit = 0;
+ bool usb_present = is_usb_present(chip);
if (chip->catch_up_soc > chip->msoc) {
/* SOC increased */
- if (is_usb_present(chip)) /* Increment if USB is present */
+ if (usb_present) /* Increment if USB is present */
chip->msoc += chip->dt.delta_soc;
} else if (chip->catch_up_soc < chip->msoc) {
/* SOC dropped */
@@ -130,6 +133,25 @@
if (rc < 0)
pr_err("Failed to update SDAM with MSOC rc=%d\n", rc);
+ if (!chip->dt.cl_disable && chip->cl->active) {
+ rc = qg_get_battery_temp(chip, &batt_temp);
+ if (rc < 0) {
+ pr_err("Failed to read BATT_TEMP rc=%d\n", rc);
+ } else {
+ batt_soc_32bit = div64_u64(
+ chip->batt_soc * BATT_SOC_32BIT,
+ QG_SOC_FULL);
+ cap_learning_update(chip->cl, batt_temp, batt_soc_32bit,
+ chip->charge_status, chip->charge_done,
+ usb_present, false);
+ }
+ }
+
+ cycle_count_update(chip->counter,
+ DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
+ chip->charge_status, chip->charge_done,
+ usb_present);
+
qg_dbg(chip, QG_DEBUG_SOC,
"SOC scale: Update maint_soc=%d msoc=%d catch_up_soc=%d delta_soc=%d\n",
chip->maint_soc, chip->msoc,
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index f7a6b7a..5a0682c 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -16,6 +16,7 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -28,6 +29,7 @@
#include <linux/pmic-voter.h>
#include <linux/qpnp/qpnp-adc.h>
#include <uapi/linux/qg.h>
+#include "fg-alg.h"
#include "qg-sdam.h"
#include "qg-core.h"
#include "qg-reg.h"
@@ -259,8 +261,13 @@
int rc = 0, i, j = 0, temp;
u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2];
u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0;
+ unsigned long rtc_sec = 0;
- chip->kdata.fifo_time = (u32)ktime_get_seconds();
+ rc = get_rtc_time(&rtc_sec);
+ if (rc < 0)
+ pr_err("Failed to get RTC time, rc=%d\n", rc);
+
+ chip->kdata.fifo_time = (u32)rtc_sec;
if (!fifo_length) {
pr_debug("No FIFO data\n");
@@ -641,6 +648,12 @@
struct qpnp_qg, udata_work);
int rc;
+ if (chip->udata.param[QG_CC_SOC].valid)
+ chip->cc_soc = chip->udata.param[QG_CC_SOC].data;
+
+ if (chip->udata.param[QG_BATT_SOC].valid)
+ chip->batt_soc = chip->udata.param[QG_BATT_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);
@@ -946,6 +959,127 @@
return 0;
}
+/* ALG callback functions below */
+
+static int qg_get_learned_capacity(void *data, int64_t *learned_cap_uah)
+{
+ struct qpnp_qg *chip = data;
+ int16_t cc_mah;
+ int rc;
+
+ if (!chip)
+ return -ENODEV;
+
+ if (chip->battery_missing || !chip->profile_loaded)
+ return -EPERM;
+
+ rc = qg_sdam_multibyte_read(QG_SDAM_LEARNED_CAPACITY_OFFSET,
+ (u8 *)&cc_mah, 2);
+ if (rc < 0) {
+ pr_err("Error in reading learned_capacity, rc=%d\n", rc);
+ return rc;
+ }
+ *learned_cap_uah = cc_mah * 1000;
+
+ qg_dbg(chip, QG_DEBUG_ALG_CL, "Retrieved learned capacity %llduah\n",
+ *learned_cap_uah);
+ return 0;
+}
+
+static int qg_store_learned_capacity(void *data, int64_t learned_cap_uah)
+{
+ struct qpnp_qg *chip = data;
+ int16_t cc_mah;
+ int rc;
+
+ if (!chip)
+ return -ENODEV;
+
+ if (chip->battery_missing || !learned_cap_uah)
+ return -EPERM;
+
+ cc_mah = div64_s64(learned_cap_uah, 1000);
+ rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET,
+ (u8 *)&cc_mah, 2);
+ if (rc < 0) {
+ pr_err("Error in writing learned_capacity, rc=%d\n", rc);
+ return rc;
+ }
+
+ qg_dbg(chip, QG_DEBUG_ALG_CL, "Stored learned capacity %llduah\n",
+ learned_cap_uah);
+ return 0;
+}
+
+static int qg_get_cc_soc(void *data, int *cc_soc)
+{
+ struct qpnp_qg *chip = data;
+
+ if (!chip)
+ return -ENODEV;
+
+ if (chip->cc_soc == INT_MIN)
+ return -EINVAL;
+
+ *cc_soc = chip->cc_soc;
+
+ return 0;
+}
+
+static int qg_restore_cycle_count(void *data, u16 *buf, int length)
+{
+ struct qpnp_qg *chip = data;
+ int id, rc = 0;
+ u8 tmp[2];
+
+ if (!chip)
+ return -ENODEV;
+
+ if (chip->battery_missing || !chip->profile_loaded)
+ return -EPERM;
+
+ if (!buf || length > BUCKET_COUNT)
+ return -EINVAL;
+
+ for (id = 0; id < length; id++) {
+ rc = qg_sdam_multibyte_read(
+ QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2),
+ (u8 *)tmp, 2);
+ if (rc < 0) {
+ pr_err("failed to read bucket %d rc=%d\n", id, rc);
+ return rc;
+ }
+ *buf++ = tmp[0] | tmp[1] << 8;
+ }
+
+ return rc;
+}
+
+static int qg_store_cycle_count(void *data, u16 *buf, int id, int length)
+{
+ struct qpnp_qg *chip = data;
+ int rc = 0;
+
+ if (!chip)
+ return -ENODEV;
+
+ if (chip->battery_missing || !chip->profile_loaded)
+ return -EPERM;
+
+ if (!buf || length > BUCKET_COUNT * 2 || id < 0 ||
+ id > BUCKET_COUNT - 1 ||
+ (((id * 2) + length) > BUCKET_COUNT * 2))
+ return -EINVAL;
+
+ rc = qg_sdam_multibyte_write(
+ QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2),
+ (u8 *)buf, length);
+ if (rc < 0)
+ pr_err("failed to write bucket %d rc=%d\n", id, rc);
+
+ return rc;
+}
+
#define DEFAULT_BATT_TYPE "Unknown Battery"
#define MISSING_BATT_TYPE "Missing Battery"
#define DEBUG_BATT_TYPE "Debug Board"
@@ -968,17 +1102,36 @@
static int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua)
{
int rc = 0, last_ibat = 0;
+ u32 fifo_length = 0;
if (chip->battery_missing) {
*ibat_ua = 0;
return 0;
}
- rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG,
- (u8 *)&last_ibat, 2);
- if (rc < 0) {
- pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc);
- return rc;
+ if (chip->parallel_enabled) {
+ /* read the last real-time FIFO */
+ rc = get_fifo_length(chip, &fifo_length, true);
+ if (rc < 0) {
+ pr_err("Failed to read RT FIFO length, rc=%d\n", rc);
+ return rc;
+ }
+ fifo_length = (fifo_length == 0) ? 0 : fifo_length - 1;
+ fifo_length *= 2;
+ rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG +
+ fifo_length, (u8 *)&last_ibat, 2);
+ if (rc < 0) {
+ pr_err("Failed to read FIFO_I_%d reg, rc=%d\n",
+ fifo_length / 2, rc);
+ return rc;
+ }
+ } else {
+ rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG,
+ (u8 *)&last_ibat, 2);
+ if (rc < 0) {
+ pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc);
+ return rc;
+ }
}
last_ibat = sign_extend32(last_ibat, 15);
@@ -1046,6 +1199,32 @@
enum power_supply_property psp,
const union power_supply_propval *pval)
{
+ struct qpnp_qg *chip = power_supply_get_drvdata(psy);
+ int rc = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ if (chip->dt.cl_disable) {
+ pr_warn("Capacity learning disabled!\n");
+ return 0;
+ }
+ if (chip->cl->active) {
+ pr_warn("Capacity learning active!\n");
+ return 0;
+ }
+ if (pval->intval <= 0 || pval->intval > chip->cl->nom_cap_uah) {
+ pr_err("charge_full is out of bounds\n");
+ return -EINVAL;
+ }
+ mutex_lock(&chip->cl->lock);
+ rc = qg_store_learned_capacity(chip, pval->intval);
+ if (!rc)
+ chip->cl->learned_cap_uah = pval->intval;
+ mutex_unlock(&chip->cl->lock);
+ break;
+ default:
+ break;
+ }
return 0;
}
@@ -1055,6 +1234,7 @@
{
struct qpnp_qg *chip = power_supply_get_drvdata(psy);
int rc = 0;
+ int64_t temp = 0;
pval->intval = 0;
@@ -1106,6 +1286,27 @@
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
pval->intval = chip->charge_counter_uah;
break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ if (!chip->dt.cl_disable && chip->dt.cl_feedback_on)
+ rc = qg_get_learned_capacity(chip, &temp);
+ else
+ rc = qg_get_nominal_capacity((int *)&temp, 250, true);
+ if (!rc)
+ pval->intval = (int)temp;
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN:
+ rc = qg_get_nominal_capacity((int *)&temp, 250, true);
+ if (!rc)
+ pval->intval = (int)temp;
+ break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNTS:
+ rc = get_cycle_counts(chip->counter, &pval->strval);
+ if (rc < 0)
+ pval->strval = NULL;
+ break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ rc = get_cycle_count(chip->counter, &pval->intval);
+ break;
default:
pr_debug("Unsupported property %d\n", psp);
break;
@@ -1117,6 +1318,12 @@
static int qg_property_is_writeable(struct power_supply *psy,
enum power_supply_property psp)
{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_FULL:
+ return 1;
+ default:
+ break;
+ }
return 0;
}
@@ -1136,6 +1343,10 @@
POWER_SUPPLY_PROP_VOLTAGE_MAX,
POWER_SUPPLY_PROP_BATT_FULL_CURRENT,
POWER_SUPPLY_PROP_BATT_PROFILE_VERSION,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
+ POWER_SUPPLY_PROP_CYCLE_COUNTS,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
};
static const struct power_supply_desc qg_psy_desc = {
@@ -1262,7 +1473,7 @@
struct qpnp_qg *chip = container_of(work,
struct qpnp_qg, qg_status_change_work);
union power_supply_propval prop = {0, };
- int rc = 0;
+ int rc = 0, batt_temp = 0, batt_soc_32b = 0;
if (!is_batt_available(chip)) {
pr_debug("batt-psy not available\n");
@@ -1294,6 +1505,24 @@
if (rc < 0)
pr_err("Failed to update usb status, rc=%d\n", rc);
+ cycle_count_update(chip->counter,
+ DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
+ chip->charge_status, chip->charge_done,
+ chip->usb_present);
+
+ if (!chip->dt.cl_disable) {
+ rc = qg_get_battery_temp(chip, &batt_temp);
+ if (rc < 0) {
+ pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
+ } else {
+ batt_soc_32b = div64_u64(
+ chip->batt_soc * BATT_SOC_32BIT,
+ QG_SOC_FULL);
+ cap_learning_update(chip->cl, batt_temp, batt_soc_32b,
+ chip->charge_status, chip->charge_done,
+ chip->usb_present, false);
+ }
+ }
rc = qg_charge_full_update(chip);
if (rc < 0)
pr_err("Failed in charge_full_update, rc=%d\n", rc);
@@ -2069,6 +2298,64 @@
return 0;
}
+static int qg_alg_init(struct qpnp_qg *chip)
+{
+ struct cycle_counter *counter;
+ struct cap_learning *cl;
+ struct device_node *node = chip->dev->of_node;
+ int rc;
+
+ counter = devm_kzalloc(chip->dev, sizeof(*counter), GFP_KERNEL);
+ if (!counter)
+ return -ENOMEM;
+
+ counter->restore_count = qg_restore_cycle_count;
+ counter->store_count = qg_store_cycle_count;
+ counter->data = chip;
+
+ rc = cycle_count_init(counter);
+ if (rc < 0) {
+ dev_err(chip->dev, "Error in initializing cycle counter, rc:%d\n",
+ rc);
+ counter->data = NULL;
+ devm_kfree(chip->dev, counter);
+ return rc;
+ }
+
+ chip->counter = counter;
+
+ chip->dt.cl_disable = of_property_read_bool(node,
+ "qcom,cl-disable");
+
+ /*Return if capacity learning is disabled*/
+ if (chip->dt.cl_disable)
+ return 0;
+
+ cl = devm_kzalloc(chip->dev, sizeof(*cl), GFP_KERNEL);
+ if (!cl)
+ return -ENOMEM;
+
+ cl->cc_soc_max = QG_SOC_FULL;
+ cl->get_cc_soc = qg_get_cc_soc;
+ cl->get_learned_capacity = qg_get_learned_capacity;
+ cl->store_learned_capacity = qg_store_learned_capacity;
+ cl->data = chip;
+
+ rc = cap_learning_init(cl);
+ if (rc < 0) {
+ dev_err(chip->dev, "Error in initializing capacity learning, rc:%d\n",
+ rc);
+ counter->data = NULL;
+ cl->data = NULL;
+ devm_kfree(chip->dev, counter);
+ devm_kfree(chip->dev, cl);
+ return rc;
+ }
+
+ chip->cl = cl;
+ return 0;
+}
+
#define DEFAULT_VBATT_EMPTY_MV 3200
#define DEFAULT_VBATT_EMPTY_COLD_MV 3000
#define DEFAULT_VBATT_CUTOFF_MV 3400
@@ -2082,6 +2369,14 @@
#define DEFAULT_DELTA_SOC 1
#define DEFAULT_SHUTDOWN_SOC_SECS 360
#define DEFAULT_COLD_TEMP_THRESHOLD 0
+#define DEFAULT_CL_MIN_START_SOC 10
+#define DEFAULT_CL_MAX_START_SOC 15
+#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150
+#define DEFAULT_CL_MAX_TEMP_DECIDEGC 500
+#define DEFAULT_CL_MAX_INC_DECIPERC 5
+#define DEFAULT_CL_MAX_DEC_DECIPERC 100
+#define DEFAULT_CL_MIN_LIM_DECIPERC 0
+#define DEFAULT_CL_MAX_LIM_DECIPERC 0
static int qg_parse_dt(struct qpnp_qg *chip)
{
int rc = 0;
@@ -2275,6 +2570,65 @@
else
chip->dt.rbat_conn_mohm = temp;
+ /* Capacity learning params*/
+ if (!chip->dt.cl_disable) {
+ chip->dt.cl_feedback_on = of_property_read_bool(node,
+ "qcom,cl-feedback-on");
+
+ rc = of_property_read_u32(node, "qcom,cl-min-start-soc", &temp);
+ if (rc < 0)
+ chip->cl->dt.min_start_soc = DEFAULT_CL_MIN_START_SOC;
+ else
+ chip->cl->dt.min_start_soc = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-max-start-soc", &temp);
+ if (rc < 0)
+ chip->cl->dt.max_start_soc = DEFAULT_CL_MAX_START_SOC;
+ else
+ chip->cl->dt.max_start_soc = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp);
+ if (rc < 0)
+ chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC;
+ else
+ chip->cl->dt.min_temp = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp);
+ if (rc < 0)
+ chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC;
+ else
+ chip->cl->dt.max_temp = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp);
+ if (rc < 0)
+ chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC;
+ else
+ chip->cl->dt.max_cap_inc = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp);
+ if (rc < 0)
+ chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC;
+ else
+ chip->cl->dt.max_cap_dec = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp);
+ if (rc < 0)
+ chip->cl->dt.min_cap_limit =
+ DEFAULT_CL_MIN_LIM_DECIPERC;
+ else
+ chip->cl->dt.min_cap_limit = temp;
+
+ rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp);
+ if (rc < 0)
+ chip->cl->dt.max_cap_limit =
+ DEFAULT_CL_MAX_LIM_DECIPERC;
+ else
+ chip->cl->dt.max_cap_limit = temp;
+
+ qg_dbg(chip, QG_DEBUG_PON, "DT: cl_min_start_soc=%d cl_max_start_soc=%d cl_min_temp=%d cl_max_temp=%d\n",
+ chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc,
+ chip->cl->dt.min_temp, chip->cl->dt.max_temp);
+ }
qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d\n",
chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv,
chip->dt.delta_soc);
@@ -2392,7 +2746,9 @@
chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv;
chip->kdata.param[QG_GOOD_OCV_UV].valid = true;
/* Clear suspend data as there has been a GOOD OCV */
+ memset(&chip->kdata, 0, sizeof(chip->kdata));
chip->suspend_data = false;
+
qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n",
ocv_uv);
}
@@ -2464,7 +2820,7 @@
static int qpnp_qg_probe(struct platform_device *pdev)
{
- int rc = 0, soc = 0;
+ int rc = 0, soc = 0, nom_cap_uah;
struct qpnp_qg *chip;
chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
@@ -2497,6 +2853,14 @@
mutex_init(&chip->data_lock);
init_waitqueue_head(&chip->qg_wait_q);
chip->maint_soc = -EINVAL;
+ chip->batt_soc = INT_MIN;
+ chip->cc_soc = INT_MIN;
+
+ rc = qg_alg_init(chip);
+ if (rc < 0) {
+ pr_err("Error in alg_init, rc:%d\n", rc);
+ return rc;
+ }
rc = qg_parse_dt(chip);
if (rc < 0) {
@@ -2534,6 +2898,30 @@
return rc;
}
+ if (chip->profile_loaded) {
+ if (!chip->dt.cl_disable) {
+ /*
+ * Use FCC @ 25 C and charge-profile for
+ * Nominal Capacity
+ */
+ rc = qg_get_nominal_capacity(&nom_cap_uah, 250, true);
+ if (!rc) {
+ rc = cap_learning_post_profile_init(chip->cl,
+ nom_cap_uah);
+ if (rc < 0) {
+ pr_err("Error in cap_learning_post_profile_init rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+ }
+ rc = restore_cycle_count(chip->counter);
+ if (rc < 0) {
+ pr_err("Error in restoring cycle_count, rc=%d\n", rc);
+ return rc;
+ }
+ }
+
rc = qg_determine_pon_soc(chip);
if (rc < 0) {
pr_err("Failed to determine initial state, rc=%d\n", rc);
@@ -2627,6 +3015,22 @@
return 0;
}
+static void qpnp_qg_shutdown(struct platform_device *pdev)
+{
+ struct qpnp_qg *chip = platform_get_drvdata(pdev);
+
+ if (!is_usb_present(chip) || !chip->profile_loaded)
+ return;
+ /*
+ * Charging status doesn't matter when the device shuts down and we
+ * have to treat this as charge done. Hence pass charge_done as true.
+ */
+ cycle_count_update(chip->counter,
+ DIV_ROUND_CLOSEST(chip->msoc * 255, 100),
+ POWER_SUPPLY_STATUS_NOT_CHARGING,
+ true, chip->usb_present);
+}
+
static const struct of_device_id match_table[] = {
{ .compatible = "qcom,qpnp-qg", },
{ },
@@ -2641,6 +3045,7 @@
},
.probe = qpnp_qg_probe,
.remove = qpnp_qg_remove,
+ .shutdown = qpnp_qg_shutdown,
};
module_platform_driver(qpnp_qg_driver);
diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c
index d3aaf26..8ff5330d 100644
--- a/drivers/power/supply/qcom/qpnp-smb5.c
+++ b/drivers/power/supply/qcom/qpnp-smb5.c
@@ -52,6 +52,13 @@
.max_u = 3000000,
.step_u = 50000,
},
+ .icl_max_stat = {
+ .name = "dcdc icl max status",
+ .reg = ICL_MAX_STATUS_REG,
+ .min_u = 0,
+ .max_u = 3000000,
+ .step_u = 50000,
+ },
.icl_stat = {
.name = "input current limit status",
.reg = AICL_ICL_STATUS_REG,
@@ -90,7 +97,7 @@
},
};
-static struct smb_params smb5_pmi855_params = {
+static struct smb_params smb5_pm855b_params = {
.fcc = {
.name = "fast charge current",
.reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG,
@@ -112,8 +119,15 @@
.max_u = 5000000,
.step_u = 50000,
},
+ .icl_max_stat = {
+ .name = "dcdc icl max status",
+ .reg = ICL_MAX_STATUS_REG,
+ .min_u = 0,
+ .max_u = 5000000,
+ .step_u = 50000,
+ },
.icl_stat = {
- .name = "input current limit status",
+ .name = "aicl icl status",
.reg = AICL_ICL_STATUS_REG,
.min_u = 0,
.max_u = 5000000,
@@ -177,6 +191,11 @@
debug_mask, __debug_mask, int, 0600
);
+static int __pd_disabled;
+module_param_named(
+ pd_disabled, __pd_disabled, int, 0600
+);
+
static int __weak_chg_icl_ua = 500000;
module_param_named(
weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600
@@ -216,7 +235,7 @@
switch (pmic_rev_id->pmic_subtype) {
case PM855B_SUBTYPE:
chip->chg.smb_version = PM855B_SUBTYPE;
- chg->param = smb5_pmi855_params;
+ chg->param = smb5_pm855b_params;
chg->name = "pm855b_charger";
break;
case PMI632_SUBTYPE:
@@ -224,6 +243,8 @@
chg->param = smb5_pmi632_params;
chg->use_extcon = true;
chg->name = "pmi632_charger";
+ /* PMI632 does not support PD */
+ chg->pd_not_supported = true;
chg->hw_max_icl_ua =
(chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua
: PMI632_MAX_ICL_UA;
@@ -434,7 +455,6 @@
POWER_SUPPLY_PROP_TYPEC_MODE,
POWER_SUPPLY_PROP_TYPEC_POWER_ROLE,
POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION,
- POWER_SUPPLY_PROP_PD_ALLOWED,
POWER_SUPPLY_PROP_PD_ACTIVE,
POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED,
POWER_SUPPLY_PROP_INPUT_CURRENT_NOW,
@@ -515,9 +535,6 @@
else
rc = smblib_get_prop_typec_cc_orientation(chg, val);
break;
- case POWER_SUPPLY_PROP_PD_ALLOWED:
- rc = smblib_get_prop_pd_allowed(chg, val);
- break;
case POWER_SUPPLY_PROP_PD_ACTIVE:
val->intval = chg->pd_active;
break;
@@ -605,12 +622,6 @@
struct smb_charger *chg = &chip->chg;
int rc = 0;
- mutex_lock(&chg->lock);
- if (!chg->typec_present) {
- rc = -EINVAL;
- goto unlock;
- }
-
switch (psp) {
case POWER_SUPPLY_PROP_PD_CURRENT_MAX:
rc = smblib_set_prop_pd_current_max(chg, val);
@@ -652,8 +663,6 @@
break;
}
-unlock:
- mutex_unlock(&chg->lock);
return rc;
}
@@ -1077,6 +1086,7 @@
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_RECHARGE_SOC,
};
@@ -1171,6 +1181,9 @@
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
rc = smblib_get_prop_batt_charge_counter(chg, val);
break;
+ case POWER_SUPPLY_PROP_CYCLE_COUNT:
+ rc = smblib_get_prop_batt_cycle_count(chg, val);
+ break;
case POWER_SUPPLY_PROP_RECHARGE_SOC:
val->intval = chg->auto_recharge_soc;
break;
@@ -1424,6 +1437,42 @@
static int smb5_configure_typec(struct smb_charger *chg)
{
int rc;
+ u8 val = 0;
+
+ rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc);
+ return rc;
+ }
+ /*
+ * If Legacy cable is detected re-trigger Legacy detection
+ * by disabling/enabling typeC mode.
+ */
+ if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) {
+ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+ TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc);
+ return rc;
+ }
+
+ /* delay before enabling typeC */
+ msleep(500);
+
+ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+ TYPEC_DISABLE_CMD_BIT, 0);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc);
+ return rc;
+ }
+ }
+
+ /* disable apsd */
+ rc = smblib_configure_hvdcp_apsd(chg, false);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc);
+ return rc;
+ }
rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG,
TYPEC_CCOUT_DETACH_INT_EN_BIT |
@@ -1459,14 +1508,6 @@
{
int rc;
- /* configure micro USB mode */
- rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG,
- EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc);
- return rc;
- }
-
rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG,
MICRO_USB_STATE_CHANGE_INT_EN_BIT,
MICRO_USB_STATE_CHANGE_INT_EN_BIT);
@@ -1500,7 +1541,6 @@
&chg->default_icl_ua);
/* Use SW based VBUS control, disable HW autonomous mode */
- /* TODO: auth can be enabled through vote based on APSD flow */
rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT,
HVDCP_AUTH_ALG_EN_CFG_BIT);
@@ -1537,18 +1577,40 @@
type = !!(val & EN_MICRO_USB_MODE_BIT);
}
- chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB
- : POWER_SUPPLY_CONNECTOR_TYPEC;
pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC");
+ if (type) {
+ chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB;
+ rc = smb5_configure_micro_usb(chg);
+ } else {
+ chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC;
+ rc = smb5_configure_typec(chg);
+ }
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
+ return rc;
+ }
+
/*
* PMI632 based hw init:
+ * - Enable STAT pin function on SMB_EN
+ * - Rerun APSD to ensure proper charger detection if device
+ * boots with charger connected.
* - Initialize flash module for PMI632
*/
- if (chg->smb_version == PMI632_SUBTYPE)
- schgm_flash_init(chg);
+ if (chg->smb_version == PMI632_SUBTYPE) {
+ rc = smblib_masked_write(chg, MISC_SMB_EN_CMD_REG,
+ EN_STAT_CMD_BIT, EN_STAT_CMD_BIT);
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't configure SMB_EN rc=%d\n",
+ rc);
+ return rc;
+ }
- smblib_rerun_apsd_if_required(chg);
+ schgm_flash_init(chg);
+ smblib_rerun_apsd_if_required(chg);
+ }
/* vote 0mA on usb_icl for non battery platforms */
vote(chg->usb_icl_votable,
@@ -1565,12 +1627,6 @@
vote(chg->fv_votable,
BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0,
chg->batt_profile_fv_uv);
- vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER,
- true, 0);
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- true, 0);
- vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER,
- chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0);
/* Some h/w limit maximum supported ICL */
vote(chg->usb_icl_votable, HW_LIMIT_VOTER,
@@ -1578,13 +1634,15 @@
/*
* AICL configuration:
- * start from min and AICL ADC disable
+ * AICL ADC disable
*/
- rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
+ if (chg->smb_version != PMI632_SUBTYPE) {
+ rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG,
USBIN_AICL_ADC_EN_BIT, 0);
- if (rc < 0) {
- dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc);
- return rc;
+ if (rc < 0) {
+ dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc);
+ return rc;
+ }
}
/* enable the charging path */
@@ -1594,16 +1652,6 @@
return rc;
}
- if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
- rc = smb5_configure_micro_usb(chg);
- else
- rc = smb5_configure_typec(chg);
- if (rc < 0) {
- dev_err(chg->dev,
- "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc);
- return rc;
- }
-
/* configure VBUS for software control */
rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0);
if (rc < 0) {
@@ -1812,11 +1860,21 @@
{
struct smb_irq_data irq_data = {chip, "determine-initial-status"};
struct smb_charger *chg = &chip->chg;
+ union power_supply_propval val;
+ int rc;
+
+ rc = smblib_get_prop_usb_present(chg, &val);
+ if (rc < 0) {
+ pr_err("Couldn't get usb present rc=%d\n", rc);
+ return rc;
+ }
+ chg->early_usb_attach = val.intval;
if (chg->bms_psy)
smblib_suspend_on_debug_battery(chg);
usb_plugin_irq_handler(0, &irq_data);
+ typec_attach_detach_irq_handler(0, &irq_data);
typec_state_change_irq_handler(0, &irq_data);
usb_source_change_irq_handler(0, &irq_data);
chg_state_change_irq_handler(0, &irq_data);
@@ -2008,6 +2066,7 @@
},
[TYPEC_ATTACH_DETACH_IRQ] = {
.name = "typec-attach-detach",
+ .handler = typec_attach_detach_irq_handler,
},
[TYPEC_LEGACY_CABLE_DETECT_IRQ] = {
.name = "typec-legacy-cable-detect",
@@ -2303,6 +2362,7 @@
chg = &chip->chg;
chg->dev = &pdev->dev;
chg->debug_mask = &__debug_mask;
+ chg->pd_disabled = &__pd_disabled;
chg->weak_chg_icl_ua = &__weak_chg_icl_ua;
chg->mode = PARALLEL_MASTER;
chg->irq_info = smb5_irqs;
@@ -2452,6 +2512,10 @@
struct smb5 *chip = platform_get_drvdata(pdev);
struct smb_charger *chg = &chip->chg;
+ /* force enable APSD */
+ smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG,
+ BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT);
+
smb5_free_interrupts(chg);
smblib_deinit(chg);
platform_set_drvdata(pdev, NULL);
diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c
index 9b5c25f..3bb4810 100644
--- a/drivers/power/supply/qcom/qpnp-smbcharger.c
+++ b/drivers/power/supply/qcom/qpnp-smbcharger.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-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
@@ -8488,6 +8488,8 @@
out:
handle_usb_removal(chip);
votables_cleanup:
+ if (chip->hvdcp_enable_votable)
+ destroy_votable(chip->hvdcp_enable_votable);
if (chip->aicl_deglitch_short_votable)
destroy_votable(chip->aicl_deglitch_short_votable);
if (chip->hw_aicl_rerun_enable_indirect_votable)
diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c
index 327ae63..1d99ccb 100644
--- a/drivers/power/supply/qcom/smb1355-charger.c
+++ b/drivers/power/supply/qcom/smb1355-charger.c
@@ -108,6 +108,9 @@
#define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43)
#define BARK_BITE_WDOG_PET_BIT BIT(0)
+#define CLOCK_REQUEST_REG (MISC_BASE + 0x44)
+#define CLOCK_REQUEST_CMD_BIT BIT(0)
+
#define WD_CFG_REG (MISC_BASE + 0x51)
#define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7)
#define BARK_WDOG_INT_EN_BIT BIT(6)
@@ -249,6 +252,9 @@
static bool is_secure(struct smb1355 *chip, int addr)
{
+ if (addr == CLOCK_REQUEST_REG)
+ return true;
+
/* assume everything above 0xA0 is secure */
return (addr & 0xFF) >= 0xA0;
}
@@ -265,6 +271,25 @@
return rc;
}
+static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask,
+ u8 val)
+{
+ int rc;
+
+ mutex_lock(&chip->write_lock);
+ if (is_secure(chip, addr)) {
+ rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
+ if (rc < 0)
+ goto unlock;
+ }
+
+ rc = regmap_write_bits(chip->regmap, addr, mask, val);
+
+unlock:
+ mutex_unlock(&chip->write_lock);
+ return rc;
+}
+
static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val)
{
int rc;
@@ -494,6 +519,7 @@
POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED,
POWER_SUPPLY_PROP_MIN_ICL,
POWER_SUPPLY_PROP_CURRENT_MAX,
+ POWER_SUPPLY_PROP_SET_SHIP_MODE,
};
static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip,
@@ -635,6 +661,10 @@
case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX:
val->intval = chip->max_fcc;
break;
+ case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+ /* Not in ship mode as long as device is active */
+ val->intval = 0;
+ break;
default:
pr_err_ratelimited("parallel psy get prop %d not supported\n",
prop);
@@ -726,6 +756,20 @@
return rc;
}
+static int smb1355_clk_request(struct smb1355 *chip, bool enable)
+{
+ int rc;
+
+ rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG,
+ CLOCK_REQUEST_CMD_BIT,
+ enable ? CLOCK_REQUEST_CMD_BIT : 0);
+ if (rc < 0)
+ pr_err("Couldn't %s clock rc=%d\n",
+ enable ? "enable" : "disable", rc);
+
+ return rc;
+}
+
static int smb1355_parallel_set_prop(struct power_supply *psy,
enum power_supply_property prop,
const union power_supply_propval *val)
@@ -752,6 +796,11 @@
chip->c_health = val->intval;
power_supply_changed(chip->parallel_psy);
break;
+ case POWER_SUPPLY_PROP_SET_SHIP_MODE:
+ if (!val->intval)
+ break;
+ rc = smb1355_clk_request(chip, false);
+ break;
default:
pr_debug("parallel power supply set prop %d not supported\n",
prop);
@@ -930,6 +979,11 @@
{
int rc;
+ /* request clock always on */
+ rc = smb1355_clk_request(chip, true);
+ if (rc < 0)
+ return rc;
+
/* enable watchdog bark and bite interrupts, and disable the watchdog */
rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT
| WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT
@@ -1340,6 +1394,8 @@
rc = smb1355_set_parallel_charging(chip, true);
if (rc < 0)
pr_err("Couldn't disable parallel path rc=%d\n", rc);
+
+ smb1355_clk_request(chip, false);
}
static struct platform_driver smb1355_driver = {
diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c
index 8756186..58466b83 100644
--- a/drivers/power/supply/qcom/smb5-lib.c
+++ b/drivers/power/supply/qcom/smb5-lib.c
@@ -39,6 +39,10 @@
__func__, ##__VA_ARGS__); \
} while (0)
+#define typec_rp_med_high(chg, typec_mode) \
+ ((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM \
+ || typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) \
+ && !chg->typec_legacy)
int smblib_read(struct smb_charger *chg, u16 addr, u8 *val)
{
@@ -508,6 +512,23 @@
/********************
* HELPER FUNCTIONS *
********************/
+int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable)
+{
+ int rc;
+ u8 mask = HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT;
+
+ if (chg->pd_not_supported)
+ return 0;
+
+ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, mask,
+ enable ? mask : 0);
+ if (rc < 0)
+ smblib_err(chg, "failed to write USBIN_OPTIONS_1_CFG rc=%d\n",
+ rc);
+
+ return rc;
+}
+
static int smblib_request_dpdm(struct smb_charger *chg, bool enable)
{
int rc = 0;
@@ -654,7 +675,7 @@
return 0;
}
-#define USBIN_100MA 100000
+#define SDP_100_MA 100000
static void smblib_uusb_removal(struct smb_charger *chg)
{
int rc;
@@ -663,10 +684,6 @@
cancel_delayed_work_sync(&chg->pl_enable_work);
- rc = smblib_request_dpdm(chg, false);
- if (rc < 0)
- smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc);
-
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
if (data) {
@@ -683,6 +700,7 @@
/* reset both usbin current and voltage votes */
vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0);
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
/* reconfigure allowed voltage for HVDCP */
@@ -705,8 +723,6 @@
smblib_err(chg, "Couldn't write float charger options rc=%d\n",
rc);
- /* leave the ICL configured to 100mA for next insertion */
- vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA);
/* clear USB ICL vote for USB_PSY_VOTER */
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
if (rc < 0)
@@ -772,6 +788,7 @@
}
#define USBIN_25MA 25000
+#define USBIN_100MA 100000
#define USBIN_150MA 150000
#define USBIN_500MA 500000
#define USBIN_900MA 900000
@@ -885,6 +902,10 @@
set_mode:
rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG,
USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't set USBIN_ICL_OPTIONS rc=%d\n", rc);
+ goto out;
+ }
/* unsuspend after configuring current and override */
rc = smblib_set_usb_suspend(chg, false);
@@ -925,7 +946,8 @@
return INT_MAX;
/* override is set */
- rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua);
+ rc = smblib_get_charge_param(chg, &chg->param.icl_max_stat,
+ icl_ua);
if (rc < 0) {
smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc);
return rc;
@@ -954,18 +976,6 @@
return smblib_set_dc_suspend(chg, (bool)suspend);
}
-static int smblib_pd_disallowed_votable_indirect_callback(
- struct votable *votable, void *data, int disallowed, const char *client)
-{
- struct smb_charger *chg = data;
- int rc;
-
- rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER,
- !disallowed, 0);
-
- return rc;
-}
-
static int smblib_awake_vote_callback(struct votable *votable, void *data,
int awake, const char *client)
{
@@ -1459,6 +1469,19 @@
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 *
***********************/
@@ -1989,13 +2012,6 @@
return rc;
}
-int smblib_get_prop_pd_allowed(struct smb_charger *chg,
- union power_supply_propval *val)
-{
- val->intval = get_effective_result(chg->pd_allowed_votable);
- return 0;
-}
-
int smblib_get_prop_input_current_settled(struct smb_charger *chg,
union power_supply_propval *val)
{
@@ -2039,13 +2055,7 @@
int smblib_get_pe_start(struct smb_charger *chg,
union power_supply_propval *val)
{
- /*
- * hvdcp timeout voter is the last one to allow pd. Use its vote
- * to indicate start of pe engine
- */
- val->intval
- = !get_client_vote_locked(chg->pd_disallowed_votable_indirect,
- APSD_VOTER);
+ val->intval = chg->ok_to_pd;
return 0;
}
@@ -2132,24 +2142,40 @@
if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) {
if (usb_current == -ETIMEDOUT) {
- /*
- * Valid FLOAT charger, report the current based
- * of Rp
- */
+ if ((chg->float_cfg & FLOAT_OPTIONS_MASK)
+ == FORCE_FLOAT_SDP_CFG_BIT) {
+ /*
+ * Confiugure USB500 mode if Float charger is
+ * configured for SDP.
+ */
+ rc = set_sdp_current(chg, USBIN_500MA);
+ if (rc < 0)
+ smblib_err(chg,
+ "Couldn't set SDP ICL rc=%d\n",
+ rc);
+
+ return rc;
+ }
+
if (chg->connector_type ==
POWER_SUPPLY_CONNECTOR_TYPEC) {
+ /*
+ * Valid FLOAT charger, report the current
+ * based of Rp.
+ */
typec_mode = smblib_get_prop_typec_mode(chg);
rp_ua = get_rp_based_dcp_current(chg,
typec_mode);
rc = vote(chg->usb_icl_votable,
- DYNAMIC_RP_VOTER, true, rp_ua);
- if (rc < 0) {
- pr_err("Couldn't vote ICL DYNAMIC_RP_VOTER rc=%d\n",
- rc);
+ SW_ICL_MAX_VOTER, true, rp_ua);
+ if (rc < 0)
return rc;
- }
+ } else {
+ rc = vote(chg->usb_icl_votable,
+ SW_ICL_MAX_VOTER, true, DCP_CURRENT_UA);
+ if (rc < 0)
+ return rc;
}
- /* No specific handling required for micro-USB */
} else {
/*
* FLOAT charger detected as SDP by USB driver,
@@ -2158,12 +2184,13 @@
*/
chg->real_charger_type = POWER_SUPPLY_TYPE_USB;
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
- true, usb_current);
- if (rc < 0) {
- pr_err("Couldn't vote ICL USB_PSY_VOTER rc=%d\n",
- rc);
+ true, usb_current);
+ if (rc < 0)
return rc;
- }
+ rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER,
+ false, 0);
+ if (rc < 0)
+ return rc;
}
} else {
rc = vote(chg->usb_icl_votable, USB_PSY_VOTER,
@@ -2173,12 +2200,12 @@
return rc;
}
- }
+ rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
+ if (rc < 0) {
+ pr_err("Couldn't remove SW_ICL_MAX vote rc=%d\n", rc);
+ return rc;
+ }
- rc = vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
- if (rc < 0) {
- pr_err("Couldn't unvote ICL DEFAULT_100MA_VOTER rc=%d\n", rc);
- return rc;
}
return 0;
@@ -2298,14 +2325,14 @@
return rc;
}
-static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active)
+int smblib_set_prop_pd_active(struct smb_charger *chg,
+ const union power_supply_propval *val)
{
int rc = 0;
- chg->pd_active = pd_active;
+ chg->pd_active = val->intval;
if (chg->pd_active) {
- vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0);
/*
@@ -2313,24 +2340,24 @@
* It is guaranteed that pd_active is set prior to
* pd_current_max
*/
- rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
- if (rc < 0)
- smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n",
- rc);
-
- /* clear USB ICL vote for DCP_VOTER */
- rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n",
- rc);
-
- /* remove USB_PSY_VOTER */
- rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc);
+ vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
} else {
- vote(chg->pd_allowed_votable, PD_VOTER, true, 0);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
+ vote(chg->usb_icl_votable, PD_VOTER, false, 0);
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
+
+ /* PD hard resets failed, rerun apsd */
+ if (chg->ok_to_pd) {
+ chg->ok_to_pd = false;
+ rc = smblib_configure_hvdcp_apsd(chg, true);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't enable APSD rc=%d\n", rc);
+ return rc;
+ }
+ smblib_rerun_apsd_if_required(chg);
+ }
}
smblib_update_usb_type(chg);
@@ -2338,15 +2365,6 @@
return rc;
}
-int smblib_set_prop_pd_active(struct smb_charger *chg,
- const union power_supply_propval *val)
-{
- if (!get_effective_result(chg->pd_allowed_votable))
- return -EINVAL;
-
- return __smblib_set_prop_pd_active(chg, val->intval);
-}
-
int smblib_set_prop_ship_mode(struct smb_charger *chg,
const union power_supply_propval *val)
{
@@ -2657,11 +2675,7 @@
static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising)
{
- if (vbus_rising) {
- /* use the typec flag even though its not typec */
- chg->typec_present = 1;
- } else {
- chg->typec_present = 0;
+ if (!vbus_rising) {
smblib_update_usb_type(chg);
smblib_notify_device_mode(chg, false);
smblib_uusb_removal(chg);
@@ -2764,12 +2778,10 @@
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
- mutex_lock(&chg->lock);
if (chg->pd_hard_reset)
smblib_usb_plugin_hard_reset_locked(chg);
else
smblib_usb_plugin_locked(chg);
- mutex_unlock(&chg->lock);
return IRQ_HANDLED;
}
@@ -2858,8 +2870,6 @@
if (!rising)
return;
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
-
if (chg->mode == PARALLEL_MASTER)
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0);
@@ -2872,33 +2882,18 @@
static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg,
bool rising, bool qc_charger)
{
- const struct apsd_result *apsd_result = smblib_get_apsd_result(chg);
-
- /* Hold off PD only until hvdcp 2.0 detection timeout */
if (rising) {
- /* enable HDC and ICL irq for QC2/3 charger */
- if (qc_charger)
+ if (qc_charger) {
+ /* enable HDC and ICL irq for QC2/3 charger */
vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0);
- else
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- false, 0);
-
- /*
- * HVDCP detection timeout done
- * If adapter is not QC2.0/QC3.0 - it is a plain old DCP.
- */
- if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT))
- /* enforce DCP ICL if specified */
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+ HVDCP_CURRENT_UA);
+ } else {
+ /* A plain DCP, enforce DCP ICL if specified */
vote(chg->usb_icl_votable, DCP_VOTER,
chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua);
-
- /*
- * if pd is not allowed, then set pd_active = false right here,
- * so that it starts the hvdcp engine
- */
- if (!get_effective_result(chg->pd_allowed_votable))
- __smblib_set_prop_pd_active(chg, 0);
+ }
}
smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__,
@@ -2913,6 +2908,69 @@
rising ? "rising" : "falling");
}
+static void update_sw_icl_max(struct smb_charger *chg, int pst)
+{
+ int typec_mode;
+ int rp_ua;
+
+ /* while PD is active it should have complete ICL control */
+ if (chg->pd_active)
+ return;
+
+ /*
+ * HVDCP 2/3, handled separately
+ * For UNKNOWN(input not present) return without updating ICL
+ */
+ if (pst == POWER_SUPPLY_TYPE_USB_HVDCP
+ || pst == POWER_SUPPLY_TYPE_USB_HVDCP_3
+ || pst == POWER_SUPPLY_TYPE_UNKNOWN)
+ return;
+
+ /* TypeC rp med or high, use rp value */
+ typec_mode = smblib_get_prop_typec_mode(chg);
+ if (typec_rp_med_high(chg, typec_mode)) {
+ rp_ua = get_rp_based_dcp_current(chg, typec_mode);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua);
+ return;
+ }
+
+ /* rp-std or legacy, USB BC 1.2 */
+ switch (pst) {
+ case POWER_SUPPLY_TYPE_USB:
+ /*
+ * USB_PSY will vote to increase the current to 500/900mA once
+ * enumeration is done.
+ */
+ if (!is_client_vote_enabled(chg->usb_icl_votable,
+ USB_PSY_VOTER))
+ vote(chg->usb_icl_votable, USB_PSY_VOTER, true,
+ SDP_100_MA);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0);
+ break;
+ case POWER_SUPPLY_TYPE_USB_CDP:
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+ CDP_CURRENT_UA);
+ break;
+ case POWER_SUPPLY_TYPE_USB_DCP:
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+ DCP_CURRENT_UA);
+ break;
+ case POWER_SUPPLY_TYPE_USB_FLOAT:
+ /*
+ * limit ICL to 100mA, the USB driver will enumerate to check
+ * if this is a SDP and appropriately set the current
+ */
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+ SDP_100_MA);
+ break;
+ default:
+ smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true,
+ SDP_CURRENT_UA);
+ break;
+ }
+}
+
static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising)
{
const struct apsd_result *apsd_result;
@@ -2922,25 +2980,18 @@
apsd_result = smblib_update_usb_type(chg);
+ update_sw_icl_max(chg, apsd_result->pst);
+
switch (apsd_result->bit) {
case SDP_CHARGER_BIT:
case CDP_CHARGER_BIT:
case FLOAT_CHARGER_BIT:
- /* if not DCP then no hvdcp timeout happens. Enable pd here */
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- false, 0);
if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
|| chg->use_extcon)
smblib_notify_device_mode(chg, true);
break;
case OCP_CHARGER_BIT:
- vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
- /* if not DCP then no hvdcp timeout happens, Enable pd here. */
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER,
- false, 0);
- break;
case DCP_CHARGER_BIT:
- vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0);
break;
default:
break;
@@ -2957,6 +3008,14 @@
int rc = 0;
u8 stat;
+ /*
+ * Prepared to run PD or PD is active. At this moment, APSD is disabled,
+ * but there still can be irq on apsd_done from previously unfinished
+ * APSD run, skip it.
+ */
+ if (chg->ok_to_pd)
+ return IRQ_HANDLED;
+
rc = smblib_read(chg, APSD_STATUS_REG, &stat);
if (rc < 0) {
smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc);
@@ -2972,7 +3031,7 @@
* charger-mis-detection.
*/
chg->uusb_apsd_rerun_done = true;
- smblib_rerun_apsd(chg);
+ smblib_rerun_apsd_if_required(chg);
return IRQ_HANDLED;
}
@@ -3011,32 +3070,70 @@
static void typec_sink_insertion(struct smb_charger *chg)
{
- /* when a sink is inserted we should not wait on hvdcp timeout to
- * enable pd
- */
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0);
+ vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
+
if (chg->use_extcon) {
smblib_notify_usb_host(chg, true);
chg->otg_present = true;
}
+
+ if (!chg->pr_swap_in_progress)
+ chg->ok_to_pd = (!(*chg->pd_disabled) || chg->early_usb_attach)
+ && !chg->pd_not_supported;
+}
+
+static void typec_src_insertion(struct smb_charger *chg)
+{
+ int rc = 0;
+ u8 stat;
+
+ if (chg->pr_swap_in_progress)
+ return;
+
+ rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
+ rc);
+ return;
+ }
+
+ chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT;
+ chg->ok_to_pd = (!(chg->typec_legacy || *chg->pd_disabled)
+ || chg->early_usb_attach) && !chg->pd_not_supported;
+ if (!chg->ok_to_pd) {
+ rc = smblib_configure_hvdcp_apsd(chg, true);
+ if (rc < 0) {
+ dev_err(chg->dev,
+ "Couldn't enable APSD rc=%d\n", rc);
+ return;
+ }
+ smblib_rerun_apsd_if_required(chg);
+ }
}
static void typec_sink_removal(struct smb_charger *chg)
{
- smblib_set_charge_param(chg, &chg->param.freq_switcher,
- chg->chg_freq.freq_above_otg_threshold);
- chg->boost_current_ua = 0;
+ vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
+
+ if (chg->use_extcon) {
+ if (chg->otg_present)
+ smblib_notify_usb_host(chg, false);
+ chg->otg_present = false;
+ }
}
-static void smblib_handle_typec_removal(struct smb_charger *chg)
+static void typec_src_removal(struct smb_charger *chg)
{
int rc;
struct smb_irq_data *data;
struct storm_watch *wdata;
- rc = smblib_request_dpdm(chg, false);
+ /* disable apsd */
+ rc = smblib_configure_hvdcp_apsd(chg, false);
if (rc < 0)
- smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc);
+ smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc);
+
+ smblib_update_usb_type(chg);
if (chg->wa_flags & BOOST_BACK_WA) {
data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data;
@@ -3052,7 +3149,7 @@
cancel_delayed_work_sync(&chg->pl_enable_work);
/* reset input current limit voters */
- vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA);
+ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA);
vote(chg->usb_icl_votable, PD_VOTER, false, 0);
vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0);
vote(chg->usb_icl_votable, DCP_VOTER, false, 0);
@@ -3060,12 +3157,6 @@
vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0);
vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
vote(chg->usb_icl_votable, CTM_VOTER, false, 0);
- vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0);
-
- /* reset power delivery voters */
- vote(chg->pd_allowed_votable, PD_VOTER, false, 0);
- vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0);
- vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0);
/* reset usb irq voters */
vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0);
@@ -3078,14 +3169,10 @@
vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0);
vote(chg->awake_votable, PL_DELAY_VOTER, false, 0);
- chg->vconn_attempts = 0;
- chg->otg_attempts = 0;
chg->pulse_cnt = 0;
chg->usb_icl_delta_ua = 0;
chg->voltage_min_uv = MICRO_5V;
chg->voltage_max_uv = MICRO_5V;
- chg->pd_active = 0;
- chg->pd_hard_reset = 0;
/* write back the default FLOAT charger configuration */
rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG,
@@ -3094,12 +3181,6 @@
smblib_err(chg, "Couldn't write float charger options rc=%d\n",
rc);
- /* reset back to 103mS tCC debounce */
- rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
- REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc);
-
/* reconfigure allowed voltage for HVDCP */
rc = smblib_set_adapter_allowance(chg,
USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V);
@@ -3107,157 +3188,35 @@
smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n",
rc);
- /* enable DRP */
- rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
- TYPEC_POWER_ROLE_CMD_MASK, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+ if (chg->use_extcon)
+ smblib_notify_device_mode(chg, false);
- /* HW controlled CC_OUT */
- rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
- TYPEC_CCOUT_SRC_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc);
-
- /* clear exit sink based on cc */
- rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
- EXIT_SNK_BASED_ON_CC_BIT, 0);
- if (rc < 0)
- smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n",
- rc);
-
- typec_sink_removal(chg);
- smblib_update_usb_type(chg);
-
- if (chg->use_extcon) {
- if (chg->otg_present)
- smblib_notify_usb_host(chg, false);
- else
- smblib_notify_device_mode(chg, false);
- }
- chg->otg_present = false;
-}
-
-static void smblib_handle_typec_insertion(struct smb_charger *chg)
-{
- int rc;
- u8 stat;
-
- vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0);
-
- rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return;
- }
-
- if (stat & SNK_SRC_MODE_BIT) {
- typec_sink_insertion(chg);
- } else {
- rc = smblib_request_dpdm(chg, true);
- if (rc < 0)
- smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc);
- typec_sink_removal(chg);
- }
+ chg->typec_legacy = false;
}
static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode)
{
- int rp_ua;
const struct apsd_result *apsd = smblib_get_apsd_result(chg);
- if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP)
- && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT))
- return;
-
- /*
- * if APSD indicates FLOAT and the USB stack had detected SDP,
- * do not respond to Rp changes as we do not confirm that its
- * a legacy cable
- */
- if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)
- return;
/*
* We want the ICL vote @ 100mA for a FLOAT charger
* until the detection by the USB stack is complete.
* Ignore the Rp changes unless there is a
- * pre-existing valid vote.
+ * pre-existing valid vote or FLOAT is configured for
+ * SDP current.
*/
- if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT &&
- (get_client_vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER)
- <= USBIN_100MA))
+ if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT) {
+ if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER)
+ <= USBIN_100MA
+ || (chg->float_cfg & FLOAT_OPTIONS_MASK)
+ == FORCE_FLOAT_SDP_CFG_BIT)
return;
+ }
- /*
- * handle Rp change for DCP/FLOAT/OCP.
- * Update the current only if the Rp is different from
- * the last Rp value.
- */
+ update_sw_icl_max(chg, apsd->pst);
+
smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n",
chg->typec_mode, typec_mode);
-
- rp_ua = get_rp_based_dcp_current(chg, typec_mode);
- vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua);
-}
-
-static void smblib_handle_typec_cc_state_change(struct smb_charger *chg)
-{
- u8 stat;
- int typec_mode, rc;
-
- if (chg->pr_swap_in_progress)
- return;
-
- typec_mode = smblib_get_prop_typec_mode(chg);
- if (chg->typec_present && (typec_mode != chg->typec_mode))
- smblib_handle_rp_change(chg, typec_mode);
-
- chg->typec_mode = typec_mode;
-
- if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) {
- chg->typec_present = true;
- smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n",
- smblib_typec_mode_name[chg->typec_mode]);
- smblib_handle_typec_insertion(chg);
- } else if (chg->typec_present &&
- chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) {
- chg->typec_present = false;
- smblib_dbg(chg, PR_MISC, "TypeC removal\n");
- smblib_handle_typec_removal(chg);
- }
-
- rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return;
- }
- /* suspend usb if sink */
- if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present)
- vote(chg->usb_icl_votable, OTG_VOTER, true, 0);
- else
- vote(chg->usb_icl_votable, OTG_VOTER, false, 0);
-
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
- smblib_typec_mode_name[chg->typec_mode]);
-}
-
-static void smblib_usb_typec_change(struct smb_charger *chg)
-{
- int rc;
- u8 stat;
-
- smblib_handle_typec_cc_state_change(chg);
-
- rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
- if (rc < 0) {
- smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc);
- return;
- }
-
- if (stat & TYPEC_VBUS_ERROR_STATUS_BIT)
- smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n");
-
- power_supply_changed(chg->usb_psy);
}
irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data)
@@ -3281,17 +3240,81 @@
{
struct smb_irq_data *irq_data = data;
struct smb_charger *chg = irq_data->parent_data;
+ int typec_mode;
- if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)
- || chg->pr_swap_in_progress) {
+ if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) {
smblib_dbg(chg, PR_INTERRUPT,
- "Ignoring since pr_swap_in_progress\n");
+ "Ignoring for micro USB\n");
return IRQ_HANDLED;
}
- mutex_lock(&chg->lock);
- smblib_usb_typec_change(chg);
- mutex_unlock(&chg->lock);
+ typec_mode = smblib_get_prop_typec_mode(chg);
+ if (chg->sink_src_mode != UNATTACHED_MODE
+ && (typec_mode != chg->typec_mode))
+ smblib_handle_rp_change(chg, typec_mode);
+ chg->typec_mode = typec_mode;
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n",
+ smblib_typec_mode_name[chg->typec_mode]);
+
+ power_supply_changed(chg->usb_psy);
+
+ return IRQ_HANDLED;
+}
+
+irqreturn_t typec_attach_detach_irq_handler(int irq, void *data)
+{
+ struct smb_irq_data *irq_data = data;
+ struct smb_charger *chg = irq_data->parent_data;
+ u8 stat;
+ int rc;
+
+ smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name);
+
+ rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
+
+ if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) {
+ rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n",
+ rc);
+ return IRQ_HANDLED;
+ }
+
+ if (stat & SNK_SRC_MODE_BIT) {
+ chg->sink_src_mode = SRC_MODE;
+ typec_sink_insertion(chg);
+ } else {
+ chg->sink_src_mode = SINK_MODE;
+ typec_src_insertion(chg);
+ }
+
+ } else {
+ switch (chg->sink_src_mode) {
+ case SRC_MODE:
+ typec_sink_removal(chg);
+ break;
+ case SINK_MODE:
+ typec_src_removal(chg);
+ break;
+ default:
+ break;
+ }
+
+ if (!chg->pr_swap_in_progress) {
+ chg->ok_to_pd = false;
+ chg->sink_src_mode = UNATTACHED_MODE;
+ chg->early_usb_attach = false;
+ }
+ }
+
+ power_supply_changed(chg->usb_psy);
+
return IRQ_HANDLED;
}
@@ -3426,19 +3449,55 @@
const union power_supply_propval *val)
{
int rc;
+ u8 stat = 0, orientation;
chg->pr_swap_in_progress = val->intval;
- /*
- * call the cc changed irq to handle real removals while
- * PR_SWAP was in progress
- */
- smblib_usb_typec_change(chg);
rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG,
REDUCE_TCCDEBOUNCE_TO_2MS_BIT,
val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0);
if (rc < 0)
smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc);
+
+ rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG,
+ BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT,
+ val->intval ? BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT : 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't set exit state cfg rc=%d\n", rc);
+
+ if (chg->pr_swap_in_progress) {
+ rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n",
+ rc);
+ }
+
+ orientation =
+ stat & CC_ORIENTATION_BIT ? TYPEC_CCOUT_VALUE_BIT : 0;
+ rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
+ TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT
+ | TYPEC_CCOUT_VALUE_BIT,
+ TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT
+ | orientation);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n",
+ rc);
+ }
+ } else {
+ rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG,
+ TYPEC_CCOUT_SRC_BIT, 0);
+ if (rc < 0) {
+ smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n",
+ rc);
+ }
+
+ /* enable DRP */
+ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG,
+ TYPEC_POWER_ROLE_CMD_MASK, 0);
+ if (rc < 0)
+ smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc);
+ }
+
return 0;
}
@@ -3461,6 +3520,9 @@
otg = !!(stat & U_USB_GROUND_NOVBUS_BIT);
if (chg->otg_present != otg)
smblib_notify_usb_host(chg, otg);
+ else
+ goto out;
+
chg->otg_present = otg;
if (!otg)
chg->boost_current_ua = 0;
@@ -3681,23 +3743,6 @@
return rc;
}
- chg->pd_disallowed_votable_indirect
- = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY,
- smblib_pd_disallowed_votable_indirect_callback, chg);
- if (IS_ERR(chg->pd_disallowed_votable_indirect)) {
- rc = PTR_ERR(chg->pd_disallowed_votable_indirect);
- chg->pd_disallowed_votable_indirect = NULL;
- return rc;
- }
-
- chg->pd_allowed_votable = create_votable("PD_ALLOWED",
- VOTE_SET_ANY, NULL, NULL);
- if (IS_ERR(chg->pd_allowed_votable)) {
- rc = PTR_ERR(chg->pd_allowed_votable);
- chg->pd_allowed_votable = NULL;
- return rc;
- }
-
chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY,
smblib_awake_vote_callback,
chg);
@@ -3735,10 +3780,6 @@
destroy_votable(chg->dc_suspend_votable);
if (chg->usb_icl_votable)
destroy_votable(chg->usb_icl_votable);
- if (chg->pd_disallowed_votable_indirect)
- destroy_votable(chg->pd_disallowed_votable_indirect);
- if (chg->pd_allowed_votable)
- destroy_votable(chg->pd_allowed_votable);
if (chg->awake_votable)
destroy_votable(chg->awake_votable);
if (chg->chg_disable_votable)
@@ -3750,7 +3791,6 @@
int rc = 0;
mutex_init(&chg->lock);
- mutex_init(&chg->otg_oc_lock);
INIT_WORK(&chg->bms_update_work, bms_update_work);
INIT_WORK(&chg->pl_update_work, pl_update_work);
INIT_WORK(&chg->jeita_update_work, jeita_update_work);
@@ -3763,6 +3803,7 @@
chg->fake_input_current_limited = -EINVAL;
chg->fake_batt_status = -EINVAL;
chg->jeita_configured = false;
+ chg->sink_src_mode = UNATTACHED_MODE;
switch (chg->mode) {
case PARALLEL_MASTER:
diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h
index 5d6d3a6..57281cc7 100644
--- a/drivers/power/supply/qcom/smb5-lib.h
+++ b/drivers/power/supply/qcom/smb5-lib.h
@@ -56,6 +56,7 @@
#define CTM_VOTER "CTM_VOTER"
#define SW_QC3_VOTER "SW_QC3_VOTER"
#define AICL_RERUN_VOTER "AICL_RERUN_VOTER"
+#define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER"
#define QNOVO_VOTER "QNOVO_VOTER"
#define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER"
#define OTG_DELAY_VOTER "OTG_DELAY_VOTER"
@@ -65,8 +66,6 @@
#define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER"
#define WBC_VOTER "WBC_VOTER"
#define HW_LIMIT_VOTER "HW_LIMIT_VOTER"
-#define DYNAMIC_RP_VOTER "DYNAMIC_RP_VOTER"
-#define DEFAULT_100MA_VOTER "DEFAULT_100MA_VOTER"
#define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER"
#define BOOST_BACK_STORM_COUNT 3
@@ -80,6 +79,12 @@
NUM_MODES,
};
+enum sink_src_mode {
+ SINK_MODE,
+ SRC_MODE,
+ UNATTACHED_MODE,
+};
+
enum {
BOOST_BACK_WA = BIT(0),
};
@@ -228,6 +233,7 @@
struct smb_chg_param fcc;
struct smb_chg_param fv;
struct smb_chg_param usb_icl;
+ struct smb_chg_param icl_max_stat;
struct smb_chg_param icl_stat;
struct smb_chg_param otg_cl;
struct smb_chg_param jeita_cc_comp_hot;
@@ -259,17 +265,18 @@
struct smb_params param;
struct smb_iio iio;
int *debug_mask;
+ int *pd_disabled;
enum smb_mode mode;
struct smb_chg_freq chg_freq;
int smb_version;
int otg_delay_ms;
int *weak_chg_icl_ua;
struct qpnp_vadc_chip *vadc_dev;
+ bool pd_not_supported;
/* locks */
struct mutex lock;
struct mutex ps_change_lock;
- struct mutex otg_oc_lock;
/* power supplies */
struct power_supply *batt_psy;
@@ -296,8 +303,6 @@
struct votable *fcc_votable;
struct votable *fv_votable;
struct votable *usb_icl_votable;
- struct votable *pd_disallowed_votable_indirect;
- struct votable *pd_allowed_votable;
struct votable *awake_votable;
struct votable *pl_disable_votable;
struct votable *chg_disable_votable;
@@ -315,10 +320,17 @@
struct delayed_work uusb_otg_work;
struct delayed_work bb_removal_work;
- /* cached status */
+ /* pd */
int voltage_min_uv;
int voltage_max_uv;
int pd_active;
+ bool pd_hard_reset;
+ bool pr_swap_in_progress;
+ bool early_usb_attach;
+ bool ok_to_pd;
+ bool typec_legacy;
+
+ /* cached status */
bool system_suspend_supported;
int boost_threshold_ua;
int system_temp_level;
@@ -334,15 +346,10 @@
int connector_type;
bool otg_en;
bool suspend_input_on_debug_batt;
- int otg_attempts;
- int vconn_attempts;
int default_icl_ua;
int otg_cl_ua;
bool uusb_apsd_rerun_done;
- bool pd_hard_reset;
- bool typec_present;
int fake_input_current_limited;
- bool pr_swap_in_progress;
int typec_mode;
int usb_icl_change_irq_enabled;
u32 jeita_status;
@@ -352,6 +359,7 @@
int hw_max_icl_ua;
int auto_recharge_soc;
bool jeita_configured;
+ enum sink_src_mode sink_src_mode;
/* workaround flag */
u32 wa_flags;
@@ -420,6 +428,7 @@
irqreturn_t usb_source_change_irq_handler(int irq, void *data);
irqreturn_t icl_change_irq_handler(int irq, void *data);
irqreturn_t typec_state_change_irq_handler(int irq, void *data);
+irqreturn_t typec_attach_detach_irq_handler(int irq, void *data);
irqreturn_t dc_plugin_irq_handler(int irq, void *data);
irqreturn_t high_duty_cycle_irq_handler(int irq, void *data);
irqreturn_t switcher_power_ok_irq_handler(int irq, void *data);
@@ -454,6 +463,8 @@
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,
@@ -485,8 +496,6 @@
union power_supply_propval *val);
int smblib_get_prop_typec_power_role(struct smb_charger *chg,
union power_supply_propval *val);
-int smblib_get_prop_pd_allowed(struct smb_charger *chg,
- union power_supply_propval *val);
int smblib_get_prop_input_current_settled(struct smb_charger *chg,
union power_supply_propval *val);
int smblib_get_prop_input_voltage_settled(struct smb_charger *chg,
@@ -530,6 +539,7 @@
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);
+int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable);
int smblib_init(struct smb_charger *chg);
int smblib_deinit(struct smb_charger *chg);
diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h
index e199087..79a8bd0 100644
--- a/drivers/power/supply/qcom/smb5-reg.h
+++ b/drivers/power/supply/qcom/smb5-reg.h
@@ -105,6 +105,8 @@
/********************************
* DCDC Peripheral Registers *
********************************/
+#define ICL_MAX_STATUS_REG (DCDC_BASE + 0x06)
+
#define AICL_ICL_STATUS_REG (DCDC_BASE + 0x08)
#define AICL_STATUS_REG (DCDC_BASE + 0x0A)
@@ -215,6 +217,7 @@
#define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6)
#define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5)
#define BC1P2_SRC_DETECT_BIT BIT(3)
+#define HVDCP_EN_BIT BIT(2)
#define USBIN_OPTIONS_2_CFG_REG (USBIN_BASE + 0x63)
#define FLOAT_OPTIONS_MASK GENMASK(2, 0)
@@ -262,6 +265,9 @@
#define SRC_RA_OPEN_BIT BIT(1)
#define AUDIO_ACCESS_RA_RA_BIT BIT(0)
+#define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09)
+#define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5)
+
#define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B)
#define SNK_SRC_MODE_BIT BIT(6)
#define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4)
@@ -269,6 +275,7 @@
#define CC_ATTACHED_BIT BIT(0)
#define LEGACY_CABLE_STATUS_REG (TYPEC_BASE + 0x0D)
+#define TYPEC_LEGACY_CABLE_STATUS_BIT BIT(1)
#define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT BIT(0)
#define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F)
@@ -276,7 +283,7 @@
#define U_USB_GROUND_BIT BIT(4)
#define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44)
-#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0)
+#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 1)
#define EN_SRC_ONLY_BIT BIT(2)
#define EN_SNK_ONLY_BIT BIT(1)
#define TYPEC_DISABLE_CMD_BIT BIT(0)
@@ -287,10 +294,12 @@
#define VCONN_EN_SRC_BIT BIT(0)
#define TYPE_C_CCOUT_CONTROL_REG (TYPEC_BASE + 0x48)
+#define TYPEC_CCOUT_BUFFER_EN_BIT BIT(2)
#define TYPEC_CCOUT_VALUE_BIT BIT(1)
#define TYPEC_CCOUT_SRC_BIT BIT(0)
#define TYPE_C_EXIT_STATE_CFG_REG (TYPEC_BASE + 0x50)
+#define BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT BIT(3)
#define EXIT_SNK_BASED_ON_CC_BIT BIT(0)
#define TYPE_C_INTERRUPT_EN_CFG_1_REG (TYPEC_BASE + 0x5E)
@@ -318,7 +327,7 @@
#define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70)
#define EN_MICRO_USB_MODE_BIT BIT(0)
-#define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x70)
+#define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73)
#define MICRO_USB_MODE_ONLY_BIT BIT(0)
/********************************
* MISC Peripheral Registers *
diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c
index 14bde0d..5b10b50 100644
--- a/drivers/powercap/powercap_sys.c
+++ b/drivers/powercap/powercap_sys.c
@@ -538,6 +538,7 @@
power_zone->id = result;
idr_init(&power_zone->idr);
+ result = -ENOMEM;
power_zone->name = kstrdup(name, GFP_KERNEL);
if (!power_zone->name)
goto err_name_alloc;
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
index 1c85ecc..0fcf94f 100644
--- a/drivers/pwm/pwm-rcar.c
+++ b/drivers/pwm/pwm-rcar.c
@@ -156,8 +156,12 @@
if (div < 0)
return div;
- /* Let the core driver set pwm->period if disabled and duty_ns == 0 */
- if (!pwm_is_enabled(pwm) && !duty_ns)
+ /*
+ * Let the core driver set pwm->period if disabled and duty_ns == 0.
+ * But, this driver should prevent to set the new duty_ns if current
+ * duty_cycle is not set
+ */
+ if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle)
return 0;
rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c
index 9510016..2eff0cf 100644
--- a/drivers/regulator/cpr3-regulator.c
+++ b/drivers/regulator/cpr3-regulator.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -178,6 +178,7 @@
#define CPR4_REG_MISC 0x700
#define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN BIT(2)
+#define CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN BIT(3)
#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK GENMASK(23, 20)
#define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT 20
#define CPR4_MISC_TEMP_SENSOR_ID_START_MASK GENMASK(27, 24)
@@ -733,6 +734,11 @@
CPR4_MISC_RESET_STEP_QUOT_LOOP_EN,
CPR4_MISC_RESET_STEP_QUOT_LOOP_EN);
+ if (ctrl->thread_has_always_vote_en)
+ cpr3_masked_write(ctrl, CPR4_REG_MISC,
+ CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN,
+ CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN);
+
if (ctrl->supports_hw_closed_loop) {
if (ctrl->saw_use_unit_mV)
pmic_step_size = ctrl->step_volt / 1000;
diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h
index 778f482..39d3f82 100644
--- a/drivers/regulator/cpr3-regulator.h
+++ b/drivers/regulator/cpr3-regulator.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -766,6 +766,12 @@
* the CPR controller to first use the default step_quot
* and then later switch to the run-time calibrated
* step_quot.
+ * @thread_has_always_vote_en: Boolean value which indicates that this CPR
+ * controller should be configured to keep thread vote
+ * always enabled. This configuration allows the CPR
+ * controller to not consider MID/DN recommendations from
+ * other thread when all sensors mapped to a thread
+ * collapsed.
*
* This structure contains both configuration and runtime state data. The
* elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled,
@@ -879,6 +885,7 @@
struct notifier_block panic_notifier;
bool support_ldo300_vreg;
bool reset_step_quot_loop_en;
+ bool thread_has_always_vote_en;
};
/* Used for rounding voltages to the closest physically available set point. */
diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c
index 39ee3c5..9e138ce 100644
--- a/drivers/regulator/cpr3-util.c
+++ b/drivers/regulator/cpr3-util.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+ * 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
@@ -1241,6 +1241,16 @@
"qcom,cpr-reset-step-quot-loop-en");
/*
+ * Configure CPR controller to not consider MID/DN recommendations
+ * from other thread when all sensors mapped to a thread collapsed
+ * in a multi-thread configuration.
+ */
+ if (ctrl->thread_count > 1)
+ ctrl->thread_has_always_vote_en
+ = of_property_read_bool(ctrl->dev->of_node,
+ "qcom,cpr-thread-has-always-vote-en");
+
+ /*
* Regulator device handles are not necessary for CPRh controllers
* since communication with the regulators is completely managed
* in hardware.
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 99b5e35..162afcc 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -227,6 +227,13 @@
missing = year;
}
+ /* Can't proceed if alarm is still invalid after replacing
+ * missing fields.
+ */
+ err = rtc_valid_tm(&alarm->time);
+ if (err)
+ goto done;
+
/* with luck, no rollover is needed */
t_now = rtc_tm_to_time64(&now);
t_alm = rtc_tm_to_time64(&alarm->time);
@@ -278,9 +285,9 @@
dev_warn(&rtc->dev, "alarm rollover not handled\n");
}
-done:
err = rtc_valid_tm(&alarm->time);
+done:
if (err) {
dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 58698d2..c4ca6a3 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -168,6 +168,7 @@
/* Sets the given date and time to the real time clock. */
static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
+ struct m41t80_data *clientdata = i2c_get_clientdata(client);
unsigned char buf[8];
int err, flags;
@@ -183,6 +184,17 @@
buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
buf[M41T80_REG_WDAY] = tm->tm_wday;
+ /* If the square wave output is controlled in the weekday register */
+ if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
+ int val;
+
+ val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
+ if (val < 0)
+ return val;
+
+ buf[M41T80_REG_WDAY] |= (val & 0xf0);
+ }
+
err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
sizeof(buf), buf);
if (err < 0) {
diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c
index e4324dc..aa53fce 100644
--- a/drivers/rtc/rtc-opal.c
+++ b/drivers/rtc/rtc-opal.c
@@ -150,6 +150,16 @@
y_m_d = be32_to_cpu(__y_m_d);
h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
+
+ /* check if no alarm is set */
+ if (y_m_d == 0 && h_m_s_ms == 0) {
+ pr_debug("No alarm is set\n");
+ rc = -ENOENT;
+ goto exit;
+ } else {
+ pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+ }
+
opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
exit:
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index 0f11c2a..a753ef9 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -257,7 +257,7 @@
of_property_read_u32(pdev->dev.of_node, "offset", &data->offset);
}
- if (!data->regmap) {
+ if (IS_ERR(data->regmap)) {
dev_err(&pdev->dev, "Can't find snvs syscon\n");
return -ENODEV;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 5ecd408..0da2465 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -1950,8 +1950,12 @@
{
int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM);
- if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) {
- /* dasd is being set offline. */
+ if (test_bit(DASD_FLAG_OFFLINE, &device->flags) &&
+ !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) {
+ /*
+ * dasd is being set offline
+ * but it is no safe offline where we have to allow I/O
+ */
return 1;
}
if (device->stopped) {
diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c
index 71bf9bd..66e9bb0 100644
--- a/drivers/s390/cio/qdio_main.c
+++ b/drivers/s390/cio/qdio_main.c
@@ -126,7 +126,7 @@
static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
int start, int count, int auto_ack)
{
- int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0;
+ int rc, tmp_count = count, tmp_start = start, nr = q->nr;
unsigned int ccq = 0;
qperf_inc(q, eqbs);
@@ -149,14 +149,7 @@
qperf_inc(q, eqbs_partial);
DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x",
tmp_count);
- /*
- * Retry once, if that fails bail out and process the
- * extracted buffers before trying again.
- */
- if (!retried++)
- goto again;
- else
- return count - tmp_count;
+ return count - tmp_count;
}
DBF_ERROR("%4x EQBS ERROR", SCH_NO(q));
@@ -212,7 +205,10 @@
return 0;
}
-/* returns number of examined buffers and their common state in *state */
+/*
+ * Returns number of examined buffers and their common state in *state.
+ * Requested number of buffers-to-examine must be > 0.
+ */
static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr,
unsigned char *state, unsigned int count,
int auto_ack, int merge_pending)
@@ -223,17 +219,23 @@
if (is_qebsm(q))
return qdio_do_eqbs(q, state, bufnr, count, auto_ack);
- for (i = 0; i < count; i++) {
- if (!__state) {
- __state = q->slsb.val[bufnr];
- if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
- __state = SLSB_P_OUTPUT_EMPTY;
- } else if (merge_pending) {
- if ((q->slsb.val[bufnr] & __state) != __state)
- break;
- } else if (q->slsb.val[bufnr] != __state)
- break;
+ /* get initial state: */
+ __state = q->slsb.val[bufnr];
+ if (merge_pending && __state == SLSB_P_OUTPUT_PENDING)
+ __state = SLSB_P_OUTPUT_EMPTY;
+
+ for (i = 1; i < count; i++) {
bufnr = next_buf(bufnr);
+
+ /* merge PENDING into EMPTY: */
+ if (merge_pending &&
+ q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING &&
+ __state == SLSB_P_OUTPUT_EMPTY)
+ continue;
+
+ /* stop if next state differs from initial state: */
+ if (q->slsb.val[bufnr] != __state)
+ break;
}
*state = __state;
return i;
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index fdd4eb4..e58786f 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -191,6 +191,7 @@
struct bnx2fc_cmd_mgr *cmd_mgr;
spinlock_t hba_lock;
struct mutex hba_mutex;
+ struct mutex hba_stats_mutex;
unsigned long adapter_state;
#define ADAPTER_STATE_UP 0
#define ADAPTER_STATE_GOING_DOWN 1
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index f9ddb61..bee7d37 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -670,15 +670,17 @@
if (!fw_stats)
return NULL;
+ mutex_lock(&hba->hba_stats_mutex);
+
bnx2fc_stats = fc_get_host_stats(shost);
init_completion(&hba->stat_req_done);
if (bnx2fc_send_stat_req(hba))
- return bnx2fc_stats;
+ goto unlock_stats_mutex;
rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ));
if (!rc) {
BNX2FC_HBA_DBG(lport, "FW stat req timed out\n");
- return bnx2fc_stats;
+ goto unlock_stats_mutex;
}
BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt);
bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt;
@@ -700,6 +702,9 @@
memcpy(&hba->prev_stats, hba->stats_buffer,
sizeof(struct fcoe_statistics_params));
+
+unlock_stats_mutex:
+ mutex_unlock(&hba->hba_stats_mutex);
return bnx2fc_stats;
}
@@ -1348,6 +1353,7 @@
}
spin_lock_init(&hba->hba_lock);
mutex_init(&hba->hba_mutex);
+ mutex_init(&hba->hba_stats_mutex);
hba->cnic = cnic;
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index 622bdab..dab195f 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -1769,7 +1769,6 @@
goto bye;
}
- mempool_free(mbp, hw->mb_mempool);
if (finicsum != cfcsum) {
csio_warn(hw,
"Config File checksum mismatch: csum=%#x, computed=%#x\n",
@@ -1780,6 +1779,10 @@
rv = csio_hw_validate_caps(hw, mbp);
if (rv != 0)
goto bye;
+
+ mempool_free(mbp, hw->mb_mempool);
+ mbp = NULL;
+
/*
* Note that we're operating with parameters
* not supplied by the driver, rather than from hard-wired
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 4abd3fc..c2b6829 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1695,6 +1695,15 @@
*/
switch (session->state) {
case ISCSI_STATE_FAILED:
+ /*
+ * cmds should fail during shutdown, if the session
+ * state is bad, allowing completion to happen
+ */
+ if (unlikely(system_state != SYSTEM_RUNNING)) {
+ reason = FAILURE_SESSION_FAILED;
+ sc->result = DID_NO_CONNECT << 16;
+ break;
+ }
case ISCSI_STATE_IN_RECOVERY:
reason = FAILURE_SESSION_IN_RECOVERY;
sc->result = DID_IMM_RETRY << 16;
@@ -1980,6 +1989,19 @@
if (session->state != ISCSI_STATE_LOGGED_IN) {
/*
+ * During shutdown, if session is prematurely disconnected,
+ * recovery won't happen and there will be hung cmds. Not
+ * handling cmds would trigger EH, also bad in this case.
+ * Instead, handle cmd, allow completion to happen and let
+ * upper layer to deal with the result.
+ */
+ if (unlikely(system_state != SYSTEM_RUNNING)) {
+ sc->result = DID_NO_CONNECT << 16;
+ ISCSI_DBG_EH(session, "sc on shutdown, handled\n");
+ rc = BLK_EH_HANDLED;
+ goto done;
+ }
+ /*
* We are probably in the middle of iscsi recovery so let
* that complete and handle the error.
*/
@@ -2083,7 +2105,7 @@
task->last_timeout = jiffies;
spin_unlock(&session->frwd_lock);
ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ?
- "timer reset" : "nh");
+ "timer reset" : "shutdown or nh");
return rc;
}
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 022bb6e..12886f9 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -282,6 +282,7 @@
phy->phy->minimum_linkrate = dr->pmin_linkrate;
phy->phy->maximum_linkrate = dr->pmax_linkrate;
phy->phy->negotiated_linkrate = phy->linkrate;
+ phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED);
skip:
if (new_phy)
@@ -675,7 +676,7 @@
res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
resp, RPEL_RESP_SIZE);
- if (!res)
+ if (res)
goto out;
phy->invalid_dword_count = scsi_to_u32(&resp[12]);
@@ -684,6 +685,7 @@
phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
out:
+ kfree(req);
kfree(resp);
return res;
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 7568e06..44da9d8 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -4065,19 +4065,6 @@
return 0;
}
- /*
- * Bug work around for firmware SATL handling. The loop
- * is based on atomic operations and ensures consistency
- * since we're lockless at this point
- */
- do {
- if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
- scmd->result = SAM_STAT_BUSY;
- scmd->scsi_done(scmd);
- return 0;
- }
- } while (_scsih_set_satl_pending(scmd, true));
-
sas_target_priv_data = sas_device_priv_data->sas_target;
/* invalid device handle */
@@ -4103,6 +4090,19 @@
sas_device_priv_data->block)
return SCSI_MLQUEUE_DEVICE_BUSY;
+ /*
+ * Bug work around for firmware SATL handling. The loop
+ * is based on atomic operations and ensures consistency
+ * since we're lockless at this point
+ */
+ do {
+ if (test_bit(0, &sas_device_priv_data->ata_command_pending)) {
+ scmd->result = SAM_STAT_BUSY;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+ } while (_scsih_set_satl_pending(scmd, true));
+
if (scmd->sc_data_direction == DMA_FROM_DEVICE)
mpi_control = MPI2_SCSIIO_CONTROL_READ;
else if (scmd->sc_data_direction == DMA_TO_DEVICE)
@@ -4124,6 +4124,7 @@
if (!smid) {
pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
+ _scsih_set_satl_pending(scmd, false);
goto out;
}
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
@@ -4154,6 +4155,7 @@
if (mpi_request->DataLength) {
if (ioc->build_sg_scmd(ioc, scmd, smid)) {
mpt3sas_base_free_smid(ioc, smid);
+ _scsih_set_satl_pending(scmd, false);
goto out;
}
} else
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index 8f4adc1..cbc8e93 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -819,6 +819,7 @@
.change_queue_depth = virtscsi_change_queue_depth,
.eh_abort_handler = virtscsi_abort,
.eh_device_reset_handler = virtscsi_device_reset,
+ .slave_alloc = virtscsi_device_alloc,
.can_queue = 1024,
.dma_boundary = UINT_MAX,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 5fafaca..090b3e1 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -868,3 +868,11 @@
interrupt event and event data.
source "drivers/soc/qcom/wcnss/Kconfig"
+
+config BIG_CLUSTER_MIN_FREQ_ADJUST
+ bool "Adjust BIG cluster min frequency based on power collapse state"
+ default n
+ help
+ This driver is used to set the floor of the min frequency of big cluster
+ to the user specified value when the cluster is not power collapsed. When
+ the cluster is power collpsed it resets the value to physical limits.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index b83f554..967f525 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -105,3 +105,4 @@
obj-$(CONFIG_QCOM_QDSS_BRIDGE) += qdss_bridge.o
obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o
obj-$(CONFIG_WCNSS_CORE) += wcnss/
+obj-$(CONFIG_BIG_CLUSTER_MIN_FREQ_ADJUST) += big_cluster_min_freq_adjust.o
diff --git a/drivers/soc/qcom/big_cluster_min_freq_adjust.c b/drivers/soc/qcom/big_cluster_min_freq_adjust.c
new file mode 100644
index 0000000..dbc89e1
--- /dev/null
+++ b/drivers/soc/qcom/big_cluster_min_freq_adjust.c
@@ -0,0 +1,278 @@
+/* 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.
+ *
+ */
+
+#define pr_fmt(fmt) "big_min_freq_adjust: " fmt
+
+#include <linux/init.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_pm.h>
+#include <linux/types.h>
+#include <linux/smp.h>
+#include <linux/moduleparam.h>
+
+enum min_freq_adjust {
+ ADJUST_MIN_FLOOR, /* Set min floor to user supplied value */
+ RESET_MIN_FLOOR, /* Reset min floor cpuinfo value */
+};
+
+struct big_min_freq_adjust_data {
+ struct cpumask cluster_cpumask;
+ unsigned int min_freq_floor;
+ struct delayed_work min_freq_work;
+ unsigned long min_down_delay_jiffies;
+ enum min_freq_adjust min_freq_state;
+ enum min_freq_adjust min_freq_request;
+ spinlock_t lock;
+ bool big_min_freq_on;
+ bool is_init;
+};
+static struct big_min_freq_adjust_data big_min_freq_adjust_data;
+
+static void cpufreq_min_freq_work(struct work_struct *work)
+{
+ struct big_min_freq_adjust_data *p = &big_min_freq_adjust_data;
+
+ spin_lock(&p->lock);
+ if (p->min_freq_state == p->min_freq_request) {
+ spin_unlock(&p->lock);
+ return;
+ }
+ spin_unlock(&p->lock);
+ cpufreq_update_policy(cpumask_first(&p->cluster_cpumask));
+}
+
+static int cpufreq_callback(struct notifier_block *nb, unsigned long val,
+ void *data)
+{
+ struct big_min_freq_adjust_data *p = &big_min_freq_adjust_data;
+ struct cpufreq_policy *policy = data;
+ unsigned int min_freq_floor;
+
+ if (p->big_min_freq_on == false)
+ return NOTIFY_DONE;
+
+ if (val != CPUFREQ_ADJUST)
+ return NOTIFY_DONE;
+
+ if (!cpumask_test_cpu(cpumask_first(&p->cluster_cpumask),
+ policy->related_cpus))
+ return NOTIFY_DONE;
+
+ spin_lock(&p->lock);
+ if (p->min_freq_request == ADJUST_MIN_FLOOR)
+ min_freq_floor = p->min_freq_floor;
+ else
+ min_freq_floor = policy->cpuinfo.min_freq;
+ cpufreq_verify_within_limits(policy, min_freq_floor,
+ policy->cpuinfo.max_freq);
+ p->min_freq_state = p->min_freq_request;
+ spin_unlock(&p->lock);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpufreq_nb = {
+ .notifier_call = cpufreq_callback
+};
+
+#define AFFINITY_LEVEL_L2 1
+static int cpu_pm_callback(struct notifier_block *self,
+ unsigned long cmd, void *v)
+{
+ struct big_min_freq_adjust_data *p = &big_min_freq_adjust_data;
+ unsigned long aff_level = (unsigned long) v;
+ unsigned long delay;
+ int cpu;
+
+ if (p->big_min_freq_on == false)
+ return NOTIFY_DONE;
+
+ if (aff_level != AFFINITY_LEVEL_L2)
+ return NOTIFY_DONE;
+
+ cpu = smp_processor_id();
+
+ if (!cpumask_test_cpu(cpu, &p->cluster_cpumask))
+ return NOTIFY_DONE;
+
+ spin_lock(&p->lock);
+ switch (cmd) {
+ case CPU_CLUSTER_PM_ENTER:
+ p->min_freq_request = RESET_MIN_FLOOR;
+ delay = p->min_down_delay_jiffies;
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ p->min_freq_request = ADJUST_MIN_FLOOR;
+ /* To avoid unnecessary oscillations between exit and idle */
+ delay = 1;
+ break;
+ default:
+ spin_unlock(&p->lock);
+ return NOTIFY_DONE;
+ }
+
+ cancel_delayed_work(&p->min_freq_work);
+
+ if (p->min_freq_state != p->min_freq_request)
+ schedule_delayed_work(&p->min_freq_work, delay);
+ spin_unlock(&p->lock);
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpu_pm_nb = {
+ .notifier_call = cpu_pm_callback
+};
+
+static unsigned long __read_mostly big_min_down_delay_ms;
+#define MIN_DOWN_DELAY_MSEC 80 /* Default big_min_down_delay in msec */
+#define POLICY_MIN 1094400 /* Default min_freq_floor in KHz */
+
+static void trigger_state_machine(void *d)
+{
+ struct big_min_freq_adjust_data *p = &big_min_freq_adjust_data;
+ bool *update_policy = d;
+
+ if (p->min_freq_request != ADJUST_MIN_FLOOR) {
+ p->min_freq_request = ADJUST_MIN_FLOOR;
+ *update_policy = true;
+ }
+}
+
+static int enable_big_min_freq_adjust(void)
+{
+ struct big_min_freq_adjust_data *p = &big_min_freq_adjust_data;
+ int ret;
+ bool update_policy = false;
+
+ if (p->big_min_freq_on == true)
+ return 0;
+
+ INIT_DEFERRABLE_WORK(&p->min_freq_work, cpufreq_min_freq_work);
+
+ cpumask_clear(&p->cluster_cpumask);
+ cpumask_set_cpu(4, &p->cluster_cpumask);
+ cpumask_set_cpu(5, &p->cluster_cpumask);
+ cpumask_set_cpu(6, &p->cluster_cpumask);
+ cpumask_set_cpu(7, &p->cluster_cpumask);
+
+ if (!big_min_down_delay_ms) {
+ big_min_down_delay_ms = MIN_DOWN_DELAY_MSEC;
+ p->min_down_delay_jiffies = msecs_to_jiffies(
+ big_min_down_delay_ms);
+ }
+ if (!p->min_freq_floor)
+ p->min_freq_floor = POLICY_MIN;
+
+ ret = cpu_pm_register_notifier(&cpu_pm_nb);
+ if (ret) {
+ pr_err("Failed to register for PM notification\n");
+ return ret;
+ }
+
+ ret = cpufreq_register_notifier(&cpufreq_nb, CPUFREQ_POLICY_NOTIFIER);
+ if (ret) {
+ pr_err("Failed to register for CPUFREQ POLICY notification\n");
+ cpu_pm_unregister_notifier(&cpu_pm_nb);
+ return ret;
+ }
+
+ p->min_freq_state = RESET_MIN_FLOOR;
+ p->min_freq_request = RESET_MIN_FLOOR;
+ spin_lock_init(&p->lock);
+ p->big_min_freq_on = true;
+
+ /* If BIG cluster is active at this time and continue to be active
+ * forever, in that case min frequency of the cluster will never be
+ * set to floor value. This is to trigger the state machine and set
+ * the min freq and min_freq_state to appropriate values.
+ *
+ * Two possibilities here.
+ * 1) If cluster is idle before this, the wakeup is unnecessary but
+ * the state machine is set to proper state.
+ * 2) If cluster is active before this, the wakeup is necessary and
+ * the state machine is set to proper state.
+ */
+ smp_call_function_any(&p->cluster_cpumask,
+ trigger_state_machine, &update_policy, true);
+ if (update_policy)
+ cpufreq_update_policy(cpumask_first(&p->cluster_cpumask));
+
+ pr_info("big min freq ajustment enabled\n");
+
+ return 0;
+}
+
+static bool __read_mostly big_min_freq_adjust_enabled;
+
+static int set_big_min_freq_adjust(const char *buf,
+ const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_bool_enable_only(buf, kp);
+ if (ret) {
+ pr_err("Unable to set big_min_freq_adjust_enabled: %d\n", ret);
+ return ret;
+ }
+
+ if (!big_min_freq_adjust_data.is_init)
+ return ret;
+
+ return enable_big_min_freq_adjust();
+}
+
+static const struct kernel_param_ops param_ops_big_min_freq_adjust = {
+ .set = set_big_min_freq_adjust,
+ .get = param_get_bool,
+};
+module_param_cb(min_freq_adjust, ¶m_ops_big_min_freq_adjust,
+ &big_min_freq_adjust_enabled, 0644);
+
+module_param_named(min_freq_floor, big_min_freq_adjust_data.min_freq_floor,
+ uint, 0644);
+
+static int set_min_down_delay_ms(const char *buf, const struct kernel_param *kp)
+{
+ int ret;
+
+ ret = param_set_ulong(buf, kp);
+ if (ret) {
+ pr_err("Unable to set big_min_down_delay_ms: %d\n", ret);
+ return ret;
+ }
+
+ big_min_freq_adjust_data.min_down_delay_jiffies = msecs_to_jiffies(
+ big_min_down_delay_ms);
+
+ return 0;
+}
+
+static const struct kernel_param_ops param_ops_big_min_down_delay_ms = {
+ .set = set_min_down_delay_ms,
+ .get = param_get_ulong,
+};
+module_param_cb(min_down_delay_ms, ¶m_ops_big_min_down_delay_ms,
+ &big_min_down_delay_ms, 0644);
+
+static int __init big_min_freq_adjust_init(void)
+{
+ big_min_freq_adjust_data.is_init = true;
+ if (!big_min_freq_adjust_enabled)
+ return 0;
+
+ return enable_big_min_freq_adjust();
+}
+late_initcall(big_min_freq_adjust_init);
diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c
index a687286..bef0757 100644
--- a/drivers/soc/qcom/dcc.c
+++ b/drivers/soc/qcom/dcc.c
@@ -731,7 +731,8 @@
mutex_lock(&drvdata->mutex);
- if (!len) {
+ /* Check the len to avoid allocate huge memory */
+ if (!len || len > (drvdata->ram_size / 8)) {
dev_err(drvdata->dev, "DCC: Invalid length!\n");
ret = -EINVAL;
goto err;
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 683b074..c254299 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -2453,6 +2453,9 @@
if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state))
goto out;
+ if (priv->force_err_fatal)
+ ICNSS_ASSERT(0);
+
if (priv->early_crash_ind) {
icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n",
event_data->crashed, priv->state);
@@ -2467,9 +2470,6 @@
goto out;
}
- if (priv->force_err_fatal)
- ICNSS_ASSERT(0);
-
icnss_fw_crashed(priv, event_data);
out:
diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c
index 4a22b4d..6e9da60 100644
--- a/drivers/soc/qcom/microdump_collector.c
+++ b/drivers/soc/qcom/microdump_collector.c
@@ -48,9 +48,9 @@
crash_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size_reason
, 0, SMEM_ANY_HOST_FLAG);
if (IS_ERR_OR_NULL(crash_reason)) {
- pr_err("%s: Error in getting SMEM_reason pointer\n",
- __func__);
- return -ENODEV;
+ pr_info("%s: smem %d not available\n",
+ __func__, SMEM_SSR_REASON_MSS0);
+ goto out;
}
segment[0].v_address = crash_reason;
@@ -58,9 +58,9 @@
crash_data = smem_get_entry(smem_id, &size_data, SMEM_MODEM, 0);
if (IS_ERR_OR_NULL(crash_data)) {
- pr_err("%s: Error in getting SMEM_data pointer\n",
- __func__);
- return -ENODEV;
+ pr_info("%s: smem %d not available\n ",
+ __func__, smem_id);
+ goto out;
}
segment[1].v_address = crash_data;
@@ -68,10 +68,11 @@
ret = do_ramdump(drv->microdump_dev, segment, 2);
if (ret)
- pr_err("%s: do_ramdump() failed\n", __func__);
+ pr_info("%s: do_ramdump() failed\n", __func__);
}
- return ret;
+out:
+ return NOTIFY_OK;
}
static int microdump_modem_ssr_register_notifier(struct microdump_data *drv)
diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c
index 360dbcf..8776379 100644
--- a/drivers/soc/qcom/peripheral-loader.c
+++ b/drivers/soc/qcom/peripheral-loader.c
@@ -263,6 +263,7 @@
struct pil_priv *priv = desc->priv;
struct pil_seg *seg;
int count = 0, ret;
+ u32 encryption_status = 0;
if (desc->minidump_ss) {
pr_info("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n",
@@ -280,12 +281,14 @@
* Collect minidump if SS ToC is valid and segment table
* is initialized in memory and encryption status is set.
*/
+ encryption_status = desc->minidump_ss->encryption_status;
+
if ((desc->minidump_ss->md_ss_smem_regions_baseptr != 0) &&
(desc->minidump_ss->md_ss_toc_init == true) &&
(desc->minidump_ss->md_ss_enable_status ==
MD_SS_ENABLED)) {
- if (desc->minidump_ss->encryption_status ==
- MD_SS_ENCR_DONE) {
+ if (encryption_status == MD_SS_ENCR_DONE ||
+ encryption_status == MD_SS_ENCR_NOTREQ) {
pr_info("Minidump : Dumping for %s\n",
desc->name);
return pil_do_minidump(desc, minidump_dev);
diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c
index 6283477..2a46d0b 100644
--- a/drivers/soc/qcom/pil-msa.c
+++ b/drivers/soc/qcom/pil-msa.c
@@ -797,14 +797,18 @@
int pil_mss_debug_reset(struct pil_desc *pil)
{
struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc);
+ u32 encryption_status;
int ret;
+
if (!pil->minidump_ss)
return 0;
- if (pil->minidump_ss) {
- if (pil->minidump_ss->md_ss_enable_status != MD_SS_ENABLED)
- return 0;
- }
+
+ encryption_status = pil->minidump_ss->encryption_status;
+
+ if ((pil->minidump_ss->md_ss_enable_status != MD_SS_ENABLED) ||
+ encryption_status == MD_SS_ENCR_NOTREQ)
+ return 0;
/*
* Bring subsystem out of reset and enable required
@@ -836,7 +840,7 @@
* complete before returning
*/
pr_info("Minidump: waiting encryption to complete\n");
- msleep(10000);
+ msleep(13000);
if (pil->minidump_ss) {
writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG);
/* Let write complete before proceeding */
diff --git a/drivers/soc/qcom/qdss_bridge.c b/drivers/soc/qcom/qdss_bridge.c
index 8668155..fb70a07 100644
--- a/drivers/soc/qcom/qdss_bridge.c
+++ b/drivers/soc/qcom/qdss_bridge.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,7 +245,7 @@
switch (event) {
case USB_QDSS_CONNECT:
- usb_qdss_alloc_req(drvdata->usb_ch, poolsize, 0);
+ usb_qdss_alloc_req(ch, poolsize, 0);
mhi_queue_read(drvdata);
break;
diff --git a/drivers/soc/qcom/wcnss/wcnss_vreg.c b/drivers/soc/qcom/wcnss/wcnss_vreg.c
index 9d24ce1..1e61250 100644
--- a/drivers/soc/qcom/wcnss/wcnss_vreg.c
+++ b/drivers/soc/qcom/wcnss/wcnss_vreg.c
@@ -206,7 +206,7 @@
voltage_levels,
ARRAY_SIZE(voltage_levels));
if (ret) {
- dev_err(dev, "error reading %s property\n", vreg_name);
+ wcnss_log(ERR, "error reading %s property\n", vreg_name);
return ret;
}
@@ -217,7 +217,8 @@
ret = of_property_read_u32(dev->of_node, current_vreg_name,
¤t_vreg);
if (ret) {
- dev_err(dev, "error reading %s property\n", current_vreg_name);
+ wcnss_log(ERR, "error reading %s property\n",
+ current_vreg_name);
return ret;
}
@@ -240,12 +241,14 @@
if (IS_ERR(pronto_vregs[vreg_i].regulator)) {
if (pronto_vregs[vreg_i].required) {
rc = PTR_ERR(pronto_vregs[vreg_i].regulator);
- dev_err(dev, "regulator get of %s failed (%d)\n",
+ wcnss_log(ERR,
+ "regulator get of %s failed (%d)\n",
pronto_vregs[vreg_i].name, rc);
return rc;
} else {
- dev_dbg(dev, "Skip optional regulator configuration: %s\n",
- pronto_vregs[vreg_i].name);
+ wcnss_log(DBG,
+ "Skip optional regulator configuration: %s\n",
+ pronto_vregs[vreg_i].name);
continue;
}
}
@@ -255,7 +258,8 @@
pronto_vregs[vreg_i].volt,
wlan_config->pronto_vlevel);
if (rc) {
- dev_err(dev, "error reading voltage-level property\n");
+ wcnss_log(ERR,
+ "error reading voltage-level property\n");
return rc;
}
pronto_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK;
@@ -269,12 +273,14 @@
if (IS_ERR(iris_vregs[vreg_i].regulator)) {
if (iris_vregs[vreg_i].required) {
rc = PTR_ERR(iris_vregs[vreg_i].regulator);
- dev_err(dev, "regulator get of %s failed (%d)\n",
+ wcnss_log(ERR,
+ "regulator get of %s failed (%d)\n",
iris_vregs[vreg_i].name, rc);
return rc;
} else {
- dev_dbg(dev, "Skip optional regulator configuration: %s\n",
- iris_vregs[vreg_i].name);
+ wcnss_log(DBG,
+ "Skip optional regulator configuration: %s\n",
+ iris_vregs[vreg_i].name);
continue;
}
}
@@ -284,7 +290,8 @@
iris_vregs[vreg_i].volt,
wlan_config->iris_vlevel);
if (rc) {
- dev_err(dev, "error reading voltage-level property\n");
+ wcnss_log(ERR,
+ "error reading voltage-level property\n");
return rc;
}
iris_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK;
@@ -334,7 +341,7 @@
clk = clk_get(dev, "xo");
if (IS_ERR(clk)) {
- pr_err("Couldn't get xo clock\n");
+ wcnss_log(ERR, "Couldn't get xo clock\n");
return PTR_ERR(clk);
}
@@ -344,7 +351,7 @@
clk = clk_get(dev, "cxo");
if (IS_ERR(clk)) {
- pr_err("Couldn't get cxo clock\n");
+ wcnss_log(ERR, "Couldn't get cxo clock\n");
return PTR_ERR(clk);
}
}
@@ -352,21 +359,21 @@
if (on) {
msm_wcnss_base = cfg->msm_wcnss_base;
if (!msm_wcnss_base) {
- pr_err("ioremap wcnss physical failed\n");
+ wcnss_log(ERR, "ioremap wcnss physical failed\n");
goto fail;
}
/* Enable IRIS XO */
rc = clk_prepare_enable(clk);
if (rc) {
- pr_err("clk enable failed\n");
+ wcnss_log(ERR, "clk enable failed\n");
goto fail;
}
/* NV bit is set to indicate that platform driver is capable
* of doing NV download.
*/
- pr_debug("wcnss: Indicate NV bin download\n");
+ wcnss_log(DBG, "Indicate NV bin download\n");
spare_reg = msm_wcnss_base + spare_offset;
reg = readl_relaxed(spare_reg);
reg |= NVBIN_DLND_BIT;
@@ -403,10 +410,11 @@
cpu_relax();
iris_reg = readl_relaxed(iris_read_reg);
- pr_info("wcnss: IRIS Reg: %08x\n", iris_reg);
+ wcnss_log(INFO, "IRIS Reg: %08x\n", iris_reg);
if (validate_iris_chip_id(iris_reg) && i >= 4) {
- pr_info("wcnss: IRIS Card absent/invalid\n");
+ wcnss_log(INFO,
+ "IRIS Card absent/invalid\n");
auto_detect = WCNSS_XO_INVALID;
/* Reset iris read bit */
reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
@@ -416,7 +424,8 @@
reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE);
goto xo_configure;
} else if (!validate_iris_chip_id(iris_reg)) {
- pr_debug("wcnss: IRIS Card is present\n");
+ wcnss_log(DBG,
+ "IRIS Card is present\n");
break;
}
reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ;
@@ -472,13 +481,13 @@
auto_detect == WCNSS_XO_19MHZ) {
clk_rf = clk_get(dev, "rf_clk");
if (IS_ERR(clk_rf)) {
- pr_err("Couldn't get rf_clk\n");
+ wcnss_log(ERR, "Couldn't get rf_clk\n");
goto fail;
}
rc = clk_prepare_enable(clk_rf);
if (rc) {
- pr_err("clk_rf enable failed\n");
+ wcnss_log(ERR, "clk_rf enable failed\n");
goto fail;
}
if (iris_xo_set)
@@ -489,7 +498,7 @@
auto_detect == WCNSS_XO_19MHZ) {
clk_rf = clk_get(dev, "rf_clk");
if (IS_ERR(clk_rf)) {
- pr_err("Couldn't get rf_clk\n");
+ wcnss_log(ERR, "Couldn't get rf_clk\n");
goto fail;
}
clk_disable_unprepare(clk_rf);
@@ -517,7 +526,7 @@
cfg = wcnss_get_wlan_config();
if (!cfg) {
- pr_err("Failed to get WLAN configuration\n");
+ wcnss_log(ERR, "Failed to get WLAN configuration\n");
return;
}
@@ -530,7 +539,8 @@
if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) {
rc = regulator_set_load(regulators[i].regulator, 0);
if (rc < 0) {
- pr_err("regulator set load(%s) failed (%d)\n",
+ wcnss_log(ERR,
+ "regulator set load(%s) failed (%d)\n",
regulators[i].name, rc);
}
}
@@ -553,15 +563,16 @@
max_voltage);
if (rc)
- pr_err("regulator_set_voltage(%s) failed (%d)\n",
- regulators[i].name, rc);
+ wcnss_log(ERR,
+ "regulator_set_voltage(%s) failed (%d)\n",
+ regulators[i].name, rc);
}
/* Disable regulator */
if (regulators[i].state & VREG_ENABLE_MASK) {
rc = regulator_disable(regulators[i].regulator);
if (rc < 0)
- pr_err("vreg %s disable failed (%d)\n",
+ wcnss_log(ERR, "vreg %s disable failed (%d)\n",
regulators[i].name, rc);
}
}
@@ -579,7 +590,7 @@
cfg = wcnss_get_wlan_config();
if (!cfg) {
- pr_err("Failed to get WLAN configuration\n");
+ wcnss_log(ERR, "Failed to get WLAN configuration\n");
return -EINVAL;
}
@@ -608,7 +619,8 @@
max_voltage);
if (rc) {
- pr_err("regulator_set_voltage(%s) failed (%d)\n",
+ wcnss_log(ERR,
+ "regulator_set_voltage(%s) failed (%d)\n",
regulators[i].name, rc);
goto fail;
}
@@ -620,7 +632,8 @@
rc = regulator_set_load(regulators[i].regulator,
voltage_level[i].uA_load);
if (rc < 0) {
- pr_err("regulator set load(%s) failed (%d)\n",
+ wcnss_log(ERR,
+ "regulator set load(%s) failed (%d)\n",
regulators[i].name, rc);
goto fail;
}
@@ -630,7 +643,7 @@
/* Enable the regulator */
rc = regulator_enable(regulators[i].regulator);
if (rc) {
- pr_err("vreg %s enable failed (%d)\n",
+ wcnss_log(ERR, "vreg %s enable failed (%d)\n",
regulators[i].name, rc);
goto fail;
}
@@ -653,7 +666,7 @@
cfg->iris_vlevel);
break;
default:
- pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
}
}
@@ -669,7 +682,7 @@
cfg->iris_vlevel);
break;
default:
- pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
}
return ret;
}
@@ -683,7 +696,7 @@
ARRAY_SIZE(pronto_vregs), cfg->pronto_vlevel);
break;
default:
- pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
}
}
@@ -700,7 +713,7 @@
cfg->pronto_vlevel);
break;
default:
- pr_err("%s invalid hardware %d\n", __func__, hw_type);
+ wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type);
}
return ret;
diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c
index c3fb30b..08bd78b 100644
--- a/drivers/soc/qcom/wcnss/wcnss_wlan.c
+++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c
@@ -38,6 +38,7 @@
#include <linux/pm_qos.h>
#include <linux/bitops.h>
#include <linux/cdev.h>
+#include <linux/ipc_logging.h>
#include <soc/qcom/socinfo.h>
#include <soc/qcom/subsystem_restart.h>
@@ -452,6 +453,53 @@
struct cdev ctrl_dev, node_dev;
} *penv = NULL;
+static void *wcnss_ipc_log;
+
+#define IPC_NUM_LOG_PAGES 12
+#define wcnss_ipc_log_string(_x...) do { \
+ if (wcnss_ipc_log) \
+ ipc_log_string(wcnss_ipc_log, _x); \
+ } while (0)
+
+void wcnss_log(enum wcnss_log_type type, const char *_fmt, ...)
+{
+ struct va_format vaf = {
+ .fmt = _fmt,
+ };
+ va_list args;
+
+ va_start(args, _fmt);
+ vaf.va = &args;
+ switch (type) {
+ case ERR:
+ pr_err("wcnss: %pV", &vaf);
+ wcnss_ipc_log_string("wcnss: %pV", &vaf);
+ break;
+ case WARN:
+ pr_warn("wcnss: %pV", &vaf);
+ wcnss_ipc_log_string("wcnss: %pV", &vaf);
+ break;
+ case INFO:
+ pr_info("wcnss: %pV", &vaf);
+ wcnss_ipc_log_string("wcnss: %pV", &vaf);
+ break;
+ case DBG:
+#if defined(CONFIG_DYNAMIC_DEBUG)
+ pr_debug("wcnss: %pV", &vaf);
+ wcnss_ipc_log_string("wcnss: %pV", &vaf);
+#elif defined(DEBUG)
+ pr_debug("wcnss: %pV", &vaf);
+ wcnss_ipc_log_string("wcnss: %pV", &vaf);
+#else
+ pr_devel("wcnss: %pV", &vaf);
+ wcnss_ipc_log_string("wcnss: %pV", &vaf);
+#endif
+ break;
+ }
+ va_end(args);
+}
+EXPORT_SYMBOL(wcnss_log);
+
static ssize_t wcnss_wlan_macaddr_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -463,14 +511,14 @@
return -ENODEV;
if (strlen(buf) != WCNSS_USER_MAC_ADDR_LENGTH) {
- dev_err(dev, "%s: Invalid MAC addr length\n", __func__);
+ wcnss_log(ERR, "%s: Invalid MAC addr length\n", __func__);
return -EINVAL;
}
if (sscanf(buf, MAC_ADDRESS_STR, &mac_addr[0], &mac_addr[1],
&mac_addr[2], &mac_addr[3], &mac_addr[4],
&mac_addr[5]) != WLAN_MAC_ADDR_SIZE) {
- pr_err("%s: Failed to Copy MAC\n", __func__);
+ wcnss_log(ERR, "%s: Failed to Copy MAC\n", __func__);
return -EINVAL;
}
@@ -479,7 +527,7 @@
(char *)&mac_addr[index], sizeof(char));
}
- pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+ wcnss_log(INFO, "%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1],
penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3],
penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]);
@@ -555,19 +603,19 @@
ccu_reg = penv->riva_ccu_base + CCU_RIVA_INVALID_ADDR_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
+ wcnss_log(INFO, "%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg);
ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR0_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
+ wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg);
ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR1_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
+ wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg);
ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET;
reg = readl_relaxed(ccu_reg);
- pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
+ wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg);
}
EXPORT_SYMBOL(wcnss_riva_log_debug_regs);
@@ -586,13 +634,12 @@
break;
}
- if (iter == A2XB_FIFO_COUNTER) {
- pr_err("%s data FIFO testbus possibly stalled reg%08x\n",
- type, reg);
- } else {
- pr_err("%s data FIFO tstbus not stalled reg%08x\n",
- type, reg);
- }
+ if (iter == A2XB_FIFO_COUNTER)
+ wcnss_log(ERR,
+ "%s data FIFO testbus possibly stalled reg%08x\n", type, reg);
+ else
+ wcnss_log(ERR,
+ "%s data FIFO tstbus not stalled reg%08x\n", type, reg);
}
int wcnss_get_dual_band_capability_info(struct platform_device *pdev)
@@ -627,71 +674,72 @@
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_SPARE %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_SPARE %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_COM_CPU_CBCR %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_COM_AHB_CBCR %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_CFG %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_CFG %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_COM_CSR %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_COM_CSR %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_SOFT_RESET %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_SOFT_RESET %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WDOG_CTL;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_WDOG_CTL %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_WDOG_CTL %08x\n", reg);
reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_SAW2_SPM_STS %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_SAW2_SPM_STS %08x\n", reg);
reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_CTL;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_SAW2_SPM_CTL %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_SAW2_SPM_CTL %08x\n", reg);
if (penv->is_a2xb_split_reg) {
reg_addr = penv->msm_wcnss_base +
PMU_A2XB_CFG_HSPLIT_RESP_LIMIT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PMU_A2XB_CFG_HSPLIT_RESP_LIMIT %08x\n", reg);
+ wcnss_log(ERR, "PMU_A2XB_CFG_HSPLIT_RESP_LIMIT %08x\n", reg);
}
reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SAW2_VERSION;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_SAW2_SAW2_VERSION %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_SAW2_SAW2_VERSION %08x\n", reg);
reg >>= PRONTO_SAW2_MAJOR_VER_OFFSET;
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CCPU_BOOT_REMAP_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_CCPU_BOOT_REMAP %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_CCPU_BOOT_REMAP %08x\n", reg);
reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PLL_STATUS %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PLL_STATUS %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET;
reg4 = readl_relaxed(reg_addr);
- pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4);
+ wcnss_log(ERR, "PMU_CPU_CMD_RCGR %08x\n", reg4);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("PRONTO_PMU_COM_GDSCR %08x\n", reg);
+ wcnss_log(ERR, "PRONTO_PMU_COM_GDSCR %08x\n", reg);
reg >>= 31;
if (!reg) {
- pr_err("Cannot log, Pronto common SS is power collapsed\n");
+ wcnss_log(ERR,
+ "Cannot log, Pronto common SS is power collapsed\n");
return;
}
reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE
@@ -705,47 +753,47 @@
reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("A2XB_CFG_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "A2XB_CFG_OFFSET %08x\n", reg);
reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("A2XB_INT_SRC_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "A2XB_INT_SRC_OFFSET %08x\n", reg);
reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("A2XB_ERR_INFO_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "A2XB_ERR_INFO_OFFSET %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_CCPU_INVALID_ADDR %08x\n", reg);
+ wcnss_log(ERR, "CCU_CCPU_INVALID_ADDR %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_CCPU_LAST_ADDR0 %08x\n", reg);
+ wcnss_log(ERR, "CCU_CCPU_LAST_ADDR0 %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_CCPU_LAST_ADDR1 %08x\n", reg);
+ wcnss_log(ERR, "CCU_CCPU_LAST_ADDR1 %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_CCPU_LAST_ADDR2 %08x\n", reg);
+ wcnss_log(ERR, "CCU_CCPU_LAST_ADDR2 %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET %08x\n", reg);
reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_A2AB_ERR_ADDR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("CCU_PRONTO_A2AB_ERR_ADDR_OFFSET %08x\n", reg);
+ wcnss_log(ERR, "CCU_PRONTO_A2AB_ERR_ADDR_OFFSET %08x\n", reg);
tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET;
tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET;
@@ -760,7 +808,7 @@
A2XB_READ_FIFO_FILL_MASK,
"Read");
} else {
- pr_err("Read data FIFO testbus %08x\n", reg);
+ wcnss_log(ERR, "Read data FIFO testbus %08x\n", reg);
}
/* command FIFO */
reg = 0;
@@ -771,7 +819,7 @@
wcnss_pronto_is_a2xb_bus_stall(tst_addr,
A2XB_CMD_FIFO_FILL_MASK, "Cmd");
} else {
- pr_err("Command FIFO testbus %08x\n", reg);
+ wcnss_log(ERR, "Command FIFO testbus %08x\n", reg);
}
/* write data FIFO */
@@ -784,7 +832,7 @@
A2XB_WRITE_FIFO_FILL_MASK,
"Write");
} else {
- pr_err("Write data FIFO testbus %08x\n", reg);
+ wcnss_log(ERR, "Write data FIFO testbus %08x\n", reg);
}
/* AXIM SEL CFG0 */
@@ -793,7 +841,7 @@
WCNSS_TSTBUS_CTRL_AXIM_CFG0;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_err("AXIM SEL CFG0 testbus %08x\n", reg);
+ wcnss_log(ERR, "AXIM SEL CFG0 testbus %08x\n", reg);
/* AXIM SEL CFG1 */
reg = 0;
@@ -801,7 +849,7 @@
WCNSS_TSTBUS_CTRL_AXIM_CFG1;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_err("AXIM SEL CFG1 testbus %08x\n", reg);
+ wcnss_log(ERR, "AXIM SEL CFG1 testbus %08x\n", reg);
/* CTRL SEL CFG0 */
reg = 0;
@@ -809,7 +857,7 @@
WCNSS_TSTBUS_CTRL_CTRL_CFG0;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_err("CTRL SEL CFG0 testbus %08x\n", reg);
+ wcnss_log(ERR, "CTRL SEL CFG0 testbus %08x\n", reg);
/* CTRL SEL CFG1 */
reg = 0;
@@ -817,7 +865,7 @@
WCNSS_TSTBUS_CTRL_CTRL_CFG1;
writel_relaxed(reg, tst_ctrl_addr);
reg = readl_relaxed(tst_addr);
- pr_err("CTRL SEL CFG1 testbus %08x\n", reg);
+ wcnss_log(ERR, "CTRL SEL CFG1 testbus %08x\n", reg);
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET;
reg = readl_relaxed(reg_addr);
@@ -827,7 +875,7 @@
reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_AHB_CBCR_OFFSET;
reg3 = readl_relaxed(reg_addr);
- pr_err("PMU_WLAN_AHB_CBCR %08x\n", reg3);
+ wcnss_log(ERR, "PMU_WLAN_AHB_CBCR %08x\n", reg3);
msleep(50);
@@ -836,76 +884,76 @@
(!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) ||
(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_OFF) ||
(!(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_EN))) {
- pr_err("Cannot log, wlan domain is power collapsed\n");
+ wcnss_log(ERR, "Cannot log, wlan domain is power collapsed\n");
return;
}
reg = readl_relaxed(penv->wlan_tx_phy_aborts);
- pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg);
+ wcnss_log(ERR, "WLAN_TX_PHY_ABORTS %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_APB2PHY_STATUS_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_APB2PHY_STATUS %08x\n", reg);
+ wcnss_log(ERR, "MCU_APB2PHY_STATUS %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg);
+ wcnss_log(ERR, "MCU_CBR_CCAHB_ERR %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_CBR_CAHB_ERR %08x\n", reg);
+ wcnss_log(ERR, "MCU_CBR_CAHB_ERR %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
+ wcnss_log(ERR, "MCU_CBR_CCAHB_TIMEOUT %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
+ wcnss_log(ERR, "MCU_CBR_CAHB_TIMEOUT %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_DBR_CDAHB_ERR %08x\n", reg);
+ wcnss_log(ERR, "MCU_DBR_CDAHB_ERR %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_DBR_DAHB_ERR %08x\n", reg);
+ wcnss_log(ERR, "MCU_DBR_DAHB_ERR %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
+ wcnss_log(ERR, "MCU_DBR_CDAHB_TIMEOUT %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
+ wcnss_log(ERR, "MCU_DBR_DAHB_TIMEOUT %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_FDBR_CDAHB_ERR %08x\n", reg);
+ wcnss_log(ERR, "MCU_FDBR_CDAHB_ERR %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_ERR_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_FDBR_FDAHB_ERR %08x\n", reg);
+ wcnss_log(ERR, "MCU_FDBR_FDAHB_ERR %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
+ wcnss_log(ERR, "MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg);
reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_TIMEOUT_OFFSET;
reg = readl_relaxed(reg_addr);
- pr_err("MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
+ wcnss_log(ERR, "MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg);
reg = readl_relaxed(penv->wlan_brdg_err_source);
- pr_err("WLAN_BRDG_ERR_SOURCE %08x\n", reg);
+ wcnss_log(ERR, "WLAN_BRDG_ERR_SOURCE %08x\n", reg);
reg = readl_relaxed(penv->wlan_tx_status);
- pr_err("WLAN_TXP_STATUS %08x\n", reg);
+ wcnss_log(ERR, "WLAN_TXP_STATUS %08x\n", reg);
reg = readl_relaxed(penv->alarms_txctl);
- pr_err("ALARMS_TXCTL %08x\n", reg);
+ wcnss_log(ERR, "ALARMS_TXCTL %08x\n", reg);
reg = readl_relaxed(penv->alarms_tactl);
- pr_err("ALARMS_TACTL %08x\n", reg);
+ wcnss_log(ERR, "ALARMS_TACTL %08x\n", reg);
}
EXPORT_SYMBOL(wcnss_pronto_log_debug_regs);
@@ -930,13 +978,13 @@
if (!IS_ERR_OR_NULL(pin_state)) {
ret = pinctrl_select_state(penv->pinctrl, pin_state);
if (ret < 0) {
- pr_err("%s: can not set gpio pins err: %d\n",
+ wcnss_log(ERR, "%s: can not set gpio pins err: %d\n",
__func__, ret);
goto pinctrl_set_err;
}
} else {
- pr_err("%s: invalid gpio pinstate err: %lu\n",
+ wcnss_log(ERR, "%s: invalid gpio pinstate err: %lu\n",
__func__, PTR_ERR(pin_state));
goto pinctrl_set_err;
}
@@ -945,7 +993,7 @@
ret = gpio_request_one(penv->gpios[i],
GPIOF_DIR_IN, NULL);
if (ret) {
- pr_err("%s: request failed for gpio:%d\n",
+ wcnss_log(ERR, "%s: request failed for gpio:%d\n",
__func__, penv->gpios[i]);
i--;
goto gpio_req_err;
@@ -956,7 +1004,7 @@
ret = gpio_request_one(penv->gpios[i],
GPIOF_OUT_INIT_LOW, NULL);
if (ret) {
- pr_err("%s: request failed for gpio:%d\n",
+ wcnss_log(ERR, "%s: request failed for gpio:%d\n",
__func__, penv->gpios[i]);
i--;
goto gpio_req_err;
@@ -1072,12 +1120,13 @@
0x04, 0x05, 0x11, 0x1e, 0x40, 0x48,
0x49, 0x4b, 0x00, 0x01, 0x4d};
- pr_info("%s: IRIS Registers [address] : value\n", __func__);
+ wcnss_log(INFO, "%s: IRIS Registers [address] : value\n", __func__);
for (i = 0; i < ARRAY_SIZE(regs_array); i++) {
reg_val = wcnss_rf_read_reg(regs_array[i]);
- pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val);
+ wcnss_log(INFO, "IRIS Reg Addr: [0x%08x] : Reg val: 0x%08x\n",
+ regs_array[i], reg_val);
}
}
@@ -1111,24 +1160,25 @@
if (!IS_ERR(measure) && !IS_ERR(wcnss_debug_mux)) {
if (clk_set_parent(measure, wcnss_debug_mux)) {
- pr_err("Setting measure clk parent failed\n");
+ wcnss_log(ERR, "Setting measure clk parent failed\n");
return;
}
if (clk_prepare_enable(measure)) {
- pr_err("measure clk enable failed\n");
+ wcnss_log(ERR, "measure clk enable failed\n");
return;
}
clk_rate = clk_get_rate(measure);
- pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate);
+ wcnss_log(DBG, "clock frequency is: %luHz\n", clk_rate);
if (clk_rate) {
wcnss_pronto_log_debug_regs();
if (wcnss_get_mux_control())
wcnss_log_iris_regs();
} else {
- pr_err("clock frequency is zero, cannot access PMU or other registers\n");
+ wcnss_log(ERR, "clock frequency is zero, cannot");
+ wcnss_log(ERR, " access PMU or other registers\n");
wcnss_log_iris_regs();
}
@@ -1153,8 +1203,8 @@
wmb();
__raw_writel(1 << 16, penv->fiq_reg);
} else {
- pr_info("%s: Block FIQ during power up sequence\n",
- __func__);
+ wcnss_log(INFO,
+ "%s: Block FIQ during power up sequence\n", __func__);
}
} else {
wcnss_riva_log_debug_regs();
@@ -1202,20 +1252,20 @@
static void wcnss_pm_qos_add_request(void)
{
- pr_info("%s: add request\n", __func__);
+ wcnss_log(INFO, "%s: add request\n", __func__);
pm_qos_add_request(&penv->wcnss_pm_qos_request, PM_QOS_CPU_DMA_LATENCY,
PM_QOS_DEFAULT_VALUE);
}
static void wcnss_pm_qos_remove_request(void)
{
- pr_info("%s: remove request\n", __func__);
+ wcnss_log(INFO, "%s: remove request\n", __func__);
pm_qos_remove_request(&penv->wcnss_pm_qos_request);
}
void wcnss_pm_qos_update_request(int val)
{
- pr_info("%s: update request %d\n", __func__, val);
+ wcnss_log(INFO, "%s: update request %d\n", __func__, val);
pm_qos_update_request(&penv->wcnss_pm_qos_request, val);
}
@@ -1248,21 +1298,21 @@
int len = 0;
if (penv != data) {
- pr_err("wcnss: invalid env pointer in smd callback\n");
+ wcnss_log(ERR, "invalid env pointer in smd callback\n");
return;
}
switch (event) {
case SMD_EVENT_DATA:
len = smd_read_avail(penv->smd_ch);
if (len < 0) {
- pr_err("wcnss: failed to read from smd %d\n", len);
+ wcnss_log(ERR, "failed to read from smd %d\n", len);
return;
}
schedule_work(&penv->wcnssctrl_rx_work);
break;
case SMD_EVENT_OPEN:
- pr_debug("wcnss: opening WCNSS SMD channel :%s",
+ wcnss_log(DBG, "opening WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
schedule_work(&penv->wcnssctrl_version_work);
schedule_work(&penv->wcnss_pm_config_work);
@@ -1273,7 +1323,7 @@
break;
case SMD_EVENT_CLOSE:
- pr_debug("wcnss: closing WCNSS SMD channel :%s",
+ wcnss_log(DBG, "closing WCNSS SMD channel :%s",
WCNSS_CTRL_CHANNEL);
penv->nv_downloaded = 0;
penv->is_cbc_done = 0;
@@ -1290,7 +1340,7 @@
struct pinctrl_state *pin_state;
int ret;
- pr_debug("%s: Set GPIO state : %d\n", __func__, active);
+ wcnss_log(DBG, "%s: Set GPIO state : %d\n", __func__, active);
pin_state = active ? penv->wcnss_5wire_active
: penv->wcnss_5wire_suspend;
@@ -1298,13 +1348,13 @@
if (!IS_ERR_OR_NULL(pin_state)) {
ret = pinctrl_select_state(penv->pinctrl, pin_state);
if (ret < 0) {
- pr_err("%s: can not set %s pins\n", __func__,
+ wcnss_log(ERR, "%s: can not set %s pins\n", __func__,
active ? WCNSS_PINCTRL_STATE_DEFAULT
: WCNSS_PINCTRL_STATE_SLEEP);
return ret;
}
} else {
- pr_err("%s: invalid '%s' pinstate\n", __func__,
+ wcnss_log(ERR, "%s: invalid '%s' pinstate\n", __func__,
active ? WCNSS_PINCTRL_STATE_DEFAULT
: WCNSS_PINCTRL_STATE_SLEEP);
return PTR_ERR(pin_state);
@@ -1323,7 +1373,7 @@
penv->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR_OR_NULL(penv->pinctrl)) {
- pr_err("%s: failed to get pinctrl\n", __func__);
+ wcnss_log(ERR, "%s: failed to get pinctrl\n", __func__);
return PTR_ERR(penv->pinctrl);
}
@@ -1332,7 +1382,7 @@
WCNSS_PINCTRL_STATE_DEFAULT);
if (IS_ERR_OR_NULL(penv->wcnss_5wire_active)) {
- pr_err("%s: can not get default pinstate\n", __func__);
+ wcnss_log(ERR, "%s: can not get default pinstate\n", __func__);
return PTR_ERR(penv->wcnss_5wire_active);
}
@@ -1341,19 +1391,20 @@
WCNSS_PINCTRL_STATE_SLEEP);
if (IS_ERR_OR_NULL(penv->wcnss_5wire_suspend)) {
- pr_warn("%s: can not get sleep pinstate\n", __func__);
+ wcnss_log(WARN, "%s: can not get sleep pinstate\n", __func__);
return PTR_ERR(penv->wcnss_5wire_suspend);
}
penv->wcnss_gpio_active = pinctrl_lookup_state(penv->pinctrl,
WCNSS_PINCTRL_GPIO_STATE_DEFAULT);
if (IS_ERR_OR_NULL(penv->wcnss_gpio_active))
- pr_warn("%s: can not get gpio default pinstate\n", __func__);
+ wcnss_log(WARN, "%s: can not get gpio default pinstate\n",
+ __func__);
for (i = 0; i < WCNSS_WLAN_MAX_GPIO; i++) {
penv->gpios[i] = of_get_gpio(node, i);
if (penv->gpios[i] < 0)
- pr_warn("%s: Fail to get 5wire gpio: %d\n",
+ wcnss_log(WARN, "%s: Fail to get 5wire gpio: %d\n",
__func__, i);
}
@@ -1370,13 +1421,13 @@
/* Use Pinctrl to configure 5 wire GPIOs */
rc = wcnss_pinctrl_init(pdev);
if (rc) {
- pr_err("%s: failed to get pin resources\n", __func__);
+ wcnss_log(ERR, "%s: failed to get pin resources\n", __func__);
penv->pinctrl = NULL;
goto gpio_probe;
} else {
rc = wcnss_pinctrl_set_state(true);
if (rc)
- pr_err("%s: failed to set pin state\n",
+ wcnss_log(ERR, "%s: failed to set pin state\n",
__func__);
penv->use_pinctrl = true;
return rc;
@@ -1389,7 +1440,7 @@
if (enable) {
rc = gpio_request(gpio, "wcnss_wlan");
if (rc) {
- pr_err("WCNSS gpio_request %d err %d\n",
+ wcnss_log(ERR, "WCNSS gpio_request %d err %d\n",
gpio, rc);
goto fail;
}
@@ -1418,7 +1469,8 @@
if (enable) {
rc = gpio_request(i, gpios_5wire->name);
if (rc) {
- pr_err("WCNSS gpio_request %d err %d\n", i, rc);
+ wcnss_log(ERR,
+ "gpio_request %d err %d\n", i, rc);
goto fail;
}
} else {
@@ -1442,7 +1494,7 @@
penv->smd_channel_ready = 1;
- pr_info("%s: SMD ctrl channel up\n", __func__);
+ wcnss_log(INFO, "%s: SMD ctrl channel up\n", __func__);
return 0;
}
@@ -1452,7 +1504,7 @@
if (penv)
penv->smd_channel_ready = 0;
- pr_info("%s: SMD ctrl channel down\n", __func__);
+ wcnss_log(INFO, "%s: SMD ctrl channel down\n", __func__);
return 0;
}
@@ -1487,7 +1539,7 @@
&penv->smd_ch, penv,
wcnss_smd_notify_event);
if (ret < 0) {
- pr_err("wcnss: cannot open the smd command channel %s: %d\n",
+ wcnss_log(ERR, "cannot open the smd command channel %s: %d\n",
WCNSS_CTRL_CHANNEL, ret);
return -ENODEV;
}
@@ -1611,14 +1663,15 @@
{
if (penv && dev && (dev == &penv->pdev->dev) && pm_ops) {
if (!penv->pm_ops) {
- pr_err("%s: pm_ops is already unregistered.\n",
+ wcnss_log(ERR, "%s: pm_ops is already unregistered.\n",
__func__);
return;
}
if (pm_ops->suspend != penv->pm_ops->suspend ||
pm_ops->resume != penv->pm_ops->resume)
- pr_err("PM APIs dont match with registered APIs\n");
+ wcnss_log(ERR,
+ "PM APIs dont match with registered APIs\n");
penv->pm_ops = NULL;
}
}
@@ -1637,7 +1690,7 @@
{
if (penv && tm_notify) {
if (tm_notify != penv->tm_notify)
- pr_err("tm_notify doesn't match registered\n");
+ wcnss_log(ERR, "tm_notify doesn't match registered\n");
penv->tm_notify = NULL;
}
}
@@ -1647,7 +1700,7 @@
{
if (penv) {
penv->serial_number = socinfo_get_serial_number();
- pr_info("%s: Device serial number: %u\n",
+ wcnss_log(INFO, "%s: Device serial number: %u\n",
__func__, penv->serial_number);
return penv->serial_number;
}
@@ -1662,7 +1715,7 @@
return -ENODEV;
memcpy(mac_addr, penv->wlan_nv_mac_addr, WLAN_MAC_ADDR_SIZE);
- pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+ wcnss_log(DBG, "%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1],
penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3],
penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]);
@@ -1682,7 +1735,7 @@
return ret;
if (enable_wcnss_suspend_notify)
- pr_debug("Suspend notification activated for wcnss\n");
+ wcnss_log(DBG, "Suspend notification activated for wcnss\n");
return 0;
}
@@ -1875,12 +1928,12 @@
ret = smd_write_avail(penv->smd_ch);
if (ret < len) {
- pr_err("wcnss: no space available for smd frame\n");
+ wcnss_log(ERR, "no space available for smd frame\n");
return -ENOSPC;
}
ret = smd_write(penv->smd_ch, data, len);
if (ret < len) {
- pr_err("wcnss: failed to write Command %d", len);
+ wcnss_log(ERR, "failed to write Command %d", len);
ret = -ENODEV;
}
return ret;
@@ -1892,19 +1945,19 @@
struct qpnp_vadc_result adc_result;
if (!penv->vadc_dev) {
- pr_err("wcnss: not setting up vadc\n");
+ wcnss_log(ERR, "not setting up vadc\n");
return rc;
}
rc = qpnp_vadc_read(penv->vadc_dev, VBAT_SNS, &adc_result);
if (rc) {
- pr_err("error reading adc channel = %d, rc = %d\n",
+ wcnss_log(ERR, "error reading adc channel = %d, rc = %d\n",
VBAT_SNS, rc);
return rc;
}
- pr_info("Battery mvolts phy=%lld meas=0x%llx\n", adc_result.physical,
- adc_result.measurement);
+ wcnss_log(INFO, "Battery mvolts phy=%lld meas=0x%llx\n",
+ adc_result.physical, adc_result.measurement);
*result_uv = (int)adc_result.physical;
return 0;
@@ -1918,7 +1971,7 @@
cancel_delayed_work_sync(&penv->vbatt_work);
if (state == ADC_TM_LOW_STATE) {
- pr_debug("wcnss: low voltage notification triggered\n");
+ wcnss_log(DBG, "low voltage notification triggered\n");
penv->vbat_monitor_params.state_request =
ADC_TM_HIGH_THR_ENABLE;
penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD +
@@ -1930,14 +1983,14 @@
penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD -
WCNSS_VBATT_GUARD;
penv->vbat_monitor_params.high_thr = 0;
- pr_debug("wcnss: high voltage notification triggered\n");
+ wcnss_log(DBG, "high voltage notification triggered\n");
} else {
- pr_debug("wcnss: unknown voltage notification state: %d\n",
+ wcnss_log(DBG, "unknown voltage notification state: %d\n",
state);
mutex_unlock(&penv->vbat_monitor_mutex);
return;
}
- pr_debug("wcnss: set low thr to %d and high to %d\n",
+ wcnss_log(DBG, "set low thr to %d and high to %d\n",
penv->vbat_monitor_params.low_thr,
penv->vbat_monitor_params.high_thr);
@@ -1945,7 +1998,7 @@
&penv->vbat_monitor_params);
if (rc)
- pr_err("%s: tm setup failed: %d\n", __func__, rc);
+ wcnss_log(ERR, "%s: tm setup failed: %d\n", __func__, rc);
else
schedule_delayed_work(&penv->vbatt_work,
msecs_to_jiffies(2000));
@@ -1958,7 +2011,7 @@
int rc = -1;
if (!penv->adc_tm_dev) {
- pr_err("wcnss: not setting up vbatt\n");
+ wcnss_log(ERR, "not setting up vbatt\n");
return rc;
}
penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD;
@@ -1973,14 +2026,14 @@
penv->vbat_monitor_params.btm_ctx = (void *)penv;
penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S;
penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat;
- pr_debug("wcnss: set low thr to %d and high to %d\n",
+ wcnss_log(DBG, "set low thr to %d and high to %d\n",
penv->vbat_monitor_params.low_thr,
penv->vbat_monitor_params.high_thr);
rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev,
&penv->vbat_monitor_params);
if (rc)
- pr_err("%s: tm setup failed: %d\n", __func__, rc);
+ wcnss_log(ERR, "%s: tm setup failed: %d\n", __func__, rc);
return rc;
}
@@ -1997,12 +2050,12 @@
mutex_lock(&penv->vbat_monitor_mutex);
vbatt_msg.vbatt.curr_volt = penv->wlan_config.vbatt;
mutex_unlock(&penv->vbat_monitor_mutex);
- pr_debug("wcnss: send curr_volt: %d to FW\n",
+ wcnss_log(DBG, "send curr_volt: %d to FW\n",
vbatt_msg.vbatt.curr_volt);
ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
if (ret < 0)
- pr_err("wcnss: smd tx failed\n");
+ wcnss_log(ERR, "smd tx failed\n");
}
static void wcnss_update_vbatt(struct work_struct *work)
@@ -2020,13 +2073,13 @@
penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) {
vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH;
penv->fw_vbatt_state = WCNSS_VBATT_HIGH;
- pr_debug("wcnss: send HIGH BATT to FW\n");
+ wcnss_log(DBG, "send HIGH BATT to FW\n");
} else if (!penv->vbat_monitor_params.low_thr &&
(penv->fw_vbatt_state == WCNSS_VBATT_HIGH ||
penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){
vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW;
penv->fw_vbatt_state = WCNSS_VBATT_LOW;
- pr_debug("wcnss: send LOW BATT to FW\n");
+ wcnss_log(DBG, "send LOW BATT to FW\n");
} else {
mutex_unlock(&penv->vbat_monitor_mutex);
return;
@@ -2034,7 +2087,7 @@
mutex_unlock(&penv->vbat_monitor_mutex);
ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len);
if (ret < 0)
- pr_err("wcnss: smd tx failed\n");
+ wcnss_log(ERR, "smd tx failed\n");
}
static unsigned char wcnss_fw_status(void)
@@ -2046,13 +2099,13 @@
len = smd_read_avail(penv->smd_ch);
if (len < 1) {
- pr_err("%s: invalid firmware status", __func__);
+ wcnss_log(ERR, "%s: invalid firmware status", __func__);
return fw_status;
}
rc = smd_read(penv->smd_ch, &fw_status, 1);
if (rc < 0) {
- pr_err("%s: incomplete data read from smd\n", __func__);
+ wcnss_log(ERR, "%s: incomplete data read from smd\n", __func__);
return fw_status;
}
return fw_status;
@@ -2075,7 +2128,7 @@
rc = wcnss_smd_tx(msg, rsphdr->msg_len);
if (rc < 0)
- pr_err("wcnss: smd tx failed\n");
+ wcnss_log(ERR, "smd tx failed\n");
kfree(msg);
}
@@ -2088,7 +2141,7 @@
unsigned char fw_status = WCNSS_RESP_FAIL;
if (len < sizeof(struct cal_data_params)) {
- pr_err("wcnss: incomplete cal header length\n");
+ wcnss_log(ERR, "incomplete cal header length\n");
return;
}
@@ -2096,18 +2149,18 @@
rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr,
sizeof(struct cal_data_params));
if (rc < sizeof(struct cal_data_params)) {
- pr_err("wcnss: incomplete cal header read from smd\n");
+ wcnss_log(ERR, "incomplete cal header read from smd\n");
mutex_unlock(&penv->dev_lock);
return;
}
if (penv->fw_cal_exp_frag != calhdr.frag_number) {
- pr_err("wcnss: Invalid frgament");
+ wcnss_log(ERR, "Invalid frgament");
goto unlock_exit;
}
if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) {
- pr_err("wcnss: Invalid fragment size");
+ wcnss_log(ERR, "Invalid fragment size");
goto unlock_exit;
}
@@ -2125,7 +2178,7 @@
if (calhdr.frag_number == 0) {
if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) {
- pr_err("wcnss: Invalid cal data size %d",
+ wcnss_log(ERR, "Invalid cal data size %d",
calhdr.total_size);
goto unlock_exit;
}
@@ -2141,7 +2194,7 @@
if (penv->fw_cal_rcvd + calhdr.frag_size >
MAX_CALIBRATED_DATA_SIZE) {
- pr_err("calibrated data size is more than expected %d",
+ wcnss_log(ERR, "calibrated data size is more than expected %d",
penv->fw_cal_rcvd + calhdr.frag_size);
penv->fw_cal_exp_frag = 0;
penv->fw_cal_rcvd = 0;
@@ -2160,7 +2213,7 @@
if (calhdr.msg_flags & LAST_FRAGMENT) {
penv->fw_cal_exp_frag = 0;
penv->fw_cal_available = true;
- pr_info("wcnss: cal data collection completed\n");
+ wcnss_log(INFO, "cal data collection completed\n");
}
mutex_unlock(&penv->dev_lock);
wake_up(&penv->read_wait);
@@ -2190,18 +2243,18 @@
len = smd_read_avail(penv->smd_ch);
if (len > WCNSS_MAX_FRAME_SIZE) {
- pr_err("wcnss: frame larger than the allowed size\n");
+ wcnss_log(ERR, "frame larger than the allowed size\n");
smd_read(penv->smd_ch, NULL, len);
return;
}
if (len < sizeof(struct smd_msg_hdr)) {
- pr_debug("wcnss: incomplete header available len = %d\n", len);
+ wcnss_log(DBG, "incomplete header available len = %d\n", len);
return;
}
rc = smd_read(penv->smd_ch, buf, sizeof(struct smd_msg_hdr));
if (rc < sizeof(struct smd_msg_hdr)) {
- pr_err("wcnss: incomplete header read from smd\n");
+ wcnss_log(ERR, "incomplete header read from smd\n");
return;
}
len -= sizeof(struct smd_msg_hdr);
@@ -2212,14 +2265,14 @@
case WCNSS_VERSION_RSP:
if (len != sizeof(struct wcnss_version)
- sizeof(struct smd_msg_hdr)) {
- pr_err("wcnss: invalid version data from wcnss %d\n",
+ wcnss_log(ERR, "invalid version data from wcnss %d\n",
len);
return;
}
rc = smd_read(penv->smd_ch, buf + sizeof(struct smd_msg_hdr),
len);
if (rc < len) {
- pr_err("wcnss: incomplete data read from smd\n");
+ wcnss_log(ERR, "incomplete data read from smd\n");
return;
}
pversion = (struct wcnss_version *)buf;
@@ -2228,14 +2281,15 @@
snprintf(penv->wcnss_version, WCNSS_VERSION_LEN,
"%02x%02x%02x%02x", pversion->major, pversion->minor,
pversion->version, pversion->revision);
- pr_info("wcnss: version %s\n", penv->wcnss_version);
+ wcnss_log(INFO, "version %s\n", penv->wcnss_version);
/* schedule work to download nvbin to ccpu */
hw_type = wcnss_hardware_type();
switch (hw_type) {
case WCNSS_RIVA_HW:
/* supported only if riva major >= 1 and minor >= 4 */
if ((pversion->major >= 1) && (pversion->minor >= 4)) {
- pr_info("wcnss: schedule dnld work for riva\n");
+ wcnss_log(INFO,
+ "schedule download work for riva\n");
schedule_work(&penv->wcnssctrl_nvbin_dnld_work);
}
break;
@@ -2245,41 +2299,43 @@
smd_msg.msg_len = sizeof(smd_msg);
rc = wcnss_smd_tx(&smd_msg, smd_msg.msg_len);
if (rc < 0)
- pr_err("wcnss: smd tx failed: %s\n", __func__);
+ wcnss_log(ERR, "smd tx failed: %s\n", __func__);
/* supported only if pronto major >= 1 and minor >= 4 */
if ((pversion->major >= 1) && (pversion->minor >= 4)) {
- pr_info("wcnss: schedule dnld work for pronto\n");
+ wcnss_log(INFO,
+ "schedule dnld work for pronto\n");
schedule_work(&penv->wcnssctrl_nvbin_dnld_work);
}
break;
default:
- pr_info("wcnss: unknown hw type (%d), will not schedule dnld work\n",
- hw_type);
+ wcnss_log(INFO,
+ "unknown hw type (%d) will not schedule dnld work\n",
+ hw_type);
break;
}
break;
case WCNSS_BUILD_VER_RSP:
if (len > WCNSS_MAX_BUILD_VER_LEN) {
- pr_err("wcnss: invalid build version data from wcnss %d\n",
- len);
+ wcnss_log(ERR,
+ "invalid build version data from wcnss %d\n", len);
return;
}
rc = smd_read(penv->smd_ch, build, len);
if (rc < len) {
- pr_err("wcnss: incomplete data read from smd\n");
+ wcnss_log(ERR, "incomplete data read from smd\n");
return;
}
build[len] = 0;
- pr_info("wcnss: build version %s\n", build);
+ wcnss_log(INFO, "build version %s\n", build);
break;
case WCNSS_NVBIN_DNLD_RSP:
penv->nv_downloaded = true;
fw_status = wcnss_fw_status();
- pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
+ wcnss_log(DBG, "received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n",
fw_status);
if (fw_status != WAIT_FOR_CBC_IND)
penv->is_cbc_done = 1;
@@ -2289,12 +2345,12 @@
case WCNSS_CALDATA_DNLD_RSP:
penv->nv_downloaded = true;
fw_status = wcnss_fw_status();
- pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
+ wcnss_log(DBG, "received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n",
fw_status);
break;
case WCNSS_CBC_COMPLETE_IND:
penv->is_cbc_done = 1;
- pr_debug("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n");
+ wcnss_log(DBG, "received WCNSS_CBC_COMPLETE_IND from FW\n");
break;
case WCNSS_CALDATA_UPLD_REQ:
@@ -2302,7 +2358,7 @@
break;
default:
- pr_err("wcnss: invalid message type %d\n", phdr->msg_type);
+ wcnss_log(ERR, "invalid message type %d\n", phdr->msg_type);
}
}
@@ -2315,7 +2371,7 @@
smd_msg.msg_len = sizeof(smd_msg);
ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len);
if (ret < 0)
- pr_err("wcnss: smd tx failed\n");
+ wcnss_log(ERR, "smd tx failed\n");
}
static void wcnss_send_pm_config(struct work_struct *worker)
@@ -2340,12 +2396,12 @@
rc = of_property_read_u32_array(penv->pdev->dev.of_node,
"qcom,wcnss-pm", payload, prop_len);
if (rc < 0) {
- pr_err("wcnss: property read failed\n");
+ wcnss_log(ERR, "property read failed\n");
kfree(msg);
return;
}
- pr_debug("%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__,
+ wcnss_log(DBG, "%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__,
prop_len, *payload, *(payload + 1), *(payload + 2),
*(payload + 3), *(payload + 4), *(payload + 5));
@@ -2355,7 +2411,7 @@
rc = wcnss_smd_tx(msg, hdr->msg_len);
if (rc < 0)
- pr_err("wcnss: smd tx failed\n");
+ wcnss_log(ERR, "smd tx failed\n");
kfree(msg);
}
@@ -2386,7 +2442,8 @@
ret = request_firmware(&nv, NVBIN_FILE, dev);
if (ret || !nv || !nv->data || !nv->size) {
- pr_err("wcnss: %s: request_firmware failed for %s (ret = %d)\n",
+ wcnss_log(ERR,
+ "%s: request_firmware failed for %s (ret = %d)\n",
__func__, NVBIN_FILE, ret);
goto out;
}
@@ -2399,7 +2456,7 @@
total_fragments = TOTALFRAGMENTS(nv_blob_size);
- pr_info("wcnss: NV bin size: %d, total_fragments: %d\n",
+ wcnss_log(INFO, "NV bin size: %d, total_fragments: %d\n",
nv_blob_size, total_fragments);
/* get buffer for nv bin dnld req message */
@@ -2447,11 +2504,12 @@
retry_count = 0;
while ((ret == -ENOSPC) && (retry_count <= 3)) {
- pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+ wcnss_log(DBG, "%s: smd tx failed, ENOSPC\n",
__func__);
- pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
- count, dnld_req_msg->hdr.msg_len,
- total_fragments, retry_count);
+ wcnss_log(DBG, "fragment %d, len: %d,", count,
+ dnld_req_msg->hdr.msg_len);
+ wcnss_log(DBG, "TotFragments: %d, retry_count: %d\n",
+ total_fragments, retry_count);
/* wait and try again */
msleep(20);
@@ -2461,10 +2519,11 @@
}
if (ret < 0) {
- pr_err("wcnss: %s: smd tx failed\n", __func__);
- pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
- count, dnld_req_msg->hdr.msg_len,
- total_fragments, retry_count);
+ wcnss_log(ERR, "%s: smd tx failed\n", __func__);
+ wcnss_log(ERR, "fragment %d, len: %d,", count,
+ dnld_req_msg->hdr.msg_len);
+ wcnss_log(ERR, "TotFragments: %d, retry_count: %d\n",
+ total_fragments, retry_count);
goto err_dnld;
}
}
@@ -2538,11 +2597,12 @@
retry_count = 0;
while ((ret == -ENOSPC) && (retry_count <= 3)) {
- pr_debug("wcnss: %s: smd tx failed, ENOSPC\n",
+ wcnss_log(DBG, "%s: smd tx failed, ENOSPC\n",
__func__);
- pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n",
- count, cal_msg->hdr.msg_len,
- total_fragments, retry_count);
+ wcnss_log(DBG, "fragment: %d, len: %d",
+ count, cal_msg->hdr.msg_len);
+ wcnss_log(DBG, " TotFragments: %d, retry_count: %d\n",
+ total_fragments, retry_count);
/* wait and try again */
msleep(20);
@@ -2552,10 +2612,10 @@
}
if (ret < 0) {
- pr_err("wcnss: %s: smd tx failed\n", __func__);
- pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n",
- count, cal_msg->hdr.msg_len,
- total_fragments, retry_count);
+ wcnss_log(ERR, "%s: smd tx failed: fragment %d, len:%d",
+ count, cal_msg->hdr.msg_len, __func__);
+ wcnss_log(ERR, " TotFragments: %d, retry_count: %d\n",
+ total_fragments, retry_count);
goto err_dnld;
}
}
@@ -2578,17 +2638,17 @@
msleep(500);
}
if (penv->fw_cal_available) {
- pr_info_ratelimited("wcnss: cal download, using fw cal");
+ wcnss_log(INFO, "cal download, using fw cal");
wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, true);
} else if (penv->user_cal_available) {
- pr_info_ratelimited("wcnss: cal download, using user cal");
+ wcnss_log(INFO, "cal download, using user cal");
wcnss_caldata_dnld(penv->user_cal_data,
penv->user_cal_rcvd, true);
}
nv_download:
- pr_info_ratelimited("wcnss: NV download");
+ wcnss_log(INFO, "NV download");
wcnss_nvbin_dnld();
}
@@ -2631,20 +2691,20 @@
switch (cmd) {
case WCNSS_USR_HAS_CAL_DATA:
if (buf[2] > 1)
- pr_err("%s: Invalid data for cal %d\n", __func__,
- buf[2]);
+ wcnss_log(ERR, "%s: Invalid data for cal %d\n",
+ __func__, buf[2]);
has_calibrated_data = buf[2];
break;
case WCNSS_USR_WLAN_MAC_ADDR:
memcpy(&penv->wlan_nv_mac_addr, &buf[2],
sizeof(penv->wlan_nv_mac_addr));
- pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
+ wcnss_log(DBG, "%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__,
penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1],
penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3],
penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]);
break;
default:
- pr_err("%s: Invalid command %d\n", __func__, cmd);
+ wcnss_log(ERR, "%s: Invalid command %d\n", __func__, cmd);
break;
}
}
@@ -2703,7 +2763,7 @@
rc = wcnss_parse_voltage_regulator(&penv->wlan_config, &pdev->dev);
if (rc) {
- dev_err(&pdev->dev, "Failed to parse voltage regulators\n");
+ wcnss_log(ERR, "Failed to parse voltage regulators\n");
goto fail;
}
@@ -2742,7 +2802,7 @@
/* allocate 5-wire GPIO resources */
if (!penv->gpios_5wire) {
- dev_err(&pdev->dev, "insufficient IO resources\n");
+ wcnss_log(ERR, "insufficient IO resources\n");
ret = -ENOENT;
goto fail_gpio_res;
}
@@ -2752,7 +2812,7 @@
}
if (ret) {
- dev_err(&pdev->dev, "WCNSS gpios config failed.\n");
+ wcnss_log(ERR, "gpios config failed.\n");
goto fail_gpio_res;
}
@@ -2765,7 +2825,7 @@
"wcnss_wlanrx_irq");
if (!(penv->mmio_res && penv->tx_irq_res && penv->rx_irq_res)) {
- dev_err(&pdev->dev, "insufficient resources\n");
+ wcnss_log(ERR, "insufficient resources\n");
ret = -ENOENT;
goto fail_res;
}
@@ -2785,7 +2845,7 @@
"pronto_phy_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource pronto_phy_base failed\n",
+ wcnss_log(ERR, "%s: resource pronto_phy_base failed\n",
__func__);
goto fail_ioremap;
}
@@ -2797,7 +2857,7 @@
"riva_phy_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource riva_phy_base failed\n",
+ wcnss_log(ERR, "%s: resource riva_phy_base failed\n",
__func__);
goto fail_ioremap;
}
@@ -2807,7 +2867,7 @@
if (!penv->msm_wcnss_base) {
ret = -ENOMEM;
- pr_err("%s: ioremap wcnss physical failed\n", __func__);
+ wcnss_log(ERR, "%s: ioremap wcnss physical failed\n", __func__);
goto fail_ioremap;
}
@@ -2818,7 +2878,7 @@
"riva_ccu_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource riva_ccu_base failed\n",
+ wcnss_log(ERR, "%s: resource riva_ccu_base failed\n",
__func__);
goto fail_ioremap;
}
@@ -2827,7 +2887,7 @@
if (!penv->riva_ccu_base) {
ret = -ENOMEM;
- pr_err("%s: ioremap riva ccu physical failed\n",
+ wcnss_log(ERR, "%s: ioremap riva ccu physical failed\n",
__func__);
goto fail_ioremap;
}
@@ -2837,7 +2897,7 @@
"pronto_a2xb_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource pronto_a2xb_base failed\n",
+ wcnss_log(ERR, "%s: resource pronto_a2xb_base failed\n",
__func__);
goto fail_ioremap;
}
@@ -2846,8 +2906,8 @@
if (!penv->pronto_a2xb_base) {
ret = -ENOMEM;
- pr_err("%s: ioremap pronto a2xb physical failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: ioremap pronto a2xb physical failed\n", __func__);
goto fail_ioremap;
}
@@ -2856,7 +2916,7 @@
"pronto_ccpu_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource pronto_ccpu_base failed\n",
+ wcnss_log(ERR, "%s: resource pronto_ccpu_base failed\n",
__func__);
goto fail_ioremap;
}
@@ -2865,8 +2925,8 @@
if (!penv->pronto_ccpu_base) {
ret = -ENOMEM;
- pr_err("%s: ioremap pronto ccpu physical failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: ioremap pronto ccpu physical failed\n", __func__);
goto fail_ioremap;
}
@@ -2874,14 +2934,15 @@
res = platform_get_resource_byname(penv->pdev,
IORESOURCE_MEM, "wcnss_fiq");
if (!res) {
- dev_err(&pdev->dev, "insufficient irq mem resources\n");
+ wcnss_log(ERR, "insufficient irq mem resources\n");
ret = -ENOENT;
goto fail_ioremap;
}
penv->fiq_reg = ioremap_nocache(res->start, resource_size(res));
if (!penv->fiq_reg) {
- pr_err("wcnss: %s: ioremap_nocache() failed fiq_reg addr:%pr\n",
- __func__, &res->start);
+ wcnss_log(ERR, "%s", __func__,
+ "ioremap_nocache() failed fiq_reg addr:%pr\n",
+ &res->start);
ret = -ENOMEM;
goto fail_ioremap;
}
@@ -2891,7 +2952,7 @@
"pronto_saw2_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource pronto_saw2_base failed\n",
+ wcnss_log(ERR, "%s: resource pronto_saw2_base failed\n",
__func__);
goto fail_ioremap2;
}
@@ -2899,8 +2960,8 @@
devm_ioremap_resource(&pdev->dev, res);
if (!penv->pronto_saw2_base) {
- pr_err("%s: ioremap wcnss physical(saw2) failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: ioremap wcnss physical(saw2) failed\n", __func__);
ret = -ENOMEM;
goto fail_ioremap2;
}
@@ -2908,8 +2969,8 @@
penv->pronto_pll_base =
penv->msm_wcnss_base + PRONTO_PLL_MODE_OFFSET;
if (!penv->pronto_pll_base) {
- pr_err("%s: ioremap wcnss physical(pll) failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: ioremap wcnss physical(pll) failed\n", __func__);
ret = -ENOMEM;
goto fail_ioremap2;
}
@@ -2919,8 +2980,8 @@
"wlan_tx_phy_aborts");
if (!res) {
ret = -EIO;
- pr_err("%s: resource wlan_tx_phy_aborts failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: resource wlan_tx_phy_aborts failed\n", __func__);
goto fail_ioremap2;
}
penv->wlan_tx_phy_aborts =
@@ -2928,7 +2989,8 @@
if (!penv->wlan_tx_phy_aborts) {
ret = -ENOMEM;
- pr_err("%s: ioremap wlan TX PHY failed\n", __func__);
+ wcnss_log(ERR, "%s: ioremap wlan TX PHY failed\n",
+ __func__);
goto fail_ioremap2;
}
@@ -2937,8 +2999,8 @@
"wlan_brdg_err_source");
if (!res) {
ret = -EIO;
- pr_err("%s: resource wlan_brdg_err_source failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: get wlan_brdg_err_source res failed\n", __func__);
goto fail_ioremap2;
}
penv->wlan_brdg_err_source =
@@ -2946,7 +3008,8 @@
if (!penv->wlan_brdg_err_source) {
ret = -ENOMEM;
- pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__);
+ wcnss_log(ERR, "%s: ioremap wlan BRDG ERR failed\n",
+ __func__);
goto fail_ioremap2;
}
@@ -2955,7 +3018,7 @@
"wlan_tx_status");
if (!res) {
ret = -EIO;
- pr_err("%s: resource wlan_tx_status failed\n",
+ wcnss_log(ERR, "%s: resource wlan_tx_status failed\n",
__func__);
goto fail_ioremap2;
}
@@ -2964,7 +3027,8 @@
if (!penv->wlan_tx_status) {
ret = -ENOMEM;
- pr_err("%s: ioremap wlan TX STATUS failed\n", __func__);
+ wcnss_log(ERR, "%s: ioremap wlan TX STATUS failed\n",
+ __func__);
goto fail_ioremap2;
}
@@ -2973,8 +3037,8 @@
"alarms_txctl");
if (!res) {
ret = -EIO;
- pr_err("%s: resource alarms_txctl failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: resource alarms_txctl failed\n", __func__);
goto fail_ioremap2;
}
penv->alarms_txctl =
@@ -2982,7 +3046,8 @@
if (!penv->alarms_txctl) {
ret = -ENOMEM;
- pr_err("%s: ioremap alarms TXCTL failed\n", __func__);
+ wcnss_log(ERR,
+ "%s: ioremap alarms TXCTL failed\n", __func__);
goto fail_ioremap2;
}
@@ -2991,8 +3056,8 @@
"alarms_tactl");
if (!res) {
ret = -EIO;
- pr_err("%s: resource alarms_tactl failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: resource alarms_tactl failed\n", __func__);
goto fail_ioremap2;
}
penv->alarms_tactl =
@@ -3000,7 +3065,8 @@
if (!penv->alarms_tactl) {
ret = -ENOMEM;
- pr_err("%s: ioremap alarms TACTL failed\n", __func__);
+ wcnss_log(ERR,
+ "%s: ioremap alarms TACTL failed\n", __func__);
goto fail_ioremap2;
}
@@ -3009,8 +3075,8 @@
"pronto_mcu_base");
if (!res) {
ret = -EIO;
- pr_err("%s: resource pronto_mcu_base failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: resource pronto_mcu_base failed\n", __func__);
goto fail_ioremap2;
}
penv->pronto_mcu_base =
@@ -3018,8 +3084,8 @@
if (!penv->pronto_mcu_base) {
ret = -ENOMEM;
- pr_err("%s: ioremap pronto mcu physical failed\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: ioremap pronto mcu physical failed\n", __func__);
goto fail_ioremap2;
}
@@ -3027,8 +3093,8 @@
"qcom,is-dual-band-disabled")) {
ret = wcnss_get_dual_band_capability_info(pdev);
if (ret) {
- pr_err("%s: failed to get dual band info\n",
- __func__);
+ wcnss_log(ERR,
+ "%s: failed to get dual band info\n", __func__);
goto fail_ioremap2;
}
}
@@ -3036,7 +3102,7 @@
penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss");
if (IS_ERR(penv->adc_tm_dev)) {
- pr_err("%s: adc get failed\n", __func__);
+ wcnss_log(ERR, "%s: adc get failed\n", __func__);
penv->adc_tm_dev = NULL;
} else {
INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt);
@@ -3045,14 +3111,14 @@
penv->snoc_wcnss = devm_clk_get(&penv->pdev->dev, "snoc_wcnss");
if (IS_ERR(penv->snoc_wcnss)) {
- pr_err("%s: couldn't get snoc_wcnss\n", __func__);
+ wcnss_log(ERR, "%s: couldn't get snoc_wcnss\n", __func__);
penv->snoc_wcnss = NULL;
} else {
if (of_property_read_u32(pdev->dev.of_node,
"qcom,snoc-wcnss-clock-freq",
&penv->snoc_wcnss_clock_freq)) {
- pr_debug("%s: wcnss snoc clock frequency is not defined\n",
- __func__);
+ wcnss_log(DBG,
+ "%s: snoc clock frequency is not defined\n", __func__);
devm_clk_put(&penv->pdev->dev, penv->snoc_wcnss);
penv->snoc_wcnss = NULL;
}
@@ -3062,7 +3128,7 @@
penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss");
if (IS_ERR(penv->vadc_dev)) {
- pr_debug("%s: vadc get failed\n", __func__);
+ wcnss_log(DBG, "%s: vadc get failed\n", __func__);
penv->vadc_dev = NULL;
} else {
rc = wcnss_get_battery_volt(&penv->wlan_config.vbatt);
@@ -3070,8 +3136,8 @@
wcnss_send_vbatt_indication);
if (rc < 0)
- pr_err("Failed to get battery voltage with error= %d\n",
- rc);
+ wcnss_log(ERR,
+ "battery voltage get failed:err=%d\n", rc);
}
}
@@ -3079,7 +3145,7 @@
/* trigger initialization of the WCNSS */
penv->pil = subsystem_get(WCNSS_PIL_DEVICE);
if (IS_ERR(penv->pil)) {
- dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n");
+ wcnss_log(ERR, "Peripheral Loader failed on WCNSS.\n");
ret = PTR_ERR(penv->pil);
wcnss_disable_pc_add_req();
wcnss_pronto_log_debug_regs();
@@ -3129,7 +3195,7 @@
int rc;
if (!penv->snoc_wcnss) {
- pr_err("%s: couldn't get clk snoc_wcnss\n", __func__);
+ wcnss_log(ERR, "%s: couldn't get clk snoc_wcnss\n", __func__);
return;
}
@@ -3137,13 +3203,15 @@
rc = clk_set_rate(penv->snoc_wcnss,
penv->snoc_wcnss_clock_freq);
if (rc) {
- pr_err("%s: snoc_wcnss_clk-clk_set_rate failed =%d\n",
- __func__, rc);
+ wcnss_log(ERR,
+ "%s: snoc_wcnss_clk-clk_set_rate failed=%d\n",
+ __func__, rc);
return;
}
if (clk_prepare_enable(penv->snoc_wcnss)) {
- pr_err("%s: snoc_wcnss clk enable failed\n", __func__);
+ wcnss_log(ERR, "%s: snoc_wcnss clk enable failed\n",
+ __func__);
return;
}
} else {
@@ -3219,7 +3287,7 @@
return -EFAULT;
if (!penv->triggered) {
- pr_info(DEVICE " triggered by userspace\n");
+ wcnss_log(INFO, DEVICE " triggered by userspace\n");
pdev = penv->pdev;
rc = wcnss_trigger_config(pdev);
if (rc)
@@ -3282,8 +3350,8 @@
user_buffer, 4);
if (!penv->user_cal_exp_size ||
penv->user_cal_exp_size > MAX_CALIBRATED_DATA_SIZE) {
- pr_err(DEVICE " invalid size to write %d\n",
- penv->user_cal_exp_size);
+ wcnss_log(ERR, DEVICE " invalid size to write %d\n",
+ penv->user_cal_exp_size);
penv->user_cal_exp_size = 0;
mutex_unlock(&penv->dev_lock);
return -EFAULT;
@@ -3297,8 +3365,8 @@
mutex_lock(&penv->dev_lock);
if ((UINT32_MAX - count < penv->user_cal_rcvd) ||
(penv->user_cal_exp_size < count + penv->user_cal_rcvd)) {
- pr_err(DEVICE " invalid size to write %zu\n", count +
- penv->user_cal_rcvd);
+ wcnss_log(ERR, DEVICE " invalid size to write %zu\n",
+ count + penv->user_cal_rcvd);
mutex_unlock(&penv->dev_lock);
return -ENOMEM;
}
@@ -3320,7 +3388,7 @@
kfree(cal_data);
if (penv->user_cal_rcvd == penv->user_cal_exp_size) {
penv->user_cal_available = true;
- pr_info_ratelimited("wcnss: user cal written");
+ wcnss_log(INFO, "user cal written");
}
mutex_unlock(&penv->dev_lock);
@@ -3342,12 +3410,12 @@
if (!(code >= SUBSYS_NOTIF_MIN_INDEX) &&
(code <= SUBSYS_NOTIF_MAX_INDEX)) {
- pr_debug("%s: Invaild subsystem notification code: %lu\n",
- __func__, code);
+ wcnss_log(DBG, "%s: Invaild subsystem notification code: %lu\n",
+ __func__, code);
return NOTIFY_DONE;
}
- pr_info("%s: wcnss notification event: %lu : %s\n",
+ wcnss_log(INFO, "%s: notification event: %lu : %s\n",
__func__, code, wcnss_subsys_notif_type[code]);
if (code == SUBSYS_PROXY_VOTE) {
@@ -3356,7 +3424,7 @@
WCNSS_WLAN_SWITCH_ON, &xo_mode);
wcnss_set_iris_xo_mode(xo_mode);
if (ret)
- pr_err("Failed to execute wcnss_wlan_power\n");
+ wcnss_log(ERR, "wcnss_wlan_power failed\n");
}
} else if (code == SUBSYS_PROXY_UNVOTE) {
if (pdev && pwlanconfig) {
@@ -3407,30 +3475,30 @@
ret = alloc_chrdev_region(&penv->dev_ctrl, 0, 1, CTRL_DEVICE);
if (ret < 0) {
- dev_err(&pdev->dev, "CTRL Device Registration failed\n");
+ wcnss_log(ERR, "CTRL Device Registration failed\n");
goto alloc_region_ctrl;
}
ret = alloc_chrdev_region(&penv->dev_node, 0, 1, DEVICE);
if (ret < 0) {
- dev_err(&pdev->dev, "NODE Device Registration failed\n");
+ wcnss_log(ERR, "NODE Device Registration failed\n");
goto alloc_region_node;
}
penv->node_class = class_create(THIS_MODULE, "wcnss");
if (!penv->node_class) {
- dev_err(&pdev->dev, "NODE Device Class Creation failed\n");
+ wcnss_log(ERR, "NODE Device Class Creation failed\n");
goto class_create_node;
}
if (device_create(penv->node_class, NULL, penv->dev_ctrl, NULL,
CTRL_DEVICE) == NULL) {
- dev_err(&pdev->dev, "CTRL Device Creation failed\n");
+ wcnss_log(ERR, "CTRL Device Creation failed\n");
goto device_create_ctrl;
}
if (device_create(penv->node_class, NULL, penv->dev_node, NULL,
DEVICE) == NULL) {
- dev_err(&pdev->dev, "NODE Device Creation failed\n");
+ wcnss_log(ERR, "NODE Device Creation failed\n");
goto device_create_node;
}
@@ -3438,11 +3506,11 @@
cdev_init(&penv->node_dev, &wcnss_node_fops);
if (cdev_add(&penv->ctrl_dev, penv->dev_ctrl, 1) == -1) {
- dev_err(&pdev->dev, "CTRL Device addition failed\n");
+ wcnss_log(ERR, "CTRL Device addition failed\n");
goto cdev_add_ctrl;
}
if (cdev_add(&penv->node_dev, penv->dev_node, 1) == -1) {
- dev_err(&pdev->dev, "NODE Device addition failed\n");
+ wcnss_log(ERR, "NODE Device addition failed\n");
goto cdev_add_node;
}
@@ -3466,7 +3534,7 @@
static void wcnss_cdev_unregister(struct platform_device *pdev)
{
- dev_err(&pdev->dev, "Unregistering cdev devices\n");
+ wcnss_log(ERR, "Unregistering cdev devices\n");
cdev_del(&penv->ctrl_dev);
cdev_del(&penv->node_dev);
device_destroy(penv->node_class, penv->dev_ctrl);
@@ -3483,7 +3551,7 @@
/* verify we haven't been called more than once */
if (penv) {
- dev_err(&pdev->dev, "cannot handle multiple devices.\n");
+ wcnss_log(ERR, "cannot handle multiple devices.\n");
return -ENODEV;
}
@@ -3497,7 +3565,7 @@
penv->user_cal_data =
devm_kzalloc(&pdev->dev, MAX_CALIBRATED_DATA_SIZE, GFP_KERNEL);
if (!penv->user_cal_data) {
- dev_err(&pdev->dev, "Failed to alloc memory for cal data.\n");
+ wcnss_log(ERR, "Failed to alloc memory for cal data.\n");
return -ENOMEM;
}
@@ -3511,7 +3579,7 @@
/* register wcnss event notification */
penv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb);
if (IS_ERR(penv->wcnss_notif_hdle)) {
- pr_err("wcnss: register event notification failed!\n");
+ wcnss_log(ERR, "register event notification failed!\n");
return PTR_ERR(penv->wcnss_notif_hdle);
}
@@ -3534,7 +3602,7 @@
* device so that we know that WCNSS configuration can take
* place
*/
- pr_info(DEVICE " probed in built-in mode\n");
+ wcnss_log(INFO, DEVICE " probed in built-in mode\n");
return wcnss_cdev_register(pdev);
}
@@ -3579,6 +3647,11 @@
static int __init wcnss_wlan_init(void)
{
+
+ wcnss_ipc_log = ipc_log_context_create(IPC_NUM_LOG_PAGES, "wcnss", 0);
+ if (!wcnss_ipc_log)
+ wcnss_log(ERR, "Unable to create log context\n");
+
platform_driver_register(&wcnss_wlan_driver);
platform_driver_register(&wcnss_wlan_ctrl_driver);
platform_driver_register(&wcnss_ctrl_driver);
@@ -3599,6 +3672,8 @@
platform_driver_unregister(&wcnss_ctrl_driver);
platform_driver_unregister(&wcnss_wlan_ctrl_driver);
platform_driver_unregister(&wcnss_wlan_driver);
+ ipc_log_context_destroy(wcnss_ipc_log);
+ wcnss_ipc_log = NULL;
}
module_init(wcnss_wlan_init);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 6ee1da0..fc96f62 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -156,7 +156,6 @@
config SPI_BCM_QSPI
tristate "Broadcom BSPI and MSPI controller support"
depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST
- depends on MTD_NORFLASH
default ARCH_BCM_IPROC
help
Enables support for the Broadcom SPI flash and MSPI controller.
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index 02fb967..0d8f43a 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.c
@@ -646,7 +646,7 @@
buf = t->rx_buf;
t->rx_dma = dma_map_single(&spi->dev, buf,
t->len, DMA_FROM_DEVICE);
- if (dma_mapping_error(&spi->dev, !t->rx_dma)) {
+ if (dma_mapping_error(&spi->dev, t->rx_dma)) {
ret = -EFAULT;
goto err_rx_map;
}
diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c
index a074763..dfa387c 100644
--- a/drivers/spi/spi-geni-qcom.c
+++ b/drivers/spi/spi-geni-qcom.c
@@ -356,9 +356,6 @@
if (mode & SPI_CPHA)
flags |= GSI_CPHA;
- if (xfer->cs_change)
- flags |= GSI_CS_TOGGLE;
-
word_len = xfer->bits_per_word - MIN_WORD_LEN;
pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN);
ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div);
@@ -586,8 +583,11 @@
}
cs |= spi_slv->chip_select;
- if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
- go_flags |= FRAGMENTATION;
+ if (!xfer->cs_change) {
+ if (!list_is_last(&xfer->transfer_list,
+ &spi->cur_msg->transfers))
+ go_flags |= FRAGMENTATION;
+ }
go_tre = setup_go_tre(cmd, cs, rx_len, go_flags, mas);
sg_init_table(xfer_tx_sg, tx_nent);
@@ -940,8 +940,6 @@
m_cmd = SPI_RX_ONLY;
spi_tx_cfg &= ~CS_TOGGLE;
- if (xfer->cs_change)
- spi_tx_cfg |= CS_TOGGLE;
if (!(mas->cur_word_len % MIN_WORD_LEN)) {
trans_len =
((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK;
@@ -950,8 +948,12 @@
trans_len = (xfer->len / bytes_per_word) & TRANS_LEN_MSK;
}
- if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers))
- m_param |= FRAGMENTATION;
+
+ if (!xfer->cs_change) {
+ if (!list_is_last(&xfer->transfer_list,
+ &spi->cur_msg->transfers))
+ m_param |= FRAGMENTATION;
+ }
mas->cur_xfer = xfer;
if (m_cmd & SPI_TX_ONLY) {
@@ -966,8 +968,9 @@
geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG);
geni_setup_m_cmd(mas->base, m_cmd, m_param);
GENI_SE_DBG(mas->ipc, false, mas->dev,
- "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x\n",
- __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd);
+ "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs %d\n",
+ __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd,
+ xfer->cs_change);
if (m_cmd & SPI_TX_ONLY)
geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG);
/* Ensure all writes are done before the WM interrupt */
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 6db8063..c2e85e2 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -743,8 +743,14 @@
for (i = 0; i < sgs; i++) {
if (vmalloced_buf || kmap_buf) {
- min = min_t(size_t,
- len, desc_len - offset_in_page(buf));
+ /*
+ * Next scatterlist entry size is the minimum between
+ * the desc_len and the remaining buffer length that
+ * fits in a page.
+ */
+ min = min_t(size_t, desc_len,
+ min_t(size_t, len,
+ PAGE_SIZE - offset_in_page(buf)));
if (vmalloced_buf)
vm_page = vmalloc_to_page(buf);
else
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 7bd27a4..a17c483 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -33,6 +33,15 @@
/sys/module/lowmemorykiller/parameters/adj and convert them
to oom_score_adj values.
+config ANDROID_VSOC
+ tristate "Android Virtual SoC support"
+ default n
+ depends on PCI_MSI
+ ---help---
+ This option adds support for the Virtual SoC driver needed to boot
+ a 'cuttlefish' Android image inside QEmu. The driver interacts with
+ a QEmu ivshmem device. If built as a module, it will be called vsoc.
+
source "drivers/staging/android/ion/Kconfig"
source "drivers/staging/android/fiq_debugger/Kconfig"
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 21b0ff4..93c5f5a 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -5,3 +5,4 @@
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
+obj-$(CONFIG_ANDROID_VSOC) += vsoc.o
diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO
index 64d8c87..dd64148 100644
--- a/drivers/staging/android/TODO
+++ b/drivers/staging/android/TODO
@@ -33,5 +33,15 @@
- clean up and ABI check for security issues
- move it to drivers/base/dma-buf
+vsoc.c, uapi/vsoc_shm.h
+ - The current driver uses the same wait queue for all of the futexes in a
+ region. This will cause false wakeups in regions with a large number of
+ waiting threads. We should eventually use multiple queues and select the
+ queue based on the region.
+ - Add debugfs support for examining the permissions of regions.
+ - Use ioremap_wc instead of ioremap_nocache.
+ - Remove VSOC_WAIT_FOR_INCOMING_INTERRUPT ioctl. This functionality has been
+ superseded by the futex and is there for legacy reasons.
+
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:
Arve Hjønnevåg <arve@android.com> and Riley Andrews <riandrews@android.com>
diff --git a/drivers/staging/android/uapi/vsoc_shm.h b/drivers/staging/android/uapi/vsoc_shm.h
new file mode 100644
index 0000000..741b138
--- /dev/null
+++ b/drivers/staging/android/uapi/vsoc_shm.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _UAPI_LINUX_VSOC_SHM_H
+#define _UAPI_LINUX_VSOC_SHM_H
+
+#include <linux/types.h>
+
+/**
+ * A permission is a token that permits a receiver to read and/or write an area
+ * of memory within a Vsoc region.
+ *
+ * An fd_scoped permission grants both read and write access, and can be
+ * attached to a file description (see open(2)).
+ * Ownership of the area can then be shared by passing a file descriptor
+ * among processes.
+ *
+ * begin_offset and end_offset define the area of memory that is controlled by
+ * the permission. owner_offset points to a word, also in shared memory, that
+ * controls ownership of the area.
+ *
+ * ownership of the region expires when the associated file description is
+ * released.
+ *
+ * At most one permission can be attached to each file description.
+ *
+ * This is useful when implementing HALs like gralloc that scope and pass
+ * ownership of shared resources via file descriptors.
+ *
+ * The caller is responsibe for doing any fencing.
+ *
+ * The calling process will normally identify a currently free area of
+ * memory. It will construct a proposed fd_scoped_permission_arg structure:
+ *
+ * begin_offset and end_offset describe the area being claimed
+ *
+ * owner_offset points to the location in shared memory that indicates the
+ * owner of the area.
+ *
+ * owned_value is the value that will be stored in owner_offset iff the
+ * permission can be granted. It must be different than VSOC_REGION_FREE.
+ *
+ * Two fd_scoped_permission structures are compatible if they vary only by
+ * their owned_value fields.
+ *
+ * The driver ensures that, for any group of simultaneous callers proposing
+ * compatible fd_scoped_permissions, it will accept exactly one of the
+ * propopsals. The other callers will get a failure with errno of EAGAIN.
+ *
+ * A process receiving a file descriptor can identify the region being
+ * granted using the VSOC_GET_FD_SCOPED_PERMISSION ioctl.
+ */
+struct fd_scoped_permission {
+ __u32 begin_offset;
+ __u32 end_offset;
+ __u32 owner_offset;
+ __u32 owned_value;
+};
+
+/*
+ * This value represents a free area of memory. The driver expects to see this
+ * value at owner_offset when creating a permission otherwise it will not do it,
+ * and will write this value back once the permission is no longer needed.
+ */
+#define VSOC_REGION_FREE ((__u32)0)
+
+/**
+ * ioctl argument for VSOC_CREATE_FD_SCOPE_PERMISSION
+ */
+struct fd_scoped_permission_arg {
+ struct fd_scoped_permission perm;
+ __s32 managed_region_fd;
+};
+
+#define VSOC_NODE_FREE ((__u32)0)
+
+/*
+ * Describes a signal table in shared memory. Each non-zero entry in the
+ * table indicates that the receiver should signal the futex at the given
+ * offset. Offsets are relative to the region, not the shared memory window.
+ *
+ * interrupt_signalled_offset is used to reliably signal interrupts across the
+ * vmm boundary. There are two roles: transmitter and receiver. For example,
+ * in the host_to_guest_signal_table the host is the transmitter and the
+ * guest is the receiver. The protocol is as follows:
+ *
+ * 1. The transmitter should convert the offset of the futex to an offset
+ * in the signal table [0, (1 << num_nodes_lg2))
+ * The transmitter can choose any appropriate hashing algorithm, including
+ * hash = futex_offset & ((1 << num_nodes_lg2) - 1)
+ *
+ * 3. The transmitter should atomically compare and swap futex_offset with 0
+ * at hash. There are 3 possible outcomes
+ * a. The swap fails because the futex_offset is already in the table.
+ * The transmitter should stop.
+ * b. Some other offset is in the table. This is a hash collision. The
+ * transmitter should move to another table slot and try again. One
+ * possible algorithm:
+ * hash = (hash + 1) & ((1 << num_nodes_lg2) - 1)
+ * c. The swap worked. Continue below.
+ *
+ * 3. The transmitter atomically swaps 1 with the value at the
+ * interrupt_signalled_offset. There are two outcomes:
+ * a. The prior value was 1. In this case an interrupt has already been
+ * posted. The transmitter is done.
+ * b. The prior value was 0, indicating that the receiver may be sleeping.
+ * The transmitter will issue an interrupt.
+ *
+ * 4. On waking the receiver immediately exchanges a 0 with the
+ * interrupt_signalled_offset. If it receives a 0 then this a spurious
+ * interrupt. That may occasionally happen in the current protocol, but
+ * should be rare.
+ *
+ * 5. The receiver scans the signal table by atomicaly exchanging 0 at each
+ * location. If a non-zero offset is returned from the exchange the
+ * receiver wakes all sleepers at the given offset:
+ * futex((int*)(region_base + old_value), FUTEX_WAKE, MAX_INT);
+ *
+ * 6. The receiver thread then does a conditional wait, waking immediately
+ * if the value at interrupt_signalled_offset is non-zero. This catches cases
+ * here additional signals were posted while the table was being scanned.
+ * On the guest the wait is handled via the VSOC_WAIT_FOR_INCOMING_INTERRUPT
+ * ioctl.
+ */
+struct vsoc_signal_table_layout {
+ /* log_2(Number of signal table entries) */
+ __u32 num_nodes_lg2;
+ /*
+ * Offset to the first signal table entry relative to the start of the
+ * region
+ */
+ __u32 futex_uaddr_table_offset;
+ /*
+ * Offset to an atomic_t / atomic uint32_t. A non-zero value indicates
+ * that one or more offsets are currently posted in the table.
+ * semi-unique access to an entry in the table
+ */
+ __u32 interrupt_signalled_offset;
+};
+
+#define VSOC_REGION_WHOLE ((__s32)0)
+#define VSOC_DEVICE_NAME_SZ 16
+
+/**
+ * Each HAL would (usually) talk to a single device region
+ * Mulitple entities care about these regions:
+ * - The ivshmem_server will populate the regions in shared memory
+ * - The guest kernel will read the region, create minor device nodes, and
+ * allow interested parties to register for FUTEX_WAKE events in the region
+ * - HALs will access via the minor device nodes published by the guest kernel
+ * - Host side processes will access the region via the ivshmem_server:
+ * 1. Pass name to ivshmem_server at a UNIX socket
+ * 2. ivshmemserver will reply with 2 fds:
+ * - host->guest doorbell fd
+ * - guest->host doorbell fd
+ * - fd for the shared memory region
+ * - region offset
+ * 3. Start a futex receiver thread on the doorbell fd pointed at the
+ * signal_nodes
+ */
+struct vsoc_device_region {
+ __u16 current_version;
+ __u16 min_compatible_version;
+ __u32 region_begin_offset;
+ __u32 region_end_offset;
+ __u32 offset_of_region_data;
+ struct vsoc_signal_table_layout guest_to_host_signal_table;
+ struct vsoc_signal_table_layout host_to_guest_signal_table;
+ /* Name of the device. Must always be terminated with a '\0', so
+ * the longest supported device name is 15 characters.
+ */
+ char device_name[VSOC_DEVICE_NAME_SZ];
+ /* There are two ways that permissions to access regions are handled:
+ * - When subdivided_by is VSOC_REGION_WHOLE, any process that can
+ * open the device node for the region gains complete access to it.
+ * - When subdivided is set processes that open the region cannot
+ * access it. Access to a sub-region must be established by invoking
+ * the VSOC_CREATE_FD_SCOPE_PERMISSION ioctl on the region
+ * referenced in subdivided_by, providing a fileinstance
+ * (represented by a fd) opened on this region.
+ */
+ __u32 managed_by;
+};
+
+/*
+ * The vsoc layout descriptor.
+ * The first 4K should be reserved for the shm header and region descriptors.
+ * The regions should be page aligned.
+ */
+
+struct vsoc_shm_layout_descriptor {
+ __u16 major_version;
+ __u16 minor_version;
+
+ /* size of the shm. This may be redundant but nice to have */
+ __u32 size;
+
+ /* number of shared memory regions */
+ __u32 region_count;
+
+ /* The offset to the start of region descriptors */
+ __u32 vsoc_region_desc_offset;
+};
+
+/*
+ * This specifies the current version that should be stored in
+ * vsoc_shm_layout_descriptor.major_version and
+ * vsoc_shm_layout_descriptor.minor_version.
+ * It should be updated only if the vsoc_device_region and
+ * vsoc_shm_layout_descriptor structures have changed.
+ * Versioning within each region is transferred
+ * via the min_compatible_version and current_version fields in
+ * vsoc_device_region. The driver does not consult these fields: they are left
+ * for the HALs and host processes and will change independently of the layout
+ * version.
+ */
+#define CURRENT_VSOC_LAYOUT_MAJOR_VERSION 2
+#define CURRENT_VSOC_LAYOUT_MINOR_VERSION 0
+
+#define VSOC_CREATE_FD_SCOPED_PERMISSION \
+ _IOW(0xF5, 0, struct fd_scoped_permission)
+#define VSOC_GET_FD_SCOPED_PERMISSION _IOR(0xF5, 1, struct fd_scoped_permission)
+
+/*
+ * This is used to signal the host to scan the guest_to_host_signal_table
+ * for new futexes to wake. This sends an interrupt if one is not already
+ * in flight.
+ */
+#define VSOC_MAYBE_SEND_INTERRUPT_TO_HOST _IO(0xF5, 2)
+
+/*
+ * When this returns the guest will scan host_to_guest_signal_table to
+ * check for new futexes to wake.
+ */
+/* TODO(ghartman): Consider moving this to the bottom half */
+#define VSOC_WAIT_FOR_INCOMING_INTERRUPT _IO(0xF5, 3)
+
+/*
+ * Guest HALs will use this to retrieve the region description after
+ * opening their device node.
+ */
+#define VSOC_DESCRIBE_REGION _IOR(0xF5, 4, struct vsoc_device_region)
+
+/*
+ * Wake any threads that may be waiting for a host interrupt on this region.
+ * This is mostly used during shutdown.
+ */
+#define VSOC_SELF_INTERRUPT _IO(0xF5, 5)
+
+/*
+ * This is used to signal the host to scan the guest_to_host_signal_table
+ * for new futexes to wake. This sends an interrupt unconditionally.
+ */
+#define VSOC_SEND_INTERRUPT_TO_HOST _IO(0xF5, 6)
+
+enum wait_types {
+ VSOC_WAIT_UNDEFINED = 0,
+ VSOC_WAIT_IF_EQUAL = 1,
+ VSOC_WAIT_IF_EQUAL_TIMEOUT = 2
+};
+
+/*
+ * Wait for a condition to be true
+ *
+ * Note, this is sized and aligned so the 32 bit and 64 bit layouts are
+ * identical.
+ */
+struct vsoc_cond_wait {
+ /* Input: Offset of the 32 bit word to check */
+ __u32 offset;
+ /* Input: Value that will be compared with the offset */
+ __u32 value;
+ /* Monotonic time to wake at in seconds */
+ __u64 wake_time_sec;
+ /* Input: Monotonic time to wait in nanoseconds */
+ __u32 wake_time_nsec;
+ /* Input: Type of wait */
+ __u32 wait_type;
+ /* Output: Number of times the thread woke before returning. */
+ __u32 wakes;
+ /* Ensure that we're 8-byte aligned and 8 byte length for 32/64 bit
+ * compatibility.
+ */
+ __u32 reserved_1;
+};
+
+#define VSOC_COND_WAIT _IOWR(0xF5, 7, struct vsoc_cond_wait)
+
+/* Wake any local threads waiting at the offset given in arg */
+#define VSOC_COND_WAKE _IO(0xF5, 8)
+
+#endif /* _UAPI_LINUX_VSOC_SHM_H */
diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c
new file mode 100644
index 0000000..587c66d7
--- /dev/null
+++ b/drivers/staging/android/vsoc.c
@@ -0,0 +1,1169 @@
+/*
+ * drivers/android/staging/vsoc.c
+ *
+ * Android Virtual System on a Chip (VSoC) driver
+ *
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * Author: ghartman@google.com
+ *
+ * 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.
+ *
+ *
+ * Based on drivers/char/kvm_ivshmem.c - driver for KVM Inter-VM shared memory
+ * Copyright 2009 Cam Macdonell <cam@cs.ualberta.ca>
+ *
+ * Based on cirrusfb.c and 8139cp.c:
+ * Copyright 1999-2001 Jeff Garzik
+ * Copyright 2001-2004 Jeff Garzik
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/freezer.h>
+#include <linux/futex.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/cdev.h>
+#include <linux/file.h>
+#include "uapi/vsoc_shm.h"
+
+#define VSOC_DEV_NAME "vsoc"
+
+/*
+ * Description of the ivshmem-doorbell PCI device used by QEmu. These
+ * constants follow docs/specs/ivshmem-spec.txt, which can be found in
+ * the QEmu repository. This was last reconciled with the version that
+ * came out with 2.8
+ */
+
+/*
+ * These constants are determined KVM Inter-VM shared memory device
+ * register offsets
+ */
+enum {
+ INTR_MASK = 0x00, /* Interrupt Mask */
+ INTR_STATUS = 0x04, /* Interrupt Status */
+ IV_POSITION = 0x08, /* VM ID */
+ DOORBELL = 0x0c, /* Doorbell */
+};
+
+static const int REGISTER_BAR; /* Equal to 0 */
+static const int MAX_REGISTER_BAR_LEN = 0x100;
+/*
+ * The MSI-x BAR is not used directly.
+ *
+ * static const int MSI_X_BAR = 1;
+ */
+static const int SHARED_MEMORY_BAR = 2;
+
+struct vsoc_region_data {
+ char name[VSOC_DEVICE_NAME_SZ + 1];
+ wait_queue_head_t interrupt_wait_queue;
+ /* TODO(b/73664181): Use multiple futex wait queues */
+ wait_queue_head_t futex_wait_queue;
+ /* Flag indicating that an interrupt has been signalled by the host. */
+ atomic_t *incoming_signalled;
+ /* Flag indicating the guest has signalled the host. */
+ atomic_t *outgoing_signalled;
+ int irq_requested;
+ int device_created;
+};
+
+struct vsoc_device {
+ /* Kernel virtual address of REGISTER_BAR. */
+ void __iomem *regs;
+ /* Physical address of SHARED_MEMORY_BAR. */
+ phys_addr_t shm_phys_start;
+ /* Kernel virtual address of SHARED_MEMORY_BAR. */
+ void *kernel_mapped_shm;
+ /* Size of the entire shared memory window in bytes. */
+ size_t shm_size;
+ /*
+ * Pointer to the virtual address of the shared memory layout structure.
+ * This is probably identical to kernel_mapped_shm, but saving this
+ * here saves a lot of annoying casts.
+ */
+ struct vsoc_shm_layout_descriptor *layout;
+ /*
+ * Points to a table of region descriptors in the kernel's virtual
+ * address space. Calculated from
+ * vsoc_shm_layout_descriptor.vsoc_region_desc_offset
+ */
+ struct vsoc_device_region *regions;
+ /* Head of a list of permissions that have been granted. */
+ struct list_head permissions;
+ struct pci_dev *dev;
+ /* Per-region (and therefore per-interrupt) information. */
+ struct vsoc_region_data *regions_data;
+ /*
+ * Table of msi-x entries. This has to be separated from struct
+ * vsoc_region_data because the kernel deals with them as an array.
+ */
+ struct msix_entry *msix_entries;
+ /*
+ * Flags that indicate what we've initialzied. These are used to do an
+ * orderly cleanup of the device.
+ */
+ char enabled_device;
+ char requested_regions;
+ char cdev_added;
+ char class_added;
+ char msix_enabled;
+ /* Mutex that protectes the permission list */
+ struct mutex mtx;
+ /* Major number assigned by the kernel */
+ int major;
+
+ struct cdev cdev;
+ struct class *class;
+};
+
+static struct vsoc_device vsoc_dev;
+
+/*
+ * TODO(ghartman): Add a /sys filesystem entry that summarizes the permissions.
+ */
+
+struct fd_scoped_permission_node {
+ struct fd_scoped_permission permission;
+ struct list_head list;
+};
+
+struct vsoc_private_data {
+ struct fd_scoped_permission_node *fd_scoped_permission_node;
+};
+
+static long vsoc_ioctl(struct file *, unsigned int, unsigned long);
+static int vsoc_mmap(struct file *, struct vm_area_struct *);
+static int vsoc_open(struct inode *, struct file *);
+static int vsoc_release(struct inode *, struct file *);
+static ssize_t vsoc_read(struct file *, char *, size_t, loff_t *);
+static ssize_t vsoc_write(struct file *, const char *, size_t, loff_t *);
+static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin);
+static int do_create_fd_scoped_permission(
+ struct vsoc_device_region *region_p,
+ struct fd_scoped_permission_node *np,
+ struct fd_scoped_permission_arg *__user arg);
+static void do_destroy_fd_scoped_permission(
+ struct vsoc_device_region *owner_region_p,
+ struct fd_scoped_permission *perm);
+static long do_vsoc_describe_region(struct file *,
+ struct vsoc_device_region __user *);
+static ssize_t vsoc_get_area(struct file *filp, __u32 *perm_off);
+
+/**
+ * Validate arguments on entry points to the driver.
+ */
+inline int vsoc_validate_inode(struct inode *inode)
+{
+ if (iminor(inode) >= vsoc_dev.layout->region_count) {
+ dev_err(&vsoc_dev.dev->dev,
+ "describe_region: invalid region %d\n", iminor(inode));
+ return -ENODEV;
+ }
+ return 0;
+}
+
+inline int vsoc_validate_filep(struct file *filp)
+{
+ int ret = vsoc_validate_inode(file_inode(filp));
+
+ if (ret)
+ return ret;
+ if (!filp->private_data) {
+ dev_err(&vsoc_dev.dev->dev,
+ "No private data on fd, region %d\n",
+ iminor(file_inode(filp)));
+ return -EBADFD;
+ }
+ return 0;
+}
+
+/* Converts from shared memory offset to virtual address */
+static inline void *shm_off_to_virtual_addr(__u32 offset)
+{
+ return vsoc_dev.kernel_mapped_shm + offset;
+}
+
+/* Converts from shared memory offset to physical address */
+static inline phys_addr_t shm_off_to_phys_addr(__u32 offset)
+{
+ return vsoc_dev.shm_phys_start + offset;
+}
+
+/**
+ * Convenience functions to obtain the region from the inode or file.
+ * Dangerous to call before validating the inode/file.
+ */
+static inline struct vsoc_device_region *vsoc_region_from_inode(
+ struct inode *inode)
+{
+ return &vsoc_dev.regions[iminor(inode)];
+}
+
+static inline struct vsoc_device_region *vsoc_region_from_filep(
+ struct file *inode)
+{
+ return vsoc_region_from_inode(file_inode(inode));
+}
+
+static inline uint32_t vsoc_device_region_size(struct vsoc_device_region *r)
+{
+ return r->region_end_offset - r->region_begin_offset;
+}
+
+static const struct file_operations vsoc_ops = {
+ .owner = THIS_MODULE,
+ .open = vsoc_open,
+ .mmap = vsoc_mmap,
+ .read = vsoc_read,
+ .unlocked_ioctl = vsoc_ioctl,
+ .compat_ioctl = vsoc_ioctl,
+ .write = vsoc_write,
+ .llseek = vsoc_lseek,
+ .release = vsoc_release,
+};
+
+static struct pci_device_id vsoc_id_table[] = {
+ {0x1af4, 0x1110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0},
+};
+
+MODULE_DEVICE_TABLE(pci, vsoc_id_table);
+
+static void vsoc_remove_device(struct pci_dev *pdev);
+static int vsoc_probe_device(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+
+static struct pci_driver vsoc_pci_driver = {
+ .name = "vsoc",
+ .id_table = vsoc_id_table,
+ .probe = vsoc_probe_device,
+ .remove = vsoc_remove_device,
+};
+
+static int do_create_fd_scoped_permission(
+ struct vsoc_device_region *region_p,
+ struct fd_scoped_permission_node *np,
+ struct fd_scoped_permission_arg *__user arg)
+{
+ struct file *managed_filp;
+ s32 managed_fd;
+ atomic_t *owner_ptr = NULL;
+ struct vsoc_device_region *managed_region_p;
+
+ if (copy_from_user(&np->permission, &arg->perm, sizeof(*np)) ||
+ copy_from_user(&managed_fd,
+ &arg->managed_region_fd, sizeof(managed_fd))) {
+ return -EFAULT;
+ }
+ managed_filp = fdget(managed_fd).file;
+ /* Check that it's a valid fd, */
+ if (!managed_filp || vsoc_validate_filep(managed_filp))
+ return -EPERM;
+ /* EEXIST if the given fd already has a permission. */
+ if (((struct vsoc_private_data *)managed_filp->private_data)->
+ fd_scoped_permission_node)
+ return -EEXIST;
+ managed_region_p = vsoc_region_from_filep(managed_filp);
+ /* Check that the provided region is managed by this one */
+ if (&vsoc_dev.regions[managed_region_p->managed_by] != region_p)
+ return -EPERM;
+ /* The area must be well formed and have non-zero size */
+ if (np->permission.begin_offset >= np->permission.end_offset)
+ return -EINVAL;
+ /* The area must fit in the memory window */
+ if (np->permission.end_offset >
+ vsoc_device_region_size(managed_region_p))
+ return -ERANGE;
+ /* The area must be in the region data section */
+ if (np->permission.begin_offset <
+ managed_region_p->offset_of_region_data)
+ return -ERANGE;
+ /* The area must be page aligned */
+ if (!PAGE_ALIGNED(np->permission.begin_offset) ||
+ !PAGE_ALIGNED(np->permission.end_offset))
+ return -EINVAL;
+ /* Owner offset must be naturally aligned in the window */
+ if (np->permission.owner_offset &
+ (sizeof(np->permission.owner_offset) - 1))
+ return -EINVAL;
+ /* The owner flag must reside in the owner memory */
+ if (np->permission.owner_offset + sizeof(np->permission.owner_offset) >
+ vsoc_device_region_size(region_p))
+ return -ERANGE;
+ /* The owner flag must reside in the data section */
+ if (np->permission.owner_offset < region_p->offset_of_region_data)
+ return -EINVAL;
+ /* The owner value must change to claim the memory */
+ if (np->permission.owned_value == VSOC_REGION_FREE)
+ return -EINVAL;
+ owner_ptr =
+ (atomic_t *)shm_off_to_virtual_addr(region_p->region_begin_offset +
+ np->permission.owner_offset);
+ /* We've already verified that this is in the shared memory window, so
+ * it should be safe to write to this address.
+ */
+ if (atomic_cmpxchg(owner_ptr,
+ VSOC_REGION_FREE,
+ np->permission.owned_value) != VSOC_REGION_FREE) {
+ return -EBUSY;
+ }
+ ((struct vsoc_private_data *)managed_filp->private_data)->
+ fd_scoped_permission_node = np;
+ /* The file offset needs to be adjusted if the calling
+ * process did any read/write operations on the fd
+ * before creating the permission.
+ */
+ if (managed_filp->f_pos) {
+ if (managed_filp->f_pos > np->permission.end_offset) {
+ /* If the offset is beyond the permission end, set it
+ * to the end.
+ */
+ managed_filp->f_pos = np->permission.end_offset;
+ } else {
+ /* If the offset is within the permission interval
+ * keep it there otherwise reset it to zero.
+ */
+ if (managed_filp->f_pos < np->permission.begin_offset) {
+ managed_filp->f_pos = 0;
+ } else {
+ managed_filp->f_pos -=
+ np->permission.begin_offset;
+ }
+ }
+ }
+ return 0;
+}
+
+static void do_destroy_fd_scoped_permission_node(
+ struct vsoc_device_region *owner_region_p,
+ struct fd_scoped_permission_node *node)
+{
+ if (node) {
+ do_destroy_fd_scoped_permission(owner_region_p,
+ &node->permission);
+ mutex_lock(&vsoc_dev.mtx);
+ list_del(&node->list);
+ mutex_unlock(&vsoc_dev.mtx);
+ kfree(node);
+ }
+}
+
+static void do_destroy_fd_scoped_permission(
+ struct vsoc_device_region *owner_region_p,
+ struct fd_scoped_permission *perm)
+{
+ atomic_t *owner_ptr = NULL;
+ int prev = 0;
+
+ if (!perm)
+ return;
+ owner_ptr = (atomic_t *)shm_off_to_virtual_addr(
+ owner_region_p->region_begin_offset + perm->owner_offset);
+ prev = atomic_xchg(owner_ptr, VSOC_REGION_FREE);
+ if (prev != perm->owned_value)
+ dev_err(&vsoc_dev.dev->dev,
+ "%x-%x: owner (%s) %x: expected to be %x was %x",
+ perm->begin_offset, perm->end_offset,
+ owner_region_p->device_name, perm->owner_offset,
+ perm->owned_value, prev);
+}
+
+static long do_vsoc_describe_region(struct file *filp,
+ struct vsoc_device_region __user *dest)
+{
+ struct vsoc_device_region *region_p;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ region_p = vsoc_region_from_filep(filp);
+ if (copy_to_user(dest, region_p, sizeof(*region_p)))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * Implements the inner logic of cond_wait. Copies to and from userspace are
+ * done in the helper function below.
+ */
+static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg)
+{
+ DEFINE_WAIT(wait);
+ u32 region_number = iminor(file_inode(filp));
+ struct vsoc_region_data *data = vsoc_dev.regions_data + region_number;
+ struct hrtimer_sleeper timeout, *to = NULL;
+ int ret = 0;
+ struct vsoc_device_region *region_p = vsoc_region_from_filep(filp);
+ atomic_t *address = NULL;
+ struct timespec ts;
+
+ /* Ensure that the offset is aligned */
+ if (arg->offset & (sizeof(uint32_t) - 1))
+ return -EADDRNOTAVAIL;
+ /* Ensure that the offset is within shared memory */
+ if (((uint64_t)arg->offset) + region_p->region_begin_offset +
+ sizeof(uint32_t) > region_p->region_end_offset)
+ return -E2BIG;
+ address = shm_off_to_virtual_addr(region_p->region_begin_offset +
+ arg->offset);
+
+ /* Ensure that the type of wait is valid */
+ switch (arg->wait_type) {
+ case VSOC_WAIT_IF_EQUAL:
+ break;
+ case VSOC_WAIT_IF_EQUAL_TIMEOUT:
+ to = &timeout;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (to) {
+ /* Copy the user-supplied timesec into the kernel structure.
+ * We do things this way to flatten differences between 32 bit
+ * and 64 bit timespecs.
+ */
+ ts.tv_sec = arg->wake_time_sec;
+ ts.tv_nsec = arg->wake_time_nsec;
+
+ if (!timespec_valid(&ts))
+ return -EINVAL;
+ hrtimer_init_on_stack(&to->timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_ABS);
+ hrtimer_set_expires_range_ns(&to->timer, timespec_to_ktime(ts),
+ current->timer_slack_ns);
+
+ hrtimer_init_sleeper(to, current);
+ }
+
+ while (1) {
+ prepare_to_wait(&data->futex_wait_queue, &wait,
+ TASK_INTERRUPTIBLE);
+ /*
+ * Check the sentinel value after prepare_to_wait. If the value
+ * changes after this check the writer will call signal,
+ * changing the task state from INTERRUPTIBLE to RUNNING. That
+ * will ensure that schedule() will eventually schedule this
+ * task.
+ */
+ if (atomic_read(address) != arg->value) {
+ ret = 0;
+ break;
+ }
+ if (to) {
+ hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS);
+ if (likely(to->task))
+ freezable_schedule();
+ hrtimer_cancel(&to->timer);
+ if (!to->task) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ } else {
+ freezable_schedule();
+ }
+ /* Count the number of times that we woke up. This is useful
+ * for unit testing.
+ */
+ ++arg->wakes;
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
+ }
+ finish_wait(&data->futex_wait_queue, &wait);
+ if (to)
+ destroy_hrtimer_on_stack(&to->timer);
+ return ret;
+}
+
+/**
+ * Handles the details of copying from/to userspace to ensure that the copies
+ * happen on all of the return paths of cond_wait.
+ */
+static int do_vsoc_cond_wait(struct file *filp,
+ struct vsoc_cond_wait __user *untrusted_in)
+{
+ struct vsoc_cond_wait arg;
+ int rval = 0;
+
+ if (copy_from_user(&arg, untrusted_in, sizeof(arg)))
+ return -EFAULT;
+ /* wakes is an out parameter. Initialize it to something sensible. */
+ arg.wakes = 0;
+ rval = handle_vsoc_cond_wait(filp, &arg);
+ if (copy_to_user(untrusted_in, &arg, sizeof(arg)))
+ return -EFAULT;
+ return rval;
+}
+
+static int do_vsoc_cond_wake(struct file *filp, uint32_t offset)
+{
+ struct vsoc_device_region *region_p = vsoc_region_from_filep(filp);
+ u32 region_number = iminor(file_inode(filp));
+ struct vsoc_region_data *data = vsoc_dev.regions_data + region_number;
+ /* Ensure that the offset is aligned */
+ if (offset & (sizeof(uint32_t) - 1))
+ return -EADDRNOTAVAIL;
+ /* Ensure that the offset is within shared memory */
+ if (((uint64_t)offset) + region_p->region_begin_offset +
+ sizeof(uint32_t) > region_p->region_end_offset)
+ return -E2BIG;
+ /*
+ * TODO(b/73664181): Use multiple futex wait queues.
+ * We need to wake every sleeper when the condition changes. Typically
+ * only a single thread will be waiting on the condition, but there
+ * are exceptions. The worst case is about 10 threads.
+ */
+ wake_up_interruptible_all(&data->futex_wait_queue);
+ return 0;
+}
+
+static long vsoc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int rv = 0;
+ struct vsoc_device_region *region_p;
+ u32 reg_num;
+ struct vsoc_region_data *reg_data;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ region_p = vsoc_region_from_filep(filp);
+ reg_num = iminor(file_inode(filp));
+ reg_data = vsoc_dev.regions_data + reg_num;
+ switch (cmd) {
+ case VSOC_CREATE_FD_SCOPED_PERMISSION:
+ {
+ struct fd_scoped_permission_node *node = NULL;
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ /* We can't allocate memory for the permission */
+ if (!node)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&node->list);
+ rv = do_create_fd_scoped_permission(
+ region_p,
+ node,
+ (struct fd_scoped_permission_arg __user *)arg);
+ if (!rv) {
+ mutex_lock(&vsoc_dev.mtx);
+ list_add(&node->list, &vsoc_dev.permissions);
+ mutex_unlock(&vsoc_dev.mtx);
+ } else {
+ kfree(node);
+ return rv;
+ }
+ }
+ break;
+
+ case VSOC_GET_FD_SCOPED_PERMISSION:
+ {
+ struct fd_scoped_permission_node *node =
+ ((struct vsoc_private_data *)filp->private_data)->
+ fd_scoped_permission_node;
+ if (!node)
+ return -ENOENT;
+ if (copy_to_user
+ ((struct fd_scoped_permission __user *)arg,
+ &node->permission, sizeof(node->permission)))
+ return -EFAULT;
+ }
+ break;
+
+ case VSOC_MAYBE_SEND_INTERRUPT_TO_HOST:
+ if (!atomic_xchg(
+ reg_data->outgoing_signalled,
+ 1)) {
+ writel(reg_num, vsoc_dev.regs + DOORBELL);
+ return 0;
+ } else {
+ return -EBUSY;
+ }
+ break;
+
+ case VSOC_SEND_INTERRUPT_TO_HOST:
+ writel(reg_num, vsoc_dev.regs + DOORBELL);
+ return 0;
+
+ case VSOC_WAIT_FOR_INCOMING_INTERRUPT:
+ wait_event_interruptible(
+ reg_data->interrupt_wait_queue,
+ (atomic_read(reg_data->incoming_signalled) != 0));
+ break;
+
+ case VSOC_DESCRIBE_REGION:
+ return do_vsoc_describe_region(
+ filp,
+ (struct vsoc_device_region __user *)arg);
+
+ case VSOC_SELF_INTERRUPT:
+ atomic_set(reg_data->incoming_signalled, 1);
+ wake_up_interruptible(®_data->interrupt_wait_queue);
+ break;
+
+ case VSOC_COND_WAIT:
+ return do_vsoc_cond_wait(filp,
+ (struct vsoc_cond_wait __user *)arg);
+ case VSOC_COND_WAKE:
+ return do_vsoc_cond_wake(filp, arg);
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static ssize_t vsoc_read(struct file *filp, char *buffer, size_t len,
+ loff_t *poffset)
+{
+ __u32 area_off;
+ void *area_p;
+ ssize_t area_len;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ area_len = vsoc_get_area(filp, &area_off);
+ area_p = shm_off_to_virtual_addr(area_off);
+ area_p += *poffset;
+ area_len -= *poffset;
+ if (area_len <= 0)
+ return 0;
+ if (area_len < len)
+ len = area_len;
+ if (copy_to_user(buffer, area_p, len))
+ return -EFAULT;
+ *poffset += len;
+ return len;
+}
+
+static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin)
+{
+ ssize_t area_len = 0;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ area_len = vsoc_get_area(filp, NULL);
+ switch (origin) {
+ case SEEK_SET:
+ break;
+
+ case SEEK_CUR:
+ if (offset > 0 && offset + filp->f_pos < 0)
+ return -EOVERFLOW;
+ offset += filp->f_pos;
+ break;
+
+ case SEEK_END:
+ if (offset > 0 && offset + area_len < 0)
+ return -EOVERFLOW;
+ offset += area_len;
+ break;
+
+ case SEEK_DATA:
+ if (offset >= area_len)
+ return -EINVAL;
+ if (offset < 0)
+ offset = 0;
+ break;
+
+ case SEEK_HOLE:
+ /* Next hole is always the end of the region, unless offset is
+ * beyond that
+ */
+ if (offset < area_len)
+ offset = area_len;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (offset < 0 || offset > area_len)
+ return -EINVAL;
+ filp->f_pos = offset;
+
+ return offset;
+}
+
+static ssize_t vsoc_write(struct file *filp, const char *buffer,
+ size_t len, loff_t *poffset)
+{
+ __u32 area_off;
+ void *area_p;
+ ssize_t area_len;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ area_len = vsoc_get_area(filp, &area_off);
+ area_p = shm_off_to_virtual_addr(area_off);
+ area_p += *poffset;
+ area_len -= *poffset;
+ if (area_len <= 0)
+ return 0;
+ if (area_len < len)
+ len = area_len;
+ if (copy_from_user(area_p, buffer, len))
+ return -EFAULT;
+ *poffset += len;
+ return len;
+}
+
+static irqreturn_t vsoc_interrupt(int irq, void *region_data_v)
+{
+ struct vsoc_region_data *region_data =
+ (struct vsoc_region_data *)region_data_v;
+ int reg_num = region_data - vsoc_dev.regions_data;
+
+ if (unlikely(!region_data))
+ return IRQ_NONE;
+
+ if (unlikely(reg_num < 0 ||
+ reg_num >= vsoc_dev.layout->region_count)) {
+ dev_err(&vsoc_dev.dev->dev,
+ "invalid irq @%p reg_num=0x%04x\n",
+ region_data, reg_num);
+ return IRQ_NONE;
+ }
+ if (unlikely(vsoc_dev.regions_data + reg_num != region_data)) {
+ dev_err(&vsoc_dev.dev->dev,
+ "irq not aligned @%p reg_num=0x%04x\n",
+ region_data, reg_num);
+ return IRQ_NONE;
+ }
+ wake_up_interruptible(®ion_data->interrupt_wait_queue);
+ return IRQ_HANDLED;
+}
+
+static int vsoc_probe_device(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int result;
+ int i;
+ resource_size_t reg_size;
+ dev_t devt;
+
+ vsoc_dev.dev = pdev;
+ result = pci_enable_device(pdev);
+ if (result) {
+ dev_err(&pdev->dev,
+ "pci_enable_device failed %s: error %d\n",
+ pci_name(pdev), result);
+ return result;
+ }
+ vsoc_dev.enabled_device = 1;
+ result = pci_request_regions(pdev, "vsoc");
+ if (result < 0) {
+ dev_err(&pdev->dev, "pci_request_regions failed\n");
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+ vsoc_dev.requested_regions = 1;
+ /* Set up the control registers in BAR 0 */
+ reg_size = pci_resource_len(pdev, REGISTER_BAR);
+ if (reg_size > MAX_REGISTER_BAR_LEN)
+ vsoc_dev.regs =
+ pci_iomap(pdev, REGISTER_BAR, MAX_REGISTER_BAR_LEN);
+ else
+ vsoc_dev.regs = pci_iomap(pdev, REGISTER_BAR, reg_size);
+
+ if (!vsoc_dev.regs) {
+ dev_err(&pdev->dev,
+ "cannot ioremap registers of size %zu\n",
+ (size_t)reg_size);
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+
+ /* Map the shared memory in BAR 2 */
+ vsoc_dev.shm_phys_start = pci_resource_start(pdev, SHARED_MEMORY_BAR);
+ vsoc_dev.shm_size = pci_resource_len(pdev, SHARED_MEMORY_BAR);
+
+ dev_info(&pdev->dev, "shared memory @ DMA %p size=0x%zx\n",
+ (void *)vsoc_dev.shm_phys_start, vsoc_dev.shm_size);
+ /* TODO(ghartman): ioremap_wc should work here */
+ vsoc_dev.kernel_mapped_shm = ioremap_nocache(
+ vsoc_dev.shm_phys_start, vsoc_dev.shm_size);
+ if (!vsoc_dev.kernel_mapped_shm) {
+ dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n");
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+
+ vsoc_dev.layout =
+ (struct vsoc_shm_layout_descriptor *)vsoc_dev.kernel_mapped_shm;
+ dev_info(&pdev->dev, "major_version: %d\n",
+ vsoc_dev.layout->major_version);
+ dev_info(&pdev->dev, "minor_version: %d\n",
+ vsoc_dev.layout->minor_version);
+ dev_info(&pdev->dev, "size: 0x%x\n", vsoc_dev.layout->size);
+ dev_info(&pdev->dev, "regions: %d\n", vsoc_dev.layout->region_count);
+ if (vsoc_dev.layout->major_version !=
+ CURRENT_VSOC_LAYOUT_MAJOR_VERSION) {
+ dev_err(&vsoc_dev.dev->dev,
+ "driver supports only major_version %d\n",
+ CURRENT_VSOC_LAYOUT_MAJOR_VERSION);
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+ result = alloc_chrdev_region(&devt, 0, vsoc_dev.layout->region_count,
+ VSOC_DEV_NAME);
+ if (result) {
+ dev_err(&vsoc_dev.dev->dev, "alloc_chrdev_region failed\n");
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+ vsoc_dev.major = MAJOR(devt);
+ cdev_init(&vsoc_dev.cdev, &vsoc_ops);
+ vsoc_dev.cdev.owner = THIS_MODULE;
+ result = cdev_add(&vsoc_dev.cdev, devt, vsoc_dev.layout->region_count);
+ if (result) {
+ dev_err(&vsoc_dev.dev->dev, "cdev_add error\n");
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+ vsoc_dev.cdev_added = 1;
+ vsoc_dev.class = class_create(THIS_MODULE, VSOC_DEV_NAME);
+ if (IS_ERR(vsoc_dev.class)) {
+ dev_err(&vsoc_dev.dev->dev, "class_create failed\n");
+ vsoc_remove_device(pdev);
+ return PTR_ERR(vsoc_dev.class);
+ }
+ vsoc_dev.class_added = 1;
+ vsoc_dev.regions = (struct vsoc_device_region *)
+ (vsoc_dev.kernel_mapped_shm +
+ vsoc_dev.layout->vsoc_region_desc_offset);
+ vsoc_dev.msix_entries = kcalloc(
+ vsoc_dev.layout->region_count,
+ sizeof(vsoc_dev.msix_entries[0]), GFP_KERNEL);
+ if (!vsoc_dev.msix_entries) {
+ dev_err(&vsoc_dev.dev->dev,
+ "unable to allocate msix_entries\n");
+ vsoc_remove_device(pdev);
+ return -ENOSPC;
+ }
+ vsoc_dev.regions_data = kcalloc(
+ vsoc_dev.layout->region_count,
+ sizeof(vsoc_dev.regions_data[0]), GFP_KERNEL);
+ if (!vsoc_dev.regions_data) {
+ dev_err(&vsoc_dev.dev->dev,
+ "unable to allocate regions' data\n");
+ vsoc_remove_device(pdev);
+ return -ENOSPC;
+ }
+ for (i = 0; i < vsoc_dev.layout->region_count; ++i)
+ vsoc_dev.msix_entries[i].entry = i;
+
+ result = pci_enable_msix_exact(vsoc_dev.dev, vsoc_dev.msix_entries,
+ vsoc_dev.layout->region_count);
+ if (result) {
+ dev_info(&pdev->dev, "pci_enable_msix failed: %d\n", result);
+ vsoc_remove_device(pdev);
+ return -ENOSPC;
+ }
+ /* Check that all regions are well formed */
+ for (i = 0; i < vsoc_dev.layout->region_count; ++i) {
+ const struct vsoc_device_region *region = vsoc_dev.regions + i;
+
+ if (!PAGE_ALIGNED(region->region_begin_offset) ||
+ !PAGE_ALIGNED(region->region_end_offset)) {
+ dev_err(&vsoc_dev.dev->dev,
+ "region %d not aligned (%x:%x)", i,
+ region->region_begin_offset,
+ region->region_end_offset);
+ vsoc_remove_device(pdev);
+ return -EFAULT;
+ }
+ if (region->region_begin_offset >= region->region_end_offset ||
+ region->region_end_offset > vsoc_dev.shm_size) {
+ dev_err(&vsoc_dev.dev->dev,
+ "region %d offsets are wrong: %x %x %zx",
+ i, region->region_begin_offset,
+ region->region_end_offset, vsoc_dev.shm_size);
+ vsoc_remove_device(pdev);
+ return -EFAULT;
+ }
+ if (region->managed_by >= vsoc_dev.layout->region_count) {
+ dev_err(&vsoc_dev.dev->dev,
+ "region %d has invalid owner: %u",
+ i, region->managed_by);
+ vsoc_remove_device(pdev);
+ return -EFAULT;
+ }
+ }
+ vsoc_dev.msix_enabled = 1;
+ for (i = 0; i < vsoc_dev.layout->region_count; ++i) {
+ const struct vsoc_device_region *region = vsoc_dev.regions + i;
+ size_t name_sz = sizeof(vsoc_dev.regions_data[i].name) - 1;
+ const struct vsoc_signal_table_layout *h_to_g_signal_table =
+ ®ion->host_to_guest_signal_table;
+ const struct vsoc_signal_table_layout *g_to_h_signal_table =
+ ®ion->guest_to_host_signal_table;
+
+ vsoc_dev.regions_data[i].name[name_sz] = '\0';
+ memcpy(vsoc_dev.regions_data[i].name, region->device_name,
+ name_sz);
+ dev_info(&pdev->dev, "region %d name=%s\n",
+ i, vsoc_dev.regions_data[i].name);
+ init_waitqueue_head(
+ &vsoc_dev.regions_data[i].interrupt_wait_queue);
+ init_waitqueue_head(&vsoc_dev.regions_data[i].futex_wait_queue);
+ vsoc_dev.regions_data[i].incoming_signalled =
+ vsoc_dev.kernel_mapped_shm +
+ region->region_begin_offset +
+ h_to_g_signal_table->interrupt_signalled_offset;
+ vsoc_dev.regions_data[i].outgoing_signalled =
+ vsoc_dev.kernel_mapped_shm +
+ region->region_begin_offset +
+ g_to_h_signal_table->interrupt_signalled_offset;
+
+ result = request_irq(
+ vsoc_dev.msix_entries[i].vector,
+ vsoc_interrupt, 0,
+ vsoc_dev.regions_data[i].name,
+ vsoc_dev.regions_data + i);
+ if (result) {
+ dev_info(&pdev->dev,
+ "request_irq failed irq=%d vector=%d\n",
+ i, vsoc_dev.msix_entries[i].vector);
+ vsoc_remove_device(pdev);
+ return -ENOSPC;
+ }
+ vsoc_dev.regions_data[i].irq_requested = 1;
+ if (!device_create(vsoc_dev.class, NULL,
+ MKDEV(vsoc_dev.major, i),
+ NULL, vsoc_dev.regions_data[i].name)) {
+ dev_err(&vsoc_dev.dev->dev, "device_create failed\n");
+ vsoc_remove_device(pdev);
+ return -EBUSY;
+ }
+ vsoc_dev.regions_data[i].device_created = 1;
+ }
+ return 0;
+}
+
+/*
+ * This should undo all of the allocations in the probe function in reverse
+ * order.
+ *
+ * Notes:
+ *
+ * The device may have been partially initialized, so double check
+ * that the allocations happened.
+ *
+ * This function may be called multiple times, so mark resources as freed
+ * as they are deallocated.
+ */
+static void vsoc_remove_device(struct pci_dev *pdev)
+{
+ int i;
+ /*
+ * pdev is the first thing to be set on probe and the last thing
+ * to be cleared here. If it's NULL then there is no cleanup.
+ */
+ if (!pdev || !vsoc_dev.dev)
+ return;
+ dev_info(&pdev->dev, "remove_device\n");
+ if (vsoc_dev.regions_data) {
+ for (i = 0; i < vsoc_dev.layout->region_count; ++i) {
+ if (vsoc_dev.regions_data[i].device_created) {
+ device_destroy(vsoc_dev.class,
+ MKDEV(vsoc_dev.major, i));
+ vsoc_dev.regions_data[i].device_created = 0;
+ }
+ if (vsoc_dev.regions_data[i].irq_requested)
+ free_irq(vsoc_dev.msix_entries[i].vector, NULL);
+ vsoc_dev.regions_data[i].irq_requested = 0;
+ }
+ kfree(vsoc_dev.regions_data);
+ vsoc_dev.regions_data = 0;
+ }
+ if (vsoc_dev.msix_enabled) {
+ pci_disable_msix(pdev);
+ vsoc_dev.msix_enabled = 0;
+ }
+ kfree(vsoc_dev.msix_entries);
+ vsoc_dev.msix_entries = 0;
+ vsoc_dev.regions = 0;
+ if (vsoc_dev.class_added) {
+ class_destroy(vsoc_dev.class);
+ vsoc_dev.class_added = 0;
+ }
+ if (vsoc_dev.cdev_added) {
+ cdev_del(&vsoc_dev.cdev);
+ vsoc_dev.cdev_added = 0;
+ }
+ if (vsoc_dev.major && vsoc_dev.layout) {
+ unregister_chrdev_region(MKDEV(vsoc_dev.major, 0),
+ vsoc_dev.layout->region_count);
+ vsoc_dev.major = 0;
+ }
+ vsoc_dev.layout = 0;
+ if (vsoc_dev.kernel_mapped_shm) {
+ pci_iounmap(pdev, vsoc_dev.kernel_mapped_shm);
+ vsoc_dev.kernel_mapped_shm = 0;
+ }
+ if (vsoc_dev.regs) {
+ pci_iounmap(pdev, vsoc_dev.regs);
+ vsoc_dev.regs = 0;
+ }
+ if (vsoc_dev.requested_regions) {
+ pci_release_regions(pdev);
+ vsoc_dev.requested_regions = 0;
+ }
+ if (vsoc_dev.enabled_device) {
+ pci_disable_device(pdev);
+ vsoc_dev.enabled_device = 0;
+ }
+ /* Do this last: it indicates that the device is not initialized. */
+ vsoc_dev.dev = NULL;
+}
+
+static void __exit vsoc_cleanup_module(void)
+{
+ vsoc_remove_device(vsoc_dev.dev);
+ pci_unregister_driver(&vsoc_pci_driver);
+}
+
+static int __init vsoc_init_module(void)
+{
+ int err = -ENOMEM;
+
+ INIT_LIST_HEAD(&vsoc_dev.permissions);
+ mutex_init(&vsoc_dev.mtx);
+
+ err = pci_register_driver(&vsoc_pci_driver);
+ if (err < 0)
+ return err;
+ return 0;
+}
+
+static int vsoc_open(struct inode *inode, struct file *filp)
+{
+ /* Can't use vsoc_validate_filep because filp is still incomplete */
+ int ret = vsoc_validate_inode(inode);
+
+ if (ret)
+ return ret;
+ filp->private_data =
+ kzalloc(sizeof(struct vsoc_private_data), GFP_KERNEL);
+ if (!filp->private_data)
+ return -ENOMEM;
+ return 0;
+}
+
+static int vsoc_release(struct inode *inode, struct file *filp)
+{
+ struct vsoc_private_data *private_data = NULL;
+ struct fd_scoped_permission_node *node = NULL;
+ struct vsoc_device_region *owner_region_p = NULL;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ private_data = (struct vsoc_private_data *)filp->private_data;
+ if (!private_data)
+ return 0;
+
+ node = private_data->fd_scoped_permission_node;
+ if (node) {
+ owner_region_p = vsoc_region_from_inode(inode);
+ if (owner_region_p->managed_by != VSOC_REGION_WHOLE) {
+ owner_region_p =
+ &vsoc_dev.regions[owner_region_p->managed_by];
+ }
+ do_destroy_fd_scoped_permission_node(owner_region_p, node);
+ private_data->fd_scoped_permission_node = NULL;
+ }
+ kfree(private_data);
+ filp->private_data = NULL;
+
+ return 0;
+}
+
+/*
+ * Returns the device relative offset and length of the area specified by the
+ * fd scoped permission. If there is no fd scoped permission set, a default
+ * permission covering the entire region is assumed, unless the region is owned
+ * by another one, in which case the default is a permission with zero size.
+ */
+static ssize_t vsoc_get_area(struct file *filp, __u32 *area_offset)
+{
+ __u32 off = 0;
+ ssize_t length = 0;
+ struct vsoc_device_region *region_p;
+ struct fd_scoped_permission *perm;
+
+ region_p = vsoc_region_from_filep(filp);
+ off = region_p->region_begin_offset;
+ perm = &((struct vsoc_private_data *)filp->private_data)->
+ fd_scoped_permission_node->permission;
+ if (perm) {
+ off += perm->begin_offset;
+ length = perm->end_offset - perm->begin_offset;
+ } else if (region_p->managed_by == VSOC_REGION_WHOLE) {
+ /* No permission set and the regions is not owned by another,
+ * default to full region access.
+ */
+ length = vsoc_device_region_size(region_p);
+ } else {
+ /* return zero length, access is denied. */
+ length = 0;
+ }
+ if (area_offset)
+ *area_offset = off;
+ return length;
+}
+
+static int vsoc_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ unsigned long len = vma->vm_end - vma->vm_start;
+ __u32 area_off;
+ phys_addr_t mem_off;
+ ssize_t area_len;
+ int retval = vsoc_validate_filep(filp);
+
+ if (retval)
+ return retval;
+ area_len = vsoc_get_area(filp, &area_off);
+ /* Add the requested offset */
+ area_off += (vma->vm_pgoff << PAGE_SHIFT);
+ area_len -= (vma->vm_pgoff << PAGE_SHIFT);
+ if (area_len < len)
+ return -EINVAL;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ mem_off = shm_off_to_phys_addr(area_off);
+ if (io_remap_pfn_range(vma, vma->vm_start, mem_off >> PAGE_SHIFT,
+ len, vma->vm_page_prot))
+ return -EAGAIN;
+ return 0;
+}
+
+module_init(vsoc_init_module);
+module_exit(vsoc_cleanup_module);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Greg Hartman <ghartman@google.com>");
+MODULE_DESCRIPTION("VSoC interpretation of QEmu's ivshmem device");
+MODULE_VERSION("1.0");
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index a574885..18c5312 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -1284,6 +1284,8 @@
ack |= NISTC_INTA_ACK_AI_START;
if (a_status & NISTC_AI_STATUS1_STOP)
ack |= NISTC_INTA_ACK_AI_STOP;
+ if (a_status & NISTC_AI_STATUS1_OVER)
+ ack |= NISTC_INTA_ACK_AI_ERR;
if (ack)
ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG);
}
diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c
index 170de1c..f815f9d 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.c
+++ b/drivers/staging/wlan-ng/prism2mgmt.c
@@ -169,7 +169,7 @@
hw->ident_sta_fw.variant) >
HFA384x_FIRMWARE_VERSION(1, 5, 0)) {
if (msg->scantype.data != P80211ENUM_scantype_active)
- word = cpu_to_le16(msg->maxchanneltime.data);
+ word = msg->maxchanneltime.data;
else
word = 0;
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 06912f0..b7cb49a 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -587,6 +587,9 @@
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+ data->irq_enabled = true;
+ data->mode = THERMAL_DEVICE_ENABLED;
+
ret = devm_request_threaded_irq(&pdev->dev, data->irq,
imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
0, "imx_thermal", data);
@@ -598,9 +601,6 @@
return ret;
}
- data->irq_enabled = true;
- data->mode = THERMAL_DEVICE_ENABLED;
-
return 0;
}
diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
index b4d3116..3055f9a 100644
--- a/drivers/thermal/power_allocator.c
+++ b/drivers/thermal/power_allocator.c
@@ -523,6 +523,7 @@
struct thermal_instance *instance;
struct power_allocator_params *params = tz->governor_data;
+ mutex_lock(&tz->lock);
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
if ((instance->trip != params->trip_max_desired_temperature) ||
(!cdev_is_power_actor(instance->cdev)))
@@ -534,6 +535,7 @@
mutex_unlock(&instance->cdev->lock);
thermal_cdev_update(instance->cdev);
}
+ mutex_unlock(&tz->lock);
}
/**
diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h
index 730d124..d35b867 100644
--- a/drivers/thermal/tsens.h
+++ b/drivers/thermal/tsens.h
@@ -153,8 +153,8 @@
spinlock_t tsens_crit_lock;
spinlock_t tsens_upp_low_lock;
const struct tsens_data *ctrl_data;
+ struct tsens_mtc_sysfs mtcsys;
struct tsens_sensor sensor[0];
- struct tsens_mtc_sysfs mtcsys;
};
extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx;
diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c
index d63fcd1..19e2b5a 100644
--- a/drivers/thermal/tsens1xxx.c
+++ b/drivers/thermal/tsens1xxx.c
@@ -517,8 +517,8 @@
th_temp = code_to_degc((threshold &
TSENS_UPPER_THRESHOLD_MASK) >>
TSENS_UPPER_THRESHOLD_SHIFT,
- tm->sensor);
- if (th_temp > temp) {
+ (tm->sensor + i));
+ if (th_temp > (temp/TSENS_SCALE_MILLIDEG)) {
pr_debug("Re-arm high threshold\n");
rc = tsens_tz_activate_trip_type(
&tm->sensor[i],
@@ -539,8 +539,8 @@
tm->tsens_tm_addr + addr_offset));
th_temp = code_to_degc((threshold &
TSENS_LOWER_THRESHOLD_MASK),
- tm->sensor);
- if (th_temp < temp) {
+ (tm->sensor + i));
+ if (th_temp < (temp/TSENS_SCALE_MILLIDEG)) {
pr_debug("Re-arm Low threshold\n");
rc = tsens_tz_activate_trip_type(
&tm->sensor[i],
diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index a8c2041..cba6bc6 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -628,6 +628,7 @@
* we just disable hotplug, the
* pci-tunnels stay alive.
*/
+ .thaw_noirq = nhi_resume_noirq,
.restore_noirq = nhi_resume_noirq,
};
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index 54cab59..fe22917 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -1467,6 +1467,10 @@
* in which case an opening port goes back to closed and a closing port
* is simply put into closed state (any further frames from the other
* end will get a DM response)
+ *
+ * Some control dlci can stay in ADM mode with other dlci working just
+ * fine. In that case we can just keep the control dlci open after the
+ * DLCI_OPENING retries time out.
*/
static void gsm_dlci_t1(unsigned long data)
@@ -1480,8 +1484,15 @@
if (dlci->retries) {
gsm_command(dlci->gsm, dlci->addr, SABM|PF);
mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100);
- } else
+ } else if (!dlci->addr && gsm->control == (DM | PF)) {
+ if (debug & 8)
+ pr_info("DLCI %d opening in ADM mode.\n",
+ dlci->addr);
+ gsm_dlci_open(dlci);
+ } else {
gsm_dlci_close(dlci);
+ }
+
break;
case DLCI_CLOSING:
dlci->retries--;
@@ -1499,8 +1510,8 @@
* @dlci: DLCI to open
*
* Commence opening a DLCI from the Linux side. We issue SABM messages
- * to the modem which should then reply with a UA, at which point we
- * will move into open state. Opening is done asynchronously with retry
+ * to the modem which should then reply with a UA or ADM, at which point
+ * we will move into open state. Opening is done asynchronously with retry
* running off timers and the responses.
*/
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index faf50df..1c70541 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2182,6 +2182,12 @@
}
if (tty_hung_up_p(file))
break;
+ /*
+ * Abort readers for ttys which never actually
+ * get hung up. See __tty_hangup().
+ */
+ if (test_bit(TTY_HUPPING, &tty->flags))
+ break;
if (!timeout)
break;
if (file->f_flags & O_NONBLOCK) {
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index da31159..e8b34f1 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -613,6 +613,10 @@
up->lsr_saved_flags = 0;
up->msr_saved_flags = 0;
+ /* Disable DMA for console UART */
+ if (uart_console(port))
+ up->dma = NULL;
+
if (up->dma) {
ret = serial8250_request_dma(up);
if (ret) {
diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c
index f76b3db..8e5d100 100644
--- a/drivers/tty/serial/msm_geni_serial.c
+++ b/drivers/tty/serial/msm_geni_serial.c
@@ -1660,7 +1660,7 @@
msm_port->rx_buf = devm_kzalloc(uport->dev, DMA_RX_BUF_SIZE,
GFP_KERNEL);
if (!msm_port->rx_buf) {
- kfree(msm_port->rx_fifo);
+ devm_kfree(uport->dev, msm_port->rx_fifo);
msm_port->rx_fifo = NULL;
ret = -ENOMEM;
goto exit_portsetup;
diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c
index fcf803f..cdd2f94 100644
--- a/drivers/tty/serial/sccnxp.c
+++ b/drivers/tty/serial/sccnxp.c
@@ -884,14 +884,19 @@
clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
- if (PTR_ERR(clk) == -EPROBE_DEFER) {
- ret = -EPROBE_DEFER;
+ ret = PTR_ERR(clk);
+ if (ret == -EPROBE_DEFER)
goto err_out;
- }
+ uartclk = 0;
+ } else {
+ clk_prepare_enable(clk);
+ uartclk = clk_get_rate(clk);
+ }
+
+ if (!uartclk) {
dev_notice(&pdev->dev, "Using default clock frequency\n");
uartclk = s->chip->freq_std;
- } else
- uartclk = clk_get_rate(clk);
+ }
/* Check input frequency */
if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) {
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index a55c94d..107f0d1 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1545,7 +1545,16 @@
if (s->chan_rx)
sci_rx_dma_release(s, false);
}
-#else
+
+static void sci_flush_buffer(struct uart_port *port)
+{
+ /*
+ * In uart_flush_buffer(), the xmit circular buffer has just been
+ * cleared, so we have to reset tx_dma_len accordingly.
+ */
+ to_sci_port(port)->tx_dma_len = 0;
+}
+#else /* !CONFIG_SERIAL_SH_SCI_DMA */
static inline void sci_request_dma(struct uart_port *port)
{
}
@@ -1553,7 +1562,9 @@
static inline void sci_free_dma(struct uart_port *port)
{
}
-#endif
+
+#define sci_flush_buffer NULL
+#endif /* !CONFIG_SERIAL_SH_SCI_DMA */
static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
{
@@ -2551,6 +2562,7 @@
.break_ctl = sci_break_ctl,
.startup = sci_startup,
.shutdown = sci_shutdown,
+ .flush_buffer = sci_flush_buffer,
.set_termios = sci_set_termios,
.pm = sci_pm,
.type = sci_type,
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index fb9bada..4ee0a9d 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -709,6 +709,14 @@
return;
}
+ /*
+ * Some console devices aren't actually hung up for technical and
+ * historical reasons, which can lead to indefinite interruptible
+ * sleep in n_tty_read(). The following explicitly tells
+ * n_tty_read() to abort readers.
+ */
+ set_bit(TTY_HUPPING, &tty->flags);
+
/* inuse_filps is protected by the single tty lock,
this really needs to change if we want to flush the
workqueue with the lock held */
@@ -763,6 +771,7 @@
* from the ldisc side, which is now guaranteed.
*/
set_bit(TTY_HUPPED, &tty->flags);
+ clear_bit(TTY_HUPPING, &tty->flags);
tty_unlock(tty);
if (f)
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index 68c7bb0..9e1ac58 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -1354,6 +1354,11 @@
case 3:
vc->vc_italic = 1;
break;
+ case 21:
+ /*
+ * No console drivers support double underline, so
+ * convert it to a single underline.
+ */
case 4:
vc->vc_underline = 1;
break;
@@ -1389,7 +1394,6 @@
vc->vc_disp_ctrl = 1;
vc->vc_toggle_meta = 1;
break;
- case 21:
case 22:
vc->vc_intensity = 1;
break;
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index fba021f..208bc52 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -279,7 +279,7 @@
map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map) {
ret = -ENOMEM;
- goto err_map_kobj;
+ goto err_map;
}
kobject_init(&map->kobj, &map_attr_type);
map->mem = mem;
@@ -289,7 +289,7 @@
goto err_map_kobj;
ret = kobject_uevent(&map->kobj, KOBJ_ADD);
if (ret)
- goto err_map;
+ goto err_map_kobj;
}
for (pi = 0; pi < MAX_UIO_PORT_REGIONS; pi++) {
@@ -308,7 +308,7 @@
portio = kzalloc(sizeof(*portio), GFP_KERNEL);
if (!portio) {
ret = -ENOMEM;
- goto err_portio_kobj;
+ goto err_portio;
}
kobject_init(&portio->kobj, &portio_attr_type);
portio->port = port;
@@ -319,7 +319,7 @@
goto err_portio_kobj;
ret = kobject_uevent(&portio->kobj, KOBJ_ADD);
if (ret)
- goto err_portio;
+ goto err_portio_kobj;
}
return 0;
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 6e0d614..64c6af2c 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -839,7 +839,7 @@
{
ci_hdrc_gadget_destroy(ci);
ci_hdrc_host_destroy(ci);
- if (ci->is_otg)
+ if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
ci_hdrc_otg_destroy(ci);
}
@@ -939,27 +939,35 @@
/* initialize role(s) before the interrupt is requested */
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
ret = ci_hdrc_host_init(ci);
- if (ret)
- dev_info(dev, "doesn't support host\n");
+ if (ret) {
+ if (ret == -ENXIO)
+ dev_info(dev, "doesn't support host\n");
+ else
+ goto deinit_phy;
+ }
}
if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
ret = ci_hdrc_gadget_init(ci);
- if (ret)
- dev_info(dev, "doesn't support gadget\n");
+ if (ret) {
+ if (ret == -ENXIO)
+ dev_info(dev, "doesn't support gadget\n");
+ else
+ goto deinit_host;
+ }
}
if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
dev_err(dev, "no supported roles\n");
ret = -ENODEV;
- goto deinit_phy;
+ goto deinit_gadget;
}
if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) {
ret = ci_hdrc_otg_init(ci);
if (ret) {
dev_err(dev, "init otg fails, ret = %d\n", ret);
- goto stop;
+ goto deinit_gadget;
}
}
@@ -1024,7 +1032,12 @@
ci_extcon_unregister(ci);
stop:
- ci_role_destroy(ci);
+ if (ci->is_otg && ci->roles[CI_ROLE_GADGET])
+ ci_hdrc_otg_destroy(ci);
+deinit_gadget:
+ ci_hdrc_gadget_destroy(ci);
+deinit_host:
+ ci_hdrc_host_destroy(ci);
deinit_phy:
ci_usb_phy_exit(ci);
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 0f10ff2..8df85f6 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -240,8 +240,13 @@
if (!udev->parent)
rc = hcd_bus_suspend(udev, msg);
- /* Non-root devices don't need to do anything for FREEZE or PRETHAW */
- else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ /*
+ * Non-root USB2 devices don't need to do anything for FREEZE
+ * or PRETHAW. USB3 devices don't support global suspend and
+ * needs to be selectively suspended.
+ */
+ else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+ && (udev->speed < USB_SPEED_SUPER))
rc = 0;
else
rc = usb_port_suspend(udev, msg);
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index dfc0566..919a321 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -3220,7 +3220,6 @@
dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
spin_lock_irqsave(&hsotg->lock, flags);
- dwc2_hsotg_disconnect(hsotg);
dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hsotg_core_connect(hsotg);
@@ -3238,8 +3237,12 @@
if (count > 250)
dev_err(hsotg->dev,
"Connection id status change timed out\n");
- hsotg->op_state = OTG_STATE_A_HOST;
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dwc2_hsotg_disconnect(hsotg);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ hsotg->op_state = OTG_STATE_A_HOST;
/* Initialize the Core for Host mode */
dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c
index 7266470..12ee23f 100644
--- a/drivers/usb/dwc3/dwc3-keystone.c
+++ b/drivers/usb/dwc3/dwc3-keystone.c
@@ -107,6 +107,10 @@
return PTR_ERR(kdwc->usbss);
kdwc->clk = devm_clk_get(kdwc->dev, "usb");
+ if (IS_ERR(kdwc->clk)) {
+ dev_err(kdwc->dev, "unable to get usb clock\n");
+ return PTR_ERR(kdwc->clk);
+ }
error = clk_prepare_enable(kdwc->clk);
if (error < 0) {
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 427291a..d6493ab 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -173,7 +173,7 @@
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
- return ret;
+ goto err;
}
dwc3->dev.parent = dev;
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 73caa97..f878b8d1 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -414,7 +414,7 @@
dwc3_trace(trace_dwc3_gadget, "Command Timed Out");
dev_err(dwc->dev, "%s command timeout for %s\n",
dwc3_gadget_ep_cmd_string(cmd), dep->name);
- if (cmd != DWC3_DEPCMD_ENDTRANSFER) {
+ if (DWC3_DEPCMD_CMD(cmd) != DWC3_DEPCMD_ENDTRANSFER) {
dwc->ep_cmd_timeout_cnt++;
dwc3_notify_event(dwc,
DWC3_CONTROLLER_RESTART_USB_SESSION, 0);
@@ -1307,7 +1307,7 @@
if (req->request.status == -EINPROGRESS) {
ret = -EBUSY;
- dev_err_ratelimited(dwc->dev, "%s: %p request already in queue",
+ dev_err_ratelimited(dwc->dev, "%s: %pK request already in queue",
dep->name, req);
return ret;
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index d3e0ca5..90cbb61 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -568,6 +568,7 @@
config USB_CONFIGFS_F_GSI
bool "USB GSI function"
select USB_F_GSI
+ select USB_U_ETHER
depends on USB_CONFIGFS
help
Generic function driver to support h/w acceleration to IPA over GSI.
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 939c219..703fb24 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -3951,7 +3951,7 @@
usb_del_gadget_udc(&udc->gadget);
remove_trans:
if (udc->transceiver)
- otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+ otg_set_peripheral(udc->transceiver->otg, NULL);
err("error = %i", retval);
put_transceiver:
@@ -3989,7 +3989,7 @@
usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+ otg_set_peripheral(udc->transceiver->otg, NULL);
usb_put_phy(udc->transceiver);
}
destroy_eps(udc);
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 8eed1b3..9974332 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -1097,7 +1097,7 @@
spin_unlock_irq(&epfile->ffs->eps_lock);
extra_buf_alloc = ffs->gadget->extra_buf_alloc;
- if (io_data->read)
+ if (!io_data->read)
data = kmalloc(data_len + extra_buf_alloc,
GFP_KERNEL);
else
diff --git a/drivers/usb/gadget/function/f_gsi.c b/drivers/usb/gadget/function/f_gsi.c
index 5ffbf12..94dd64a 100644
--- a/drivers/usb/gadget/function/f_gsi.c
+++ b/drivers/usb/gadget/function/f_gsi.c
@@ -19,7 +19,7 @@
MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data");
static struct workqueue_struct *ipa_usb_wq;
-static struct f_gsi *__gsi[IPA_USB_MAX_TETH_PROT_SIZE];
+static struct f_gsi *__gsi[USB_PROT_MAX];
static void *ipc_log_ctxt;
#define NUM_LOG_PAGES 15
@@ -56,6 +56,15 @@
static struct gsi_ctrl_pkt *gsi_ctrl_pkt_alloc(unsigned int len, gfp_t flags);
static void gsi_ctrl_pkt_free(struct gsi_ctrl_pkt *pkt);
+static inline bool is_ext_prot_ether(int prot_id)
+{
+ if (prot_id == USB_PROT_RMNET_ETHER ||
+ prot_id == USB_PROT_DPL_ETHER)
+ return true;
+
+ return false;
+}
+
static inline bool usb_gsi_remote_wakeup_allowed(struct usb_function *f)
{
bool remote_wakeup_allowed;
@@ -226,7 +235,7 @@
log_event_err("%s: Set net_ready_trigger", __func__);
gsi->d_port.net_ready_trigger = true;
- if (gsi->prot_id == IPA_USB_ECM) {
+ if (gsi->prot_id == USB_PROT_ECM_IPA) {
cpkt_notify_connect = gsi_ctrl_pkt_alloc(0, GFP_ATOMIC);
if (IS_ERR(cpkt_notify_connect)) {
spin_unlock_irqrestore(&gsi->d_port.lock,
@@ -260,7 +269,7 @@
* Do not post EVT_CONNECTED for RNDIS.
* Data path for RNDIS is enabled on EVT_HOST_READY.
*/
- if (gsi->prot_id != IPA_USB_RNDIS) {
+ if (gsi->prot_id != USB_PROT_RNDIS_IPA) {
post_event(&gsi->d_port, EVT_CONNECTED);
queue_work(gsi->d_port.ipa_usb_wq,
&gsi->d_port.usb_ipa_w);
@@ -311,7 +320,7 @@
log_event_dbg("%s: USB GSI IN OPS Completed", __func__);
in_params->client =
- (gsi->prot_id != IPA_USB_DIAG) ? IPA_CLIENT_USB_CONS :
+ (gsi->prot_id != USB_PROT_DIAG_IPA) ? IPA_CLIENT_USB_CONS :
IPA_CLIENT_USB_DPL_CONS;
in_params->ipa_ep_cfg.mode.mode = IPA_BASIC;
in_params->teth_prot = gsi->prot_id;
@@ -395,7 +404,7 @@
conn_params->usb_to_ipa_xferrscidx =
d_port->out_xfer_rsc_index;
conn_params->usb_to_ipa_xferrscidx_valid =
- (gsi->prot_id != IPA_USB_DIAG) ? true : false;
+ (gsi->prot_id != USB_PROT_DIAG_IPA) ? true : false;
conn_params->ipa_to_usb_xferrscidx_valid = true;
conn_params->teth_prot = gsi->prot_id;
conn_params->teth_prot_params.max_xfer_size_bytes_to_dev = 23700;
@@ -440,7 +449,7 @@
d_port->in_request.db_reg_phs_addr_msb =
ipa_in_channel_out_params.db_reg_phs_addr_msb;
- if (gsi->prot_id != IPA_USB_DIAG) {
+ if (gsi->prot_id != USB_PROT_DIAG_IPA) {
d_port->out_channel_handle =
ipa_out_channel_out_params.clnt_hdl;
d_port->out_request.db_reg_phs_addr_lsb =
@@ -1159,7 +1168,8 @@
switch (cmd) {
case QTI_CTRL_MODEM_OFFLINE:
- if (gsi->prot_id == IPA_USB_DIAG) {
+ if (gsi->prot_id == USB_PROT_DIAG_IPA ||
+ gsi->prot_id == USB_PROT_DPL_ETHER) {
log_event_dbg("%s:Modem Offline not handled", __func__);
goto exit_ioctl;
}
@@ -1177,7 +1187,8 @@
gsi_ctrl_send_notification(gsi);
break;
case QTI_CTRL_MODEM_ONLINE:
- if (gsi->prot_id == IPA_USB_DIAG) {
+ if (gsi->prot_id == USB_PROT_DIAG_IPA ||
+ gsi->prot_id == USB_PROT_DPL_ETHER) {
log_event_dbg("%s:Modem Online not handled", __func__);
goto exit_ioctl;
}
@@ -1186,7 +1197,8 @@
break;
case QTI_CTRL_GET_LINE_STATE:
val = atomic_read(&gsi->connected);
- if (gsi->prot_id == IPA_USB_RMNET)
+ if (gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_RMNET_ETHER)
val = gsi->rmnet_dtr_status;
ret = copy_to_user((void __user *)arg, &val, sizeof(val));
@@ -1207,7 +1219,8 @@
break;
}
- if (gsi->prot_id == IPA_USB_DIAG &&
+ if ((gsi->prot_id == USB_PROT_DIAG_IPA ||
+ gsi->prot_id == USB_PROT_DPL_ETHER) &&
(gsi->d_port.in_channel_handle == -EINVAL)) {
ret = -EAGAIN;
break;
@@ -1222,7 +1235,8 @@
info.ph_ep_info.ep_type = GSI_MBIM_DATA_EP_TYPE_HSUSB;
info.ph_ep_info.peripheral_iface_id = gsi->data_id;
info.ipa_ep_pair.cons_pipe_num =
- (gsi->prot_id == IPA_USB_DIAG) ? -1 :
+ (gsi->prot_id == USB_PROT_DIAG_IPA ||
+ gsi->prot_id == USB_PROT_DPL_ETHER) ? -1 :
gsi->d_port.out_channel_handle;
info.ipa_ep_pair.prod_pipe_num = gsi->d_port.in_channel_handle;
@@ -1328,8 +1342,8 @@
static int gsi_function_ctrl_port_init(struct f_gsi *gsi)
{
int ret;
+ char *cdev_name = NULL;
int sz = GSI_CTRL_NAME_LEN;
- bool ctrl_dev_create = true;
INIT_LIST_HEAD(&gsi->c_port.cpkt_req_q);
INIT_LIST_HEAD(&gsi->c_port.cpkt_resp_q);
@@ -1338,17 +1352,30 @@
init_waitqueue_head(&gsi->c_port.read_wq);
- if (gsi->prot_id == IPA_USB_RMNET)
- strlcat(gsi->c_port.name, GSI_RMNET_CTRL_NAME, sz);
- else if (gsi->prot_id == IPA_USB_MBIM)
- strlcat(gsi->c_port.name, GSI_MBIM_CTRL_NAME, sz);
- else if (gsi->prot_id == IPA_USB_DIAG)
- strlcat(gsi->c_port.name, GSI_DPL_CTRL_NAME, sz);
- else
- ctrl_dev_create = false;
+ switch (gsi->prot_id) {
+ case USB_PROT_RMNET_IPA:
+ cdev_name = GSI_RMNET_CTRL_NAME;
+ break;
+ case USB_PROT_RMNET_ETHER:
+ cdev_name = ETHER_RMNET_CTRL_NAME;
+ break;
+ case USB_PROT_MBIM_IPA:
+ cdev_name = GSI_MBIM_CTRL_NAME;
+ break;
+ case USB_PROT_DIAG_IPA:
+ cdev_name = GSI_DPL_CTRL_NAME;
+ break;
+ case USB_PROT_DPL_ETHER:
+ cdev_name = ETHER_DPL_CTRL_NAME;
+ break;
+ default:
+ break;
+ }
- if (!ctrl_dev_create)
+ if (!cdev_name)
return 0;
+ else
+ strlcat(gsi->c_port.name, cdev_name, sz);
gsi->c_port.ctrl_device.name = gsi->c_port.name;
gsi->c_port.ctrl_device.fops = &gsi_ctrl_dev_fops;
@@ -1512,7 +1539,7 @@
event->wValue = cpu_to_le16(0);
event->wLength = cpu_to_le16(0);
- if (gsi->prot_id == IPA_USB_RNDIS) {
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA) {
data = req->buf;
data[0] = cpu_to_le32(1);
data[1] = cpu_to_le32(0);
@@ -1737,7 +1764,7 @@
/* read the request; process it later */
value = w_length;
req->context = gsi;
- if (gsi->prot_id == IPA_USB_RNDIS)
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA)
req->complete = gsi_rndis_command_complete;
else
req->complete = gsi_ctrl_cmd_complete;
@@ -1749,7 +1776,7 @@
if (w_value || w_index != id)
goto invalid;
- if (gsi->prot_id == IPA_USB_RNDIS) {
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA) {
/* return the result */
buf = rndis_get_next_response(gsi->params, &n);
if (buf) {
@@ -1785,7 +1812,8 @@
case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
line_state = (w_value & GSI_CTRL_DTR ? true : false);
- if (gsi->prot_id == IPA_USB_RMNET)
+ if (gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_RMNET_ETHER)
gsi->rmnet_dtr_status = line_state;
log_event_dbg("%s: USB_CDC_REQ_SET_CONTROL_LINE_STATE DTR:%d\n",
__func__, line_state);
@@ -1882,9 +1910,10 @@
struct f_gsi *gsi = func_to_gsi(f);
/* RNDIS, RMNET and DPL only support alt 0*/
- if (intf == gsi->ctrl_id || gsi->prot_id == IPA_USB_RNDIS ||
- gsi->prot_id == IPA_USB_RMNET ||
- gsi->prot_id == IPA_USB_DIAG)
+ if (intf == gsi->ctrl_id || gsi->prot_id == USB_PROT_RNDIS_IPA ||
+ gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_DIAG_IPA ||
+ is_ext_prot_ether(gsi->prot_id))
return 0;
else if (intf == gsi->data_id)
return gsi->data_interface_up;
@@ -2003,7 +2032,8 @@
log_event_dbg("intf=%u, alt=%u", intf, alt);
/* Control interface has only altsetting 0 */
- if (intf == gsi->ctrl_id || gsi->prot_id == IPA_USB_RMNET) {
+ if (intf == gsi->ctrl_id || gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_RMNET_ETHER) {
if (alt != 0)
goto fail;
@@ -2037,10 +2067,11 @@
if (intf == gsi->data_id) {
gsi->d_port.net_ready_trigger = false;
/* for rndis and rmnet alt is always 0 update alt accordingly */
- if (gsi->prot_id == IPA_USB_RNDIS ||
- gsi->prot_id == IPA_USB_RMNET ||
- gsi->prot_id == IPA_USB_DIAG)
- alt = 1;
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA ||
+ gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_DIAG_IPA ||
+ is_ext_prot_ether(gsi->prot_id))
+ alt = 1;
if (alt > 1)
goto notify_ep_disable;
@@ -2067,8 +2098,9 @@
}
/* Configure EPs for GSI */
- if (gsi->d_port.in_ep) {
- if (gsi->prot_id == IPA_USB_DIAG)
+ if (gsi->d_port.in_ep &&
+ gsi->prot_id <= USB_PROT_DIAG_IPA) {
+ if (gsi->prot_id == USB_PROT_DIAG_IPA)
gsi->d_port.in_ep->ep_intr_num = 3;
else
gsi->d_port.in_ep->ep_intr_num = 2;
@@ -2077,7 +2109,8 @@
GSI_EP_OP_CONFIG);
}
- if (gsi->d_port.out_ep) {
+ if (gsi->d_port.out_ep &&
+ gsi->prot_id <= USB_PROT_DIAG_IPA) {
gsi->d_port.out_ep->ep_intr_num = 1;
usb_gsi_ep_op(gsi->d_port.out_ep,
&gsi->d_port.out_request,
@@ -2086,7 +2119,17 @@
gsi->d_port.gadget = cdev->gadget;
- if (gsi->prot_id == IPA_USB_RNDIS) {
+ if (is_ext_prot_ether(gsi->prot_id)) {
+ net = gether_connect(&gsi->d_port.gether_port);
+ if (IS_ERR(net)) {
+ pr_err("%s:gether_connect err:%ld\n",
+ __func__, PTR_ERR(net));
+ goto notify_ep_disable;
+ }
+ gsi->d_port.gether_port.cdc_filter = 0;
+ }
+
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA) {
gsi_rndis_open(gsi);
net = gsi_rndis_get_netdev("rndis0");
if (IS_ERR(net))
@@ -2098,7 +2141,7 @@
&gsi->d_port.cdc_filter);
}
- if (gsi->prot_id == IPA_USB_ECM)
+ if (gsi->prot_id == USB_PROT_ECM_IPA)
gsi->d_port.cdc_filter = DEFAULT_FILTER;
/*
@@ -2106,7 +2149,7 @@
* handler which is invoked when the host sends the
* GEN_CURRENT_PACKET_FILTER message.
*/
- if (gsi->prot_id != IPA_USB_RNDIS)
+ if (gsi->prot_id != USB_PROT_RNDIS_IPA)
post_event(&gsi->d_port,
EVT_CONNECT_IN_PROGRESS);
queue_work(gsi->d_port.ipa_usb_wq,
@@ -2127,7 +2170,8 @@
atomic_set(&gsi->connected, 1);
/* send 0 len pkt to qti to notify state change */
- if (gsi->prot_id == IPA_USB_DIAG)
+ if (gsi->prot_id == USB_PROT_DIAG_IPA ||
+ gsi->prot_id == USB_PROT_DPL_ETHER)
gsi_ctrl_send_cpkt_tomodem(gsi, NULL, 0);
return 0;
@@ -2145,10 +2189,11 @@
atomic_set(&gsi->connected, 0);
- if (gsi->prot_id == IPA_USB_RNDIS)
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA)
rndis_uninit(gsi->params);
- if (gsi->prot_id == IPA_USB_RMNET)
+ if (gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_RMNET_ETHER)
gsi->rmnet_dtr_status = false;
/* Disable Control Path */
@@ -2171,6 +2216,12 @@
gsi->data_interface_up = false;
log_event_dbg("%s deactivated", gsi->function.name);
+
+ if (is_ext_prot_ether(gsi->prot_id)) {
+ gether_disconnect(&gsi->d_port.gether_port);
+ return;
+ }
+
ipa_disconnect_handler(&gsi->d_port);
post_event(&gsi->d_port, EVT_DISCONNECTED);
queue_work(gsi->d_port.ipa_usb_wq, &gsi->d_port.usb_ipa_w);
@@ -2221,7 +2272,7 @@
* RNDIS_MESSAGE_PACKET_FILTER after performing bus resume.
* Trigger state machine explicitly on resume.
*/
- if (gsi->prot_id == IPA_USB_RNDIS &&
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA &&
!usb_gsi_remote_wakeup_allowed(f))
rndis_flow_control(gsi->params, false);
@@ -2327,7 +2378,7 @@
info->data_nop_desc->bInterfaceNumber = gsi->data_id;
/* allocate instance-specific endpoints */
- if (info->fs_in_desc) {
+ if (info->fs_in_desc && gsi->prot_id <= USB_PROT_DIAG_IPA) {
ep = usb_ep_autoconfig_by_name(cdev->gadget,
info->fs_in_desc, info->in_epname);
if (!ep)
@@ -2335,9 +2386,17 @@
gsi->d_port.in_ep = ep;
msm_ep_config(gsi->d_port.in_ep, NULL);
ep->driver_data = cdev; /* claim */
+ } else {
+ if (info->fs_in_desc) {
+ ep = usb_ep_autoconfig(cdev->gadget, info->fs_in_desc);
+ if (!ep)
+ goto fail;
+ gsi->d_port.in_ep = ep;
+ ep->driver_data = cdev; /* claim */
+ }
}
- if (info->fs_out_desc) {
+ if (info->fs_out_desc && gsi->prot_id <= USB_PROT_DIAG_IPA) {
ep = usb_ep_autoconfig_by_name(cdev->gadget,
info->fs_out_desc, info->out_epname);
if (!ep)
@@ -2345,6 +2404,14 @@
gsi->d_port.out_ep = ep;
msm_ep_config(gsi->d_port.out_ep, NULL);
ep->driver_data = cdev; /* claim */
+ } else {
+ if (info->fs_out_desc) {
+ ep = usb_ep_autoconfig(cdev->gadget, info->fs_out_desc);
+ if (!ep)
+ goto fail;
+ gsi->d_port.out_ep = ep;
+ ep->driver_data = cdev; /* claim */
+ }
}
if (info->fs_notify_desc) {
@@ -2475,14 +2542,17 @@
struct gsi_function_bind_info info = {0};
struct f_gsi *gsi = func_to_gsi(f);
struct rndis_params *params;
+ struct net_device *net;
+ char *name = NULL;
int status;
__u8 class;
__u8 subclass;
__u8 proto;
- if (gsi->prot_id == IPA_USB_RMNET ||
- gsi->prot_id == IPA_USB_DIAG)
+ if (gsi->prot_id == USB_PROT_RMNET_IPA ||
+ gsi->prot_id == USB_PROT_DIAG_IPA ||
+ is_ext_prot_ether(gsi->prot_id))
gsi->ctrl_id = -ENODEV;
else {
status = gsi->ctrl_id = usb_interface_id(c, f);
@@ -2495,7 +2565,7 @@
goto fail;
switch (gsi->prot_id) {
- case IPA_USB_RNDIS:
+ case USB_PROT_RNDIS_IPA:
info.string_defs = rndis_gsi_string_defs;
info.ctrl_desc = &rndis_gsi_control_intf;
info.ctrl_str_idx = 0;
@@ -2641,7 +2711,7 @@
info.ctrl_desc->bInterfaceProtocol = proto;
break;
- case IPA_USB_MBIM:
+ case USB_PROT_MBIM_IPA:
info.string_defs = mbim_gsi_string_defs;
info.ctrl_desc = &mbim_gsi_control_intf;
info.ctrl_str_idx = 0;
@@ -2688,7 +2758,8 @@
c->bConfigurationValue + '0';
}
break;
- case IPA_USB_RMNET:
+ case USB_PROT_RMNET_IPA:
+ case USB_PROT_RMNET_ETHER:
info.string_defs = rmnet_gsi_string_defs;
info.data_desc = &rmnet_gsi_interface_desc;
info.data_str_idx = 0;
@@ -2713,8 +2784,9 @@
info.out_req_buf_len = GSI_OUT_RMNET_BUF_LEN;
info.out_req_num_buf = GSI_NUM_OUT_BUFFERS;
info.notify_buf_len = sizeof(struct usb_cdc_notification);
+ name = "usb_rmnet";
break;
- case IPA_USB_ECM:
+ case USB_PROT_ECM_IPA:
info.string_defs = ecm_gsi_string_defs;
info.ctrl_desc = &ecm_gsi_control_intf;
info.ctrl_str_idx = 0;
@@ -2763,7 +2835,8 @@
gsi->d_port.ipa_init_params.host_ethaddr[5]);
info.string_defs[1].s = gsi->ethaddr;
break;
- case IPA_USB_DIAG:
+ case USB_PROT_DIAG_IPA:
+ case USB_PROT_DPL_ETHER:
info.string_defs = qdss_gsi_string_defs;
info.data_desc = &qdss_gsi_data_intf_desc;
info.data_str_idx = 0;
@@ -2778,6 +2851,7 @@
info.in_req_buf_len = 16384;
info.in_req_num_buf = GSI_NUM_IN_BUFFERS;
info.notify_buf_len = sizeof(struct usb_cdc_notification);
+ name = "dpl_usb";
break;
default:
log_event_err("%s: Invalid prot id %d", __func__,
@@ -2789,6 +2863,29 @@
if (status)
goto dereg_rndis;
+ if (is_ext_prot_ether(gsi->prot_id)) {
+ if (!name)
+ return -EINVAL;
+
+ gsi->d_port.gether_port.in_ep = gsi->d_port.in_ep;
+ gsi->d_port.gether_port.out_ep = gsi->d_port.out_ep;
+ net = gether_setup_name_default(name);
+ if (IS_ERR(net)) {
+ pr_err("%s: gether_setup failed\n", __func__);
+ return PTR_ERR(net);
+ }
+ gsi->d_port.gether_port.ioport = netdev_priv(net);
+ gether_set_gadget(net, c->cdev->gadget);
+ status = gether_register_netdev(net);
+ if (status < 0) {
+ pr_err("%s: gether_register_netdev failed\n",
+ __func__);
+ free_netdev(net);
+ return status;
+ }
+ goto skip_ipa_init;
+ }
+
status = ipa_register_ipa_ready_cb(ipa_ready_callback, gsi);
if (!status) {
log_event_info("%s: ipa is not ready", __func__);
@@ -2814,6 +2911,7 @@
gsi->d_port.sm_state = STATE_INITIALIZED;
+skip_ipa_init:
DBG(cdev, "%s: %s speed IN/%s OUT/%s NOTIFY/%s\n",
f->name,
gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -2836,6 +2934,12 @@
{
struct f_gsi *gsi = func_to_gsi(f);
+ if (is_ext_prot_ether(gsi->prot_id)) {
+ gether_cleanup(gsi->d_port.gether_port.ioport);
+ gsi->d_port.gether_port.ioport = NULL;
+ goto skip_ipa_dinit;
+ }
+
/*
* Use drain_workqueue to accomplish below conditions:
* 1. Make sure that any running work completed
@@ -2847,12 +2951,13 @@
drain_workqueue(gsi->d_port.ipa_usb_wq);
ipa_usb_deinit_teth_prot(gsi->prot_id);
- if (gsi->prot_id == IPA_USB_RNDIS) {
+skip_ipa_dinit:
+ if (gsi->prot_id == USB_PROT_RNDIS_IPA) {
gsi->d_port.sm_state = STATE_UNINITIALIZED;
rndis_deregister(gsi->params);
}
- if (gsi->prot_id == IPA_USB_MBIM)
+ if (gsi->prot_id == USB_PROT_MBIM_IPA)
mbim_gsi_ext_config_desc.function.subCompatibleID[0] = 0;
if (gadget_is_superspeed(c->cdev->gadget)) {
@@ -2883,33 +2988,34 @@
static int gsi_bind_config(struct f_gsi *gsi)
{
int status = 0;
- enum ipa_usb_teth_prot prot_id = gsi->prot_id;
- log_event_dbg("%s: prot id %d", __func__, prot_id);
+ log_event_dbg("%s: prot id %d", __func__, gsi->prot_id);
- switch (prot_id) {
- case IPA_USB_RNDIS:
+ switch (gsi->prot_id) {
+ case USB_PROT_RNDIS_IPA:
gsi->function.name = "rndis";
gsi->function.strings = rndis_gsi_strings;
break;
- case IPA_USB_ECM:
+ case USB_PROT_ECM_IPA:
gsi->function.name = "cdc_ethernet";
gsi->function.strings = ecm_gsi_strings;
break;
- case IPA_USB_RMNET:
+ case USB_PROT_RMNET_IPA:
+ case USB_PROT_RMNET_ETHER:
gsi->function.name = "rmnet";
gsi->function.strings = rmnet_gsi_strings;
break;
- case IPA_USB_MBIM:
+ case USB_PROT_MBIM_IPA:
gsi->function.name = "mbim";
gsi->function.strings = mbim_gsi_strings;
break;
- case IPA_USB_DIAG:
+ case USB_PROT_DIAG_IPA:
+ case USB_PROT_DPL_ETHER:
gsi->function.name = "dpl";
gsi->function.strings = qdss_gsi_strings;
break;
default:
- log_event_err("%s: invalid prot id %d", __func__, prot_id);
+ log_event_err("%s: invalid prot id %d", __func__, gsi->prot_id);
return -EINVAL;
}
@@ -3164,9 +3270,10 @@
static int gsi_set_inst_name(struct usb_function_instance *fi,
const char *name)
{
- int prot_id, name_len, ret = 0;
+ int name_len, ret = 0;
struct gsi_opts *opts;
struct f_gsi *gsi;
+ enum usb_prot_id prot_id;
opts = container_of(fi, struct gsi_opts, func_inst);
@@ -3181,7 +3288,7 @@
return -EINVAL;
}
- if (prot_id == IPA_USB_RNDIS)
+ if (prot_id == USB_PROT_RNDIS_IPA)
config_group_init_type_name(&opts->func_inst.group, "",
&gsi_func_rndis_type);
@@ -3249,7 +3356,7 @@
return -ENOMEM;
}
- for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++) {
+ for (i = 0; i < USB_PROT_MAX; i++) {
__gsi[i] = gsi_function_init();
if (IS_ERR(__gsi[i]))
return PTR_ERR(__gsi[i]);
@@ -3272,7 +3379,7 @@
if (ipc_log_ctxt)
ipc_log_context_destroy(ipc_log_ctxt);
- for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++)
+ for (i = 0; i < USB_PROT_MAX; i++)
kfree(__gsi[i]);
usb_function_unregister(&gsiusb_func);
diff --git a/drivers/usb/gadget/function/f_gsi.h b/drivers/usb/gadget/function/f_gsi.h
index c6e64fd..7e998c4 100644
--- a/drivers/usb/gadget/function/f_gsi.h
+++ b/drivers/usb/gadget/function/f_gsi.h
@@ -27,9 +27,14 @@
#include <linux/ipa_usb.h>
#include <linux/ipc_logging.h>
+#include "u_ether.h"
+
#define GSI_RMNET_CTRL_NAME "rmnet_ctrl"
#define GSI_MBIM_CTRL_NAME "android_mbim"
#define GSI_DPL_CTRL_NAME "dpl_ctrl"
+#define ETHER_RMNET_CTRL_NAME "rmnet_ctrl0"
+#define ETHER_DPL_CTRL_NAME "dpl_ctrl0"
+
#define GSI_CTRL_NAME_LEN (sizeof(GSI_MBIM_CTRL_NAME)+2)
#define GSI_MAX_CTRL_PKT_SIZE 4096
#define GSI_CTRL_DTR (1 << 0)
@@ -114,6 +119,21 @@
RNDIS_ID_MAX,
};
+enum usb_prot_id {
+ /* accelerated: redefined from ipa_usb.h, do not change order */
+ USB_PROT_RNDIS_IPA,
+ USB_PROT_ECM_IPA,
+ USB_PROT_RMNET_IPA,
+ USB_PROT_MBIM_IPA,
+ USB_PROT_DIAG_IPA,
+
+ /* non-accelerated */
+ USB_PROT_RMNET_ETHER,
+ USB_PROT_DPL_ETHER,
+
+ USB_PROT_MAX,
+};
+
#define MAXQUEUELEN 128
struct event_queue {
u8 event[MAXQUEUELEN];
@@ -228,6 +248,7 @@
enum connection_state sm_state;
struct event_queue evt_q;
wait_queue_head_t wait_for_ipa_ready;
+ struct gether gether_port;
/* Track these for debugfs */
struct ipa_usb_xdci_chan_params ipa_in_channel_params;
@@ -237,7 +258,7 @@
struct f_gsi {
struct usb_function function;
- enum ipa_usb_teth_prot prot_id;
+ enum usb_prot_id prot_id;
int ctrl_id;
int data_id;
u32 vendorID;
@@ -285,21 +306,25 @@
func_inst.group);
}
-static enum ipa_usb_teth_prot name_to_prot_id(const char *name)
+static enum usb_prot_id name_to_prot_id(const char *name)
{
if (!name)
goto error;
if (!strncasecmp(name, "rndis", MAX_INST_NAME_LEN))
- return IPA_USB_RNDIS;
+ return USB_PROT_RNDIS_IPA;
if (!strncasecmp(name, "ecm", MAX_INST_NAME_LEN))
- return IPA_USB_ECM;
+ return USB_PROT_ECM_IPA;
if (!strncasecmp(name, "rmnet", MAX_INST_NAME_LEN))
- return IPA_USB_RMNET;
+ return USB_PROT_RMNET_IPA;
if (!strncasecmp(name, "mbim", MAX_INST_NAME_LEN))
- return IPA_USB_MBIM;
+ return USB_PROT_MBIM_IPA;
if (!strncasecmp(name, "dpl", MAX_INST_NAME_LEN))
- return IPA_USB_DIAG;
+ return USB_PROT_DIAG_IPA;
+ if (!strncasecmp(name, "rmnet.ether", MAX_INST_NAME_LEN))
+ return USB_PROT_RMNET_ETHER;
+ if (!strncasecmp(name, "dpl.ether", MAX_INST_NAME_LEN))
+ return USB_PROT_DPL_ETHER;
error:
return -EINVAL;
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index 1979156..4b4ce0e 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -413,7 +413,8 @@
if (err) {
ERROR(midi, "%s: couldn't enqueue request: %d\n",
midi->out_ep->name, err);
- free_ep_req(midi->out_ep, req);
+ if (req->buf != NULL)
+ free_ep_req(midi->out_ep, req);
return err;
}
}
diff --git a/drivers/usb/gadget/function/f_mtp.c b/drivers/usb/gadget/function/f_mtp.c
index 651776d..3f25946 100644
--- a/drivers/usb/gadget/function/f_mtp.c
+++ b/drivers/usb/gadget/function/f_mtp.c
@@ -613,7 +613,17 @@
return -EINVAL;
spin_lock_irq(&dev->lock);
+ if (dev->state == STATE_OFFLINE) {
+ spin_unlock_irq(&dev->lock);
+ return -ENODEV;
+ }
+
if (dev->ep_out->desc) {
+ if (!cdev) {
+ spin_unlock_irq(&dev->lock);
+ return -ENODEV;
+ }
+
len = usb_ep_align_maybe(cdev->gadget, dev->ep_out, count);
if (len > MTP_BULK_BUFFER_SIZE) {
spin_unlock_irq(&dev->lock);
@@ -1498,7 +1508,10 @@
while ((req = mtp_req_get(dev, &dev->intr_idle)))
mtp_request_free(req, dev->ep_intr);
mutex_unlock(&dev->read_mutex);
+ spin_lock_irq(&dev->lock);
dev->state = STATE_OFFLINE;
+ dev->cdev = NULL;
+ spin_unlock_irq(&dev->lock);
kfree(f->os_desc_table);
f->os_desc_n = 0;
fi_mtp->func_inst.f = NULL;
@@ -1554,7 +1567,9 @@
struct usb_composite_dev *cdev = dev->cdev;
DBG(cdev, "mtp_function_disable\n");
+ spin_lock_irq(&dev->lock);
dev->state = STATE_OFFLINE;
+ spin_unlock_irq(&dev->lock);
usb_ep_disable(dev->ep_in);
usb_ep_disable(dev->ep_out);
usb_ep_disable(dev->ep_intr);
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index bc4f9f7..814b4a3e 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -767,7 +767,7 @@
*/
if (!rndis_opts->bound) {
mutex_lock(&rndis_opts->lock);
- rndis_opts->net = gether_setup_default();
+ rndis_opts->net = gether_setup_name_default("rndis");
if (IS_ERR(rndis_opts->net)) {
status = PTR_ERR(rndis_opts->net);
mutex_unlock(&rndis_opts->lock);
diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h
index 7d53a47..2f03334 100644
--- a/drivers/usb/gadget/u_f.h
+++ b/drivers/usb/gadget/u_f.h
@@ -64,7 +64,9 @@
/* Frees a usb_request previously allocated by alloc_ep_req() */
static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
+ WARN_ON(req->buf == NULL);
kfree(req->buf);
+ req->buf = NULL;
usb_ep_free_request(ep, req);
}
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 6959071..0c71938 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -139,10 +139,8 @@
goto out;
ret = ep->ops->disable(ep);
- if (ret) {
- ret = ret;
+ if (ret)
goto out;
- }
ep->enabled = false;
@@ -250,6 +248,9 @@
* arranges to poll once per interval, and the gadget driver usually will
* have queued some data to transfer at that time.
*
+ * Note that @req's ->complete() callback must never be called from
+ * within usb_ep_queue() as that can create deadlock situations.
+ *
* Returns zero, or a negative error code. Endpoints that are not enabled
* report errors; errors will also be
* reported when the usb peripheral is disconnected.
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index a1dedf0..1ce079d 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -489,7 +489,6 @@
static struct platform_driver usb_xhci_driver = {
.probe = xhci_plat_probe,
.remove = xhci_plat_remove,
- .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xhci-hcd",
.pm = DEV_PM_OPS,
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 844a309..e85b9c2 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -114,15 +114,19 @@
}
is_in = epnum & USB_DIR_IN;
- if (is_in) {
- epnum &= 0x0f;
- ep = &musb->endpoints[epnum].ep_in;
- } else {
- ep = &musb->endpoints[epnum].ep_out;
+ epnum &= 0x0f;
+ if (epnum >= MUSB_C_NUM_EPS) {
+ handled = -EINVAL;
+ break;
}
+
+ if (is_in)
+ ep = &musb->endpoints[epnum].ep_in;
+ else
+ ep = &musb->endpoints[epnum].ep_out;
regs = musb->endpoints[epnum].regs;
- if (epnum >= MUSB_C_NUM_EPS || !ep->desc) {
+ if (!ep->desc) {
handled = -EINVAL;
break;
}
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c
index 6111d39..d21823b 100644
--- a/drivers/usb/pd/policy_engine.c
+++ b/drivers/usb/pd/policy_engine.c
@@ -942,7 +942,7 @@
/* check against received length to avoid overrun */
if (bytes_to_copy > len - sizeof(ext_hdr)) {
- usbpd_warn(&pd->dev, "not enough bytes in chunk, expected:%u received:%lu\n",
+ usbpd_warn(&pd->dev, "not enough bytes in chunk, expected:%u received:%zu\n",
bytes_to_copy, len - sizeof(ext_hdr));
bytes_to_copy = len - sizeof(ext_hdr);
}
diff --git a/drivers/usb/phy/phy-msm-qusb.c b/drivers/usb/phy/phy-msm-qusb.c
index 9c33c6e..47db12b 100644
--- a/drivers/usb/phy/phy-msm-qusb.c
+++ b/drivers/usb/phy/phy-msm-qusb.c
@@ -1,5 +1,5 @@
/*
- * 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
@@ -706,7 +706,9 @@
qphy->base + QUSB2PHY_PORT_INTR_CTRL);
/* Disable PHY */
- writel_relaxed(POWER_DOWN,
+ writel_relaxed(POWER_DOWN |
+ readl_relaxed(qphy->base +
+ QUSB2PHY_PORT_POWERDOWN),
qphy->base + QUSB2PHY_PORT_POWERDOWN);
/* Make sure that above write is completed */
wmb();
diff --git a/drivers/usb/phy/phy-msm-ssusb-qmp.c b/drivers/usb/phy/phy-msm-ssusb-qmp.c
index ad3bbf7..1795d24 100644
--- a/drivers/usb/phy/phy-msm-ssusb-qmp.c
+++ b/drivers/usb/phy/phy-msm-ssusb-qmp.c
@@ -25,10 +25,10 @@
#include <linux/clk.h>
#include <linux/reset.h>
-enum core_ldo_levels {
- CORE_LEVEL_NONE = 0,
- CORE_LEVEL_MIN,
- CORE_LEVEL_MAX,
+enum ldo_levels {
+ VOLTAGE_LEVEL_NONE = 0,
+ VOLTAGE_LEVEL_MIN,
+ VOLTAGE_LEVEL_MAX,
};
#define INIT_MAX_TIME_USEC 1000
@@ -38,6 +38,8 @@
#define USB_SSPHY_1P2_VOL_MAX 1200000 /* uV */
#define USB_SSPHY_HPM_LOAD 23000 /* uA */
+#define USB_SSPHY_LOAD_DEFAULT -1
+
/* USB3PHY_PCIE_USB3_PCS_PCS_STATUS bit */
#define PHYSTATUS BIT(6)
@@ -119,6 +121,9 @@
int vdd_levels[3]; /* none, low, high */
struct regulator *core_ldo;
int core_voltage_levels[3];
+ struct regulator *fpc_redrive_ldo;
+ int redrive_voltage_levels[3];
+ int redrive_load;
struct clk *ref_clk_src;
struct clk *ref_clk;
struct clk *aux_clk;
@@ -226,6 +231,33 @@
}
}
+static int msm_ldo_enable(struct msm_ssphy_qmp *phy,
+ struct regulator *ldo, int *voltage_levels, int load)
+{
+ int ret = 0;
+
+ dev_dbg(phy->phy.dev,
+ "ldo: min_vol:%duV max_vol:%duV\n",
+ voltage_levels[VOLTAGE_LEVEL_MIN],
+ voltage_levels[VOLTAGE_LEVEL_MAX]);
+
+ if (load > 0) {
+ ret = regulator_set_load(ldo, load);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = regulator_set_voltage(ldo,
+ voltage_levels[VOLTAGE_LEVEL_MIN],
+ voltage_levels[VOLTAGE_LEVEL_MAX]);
+ if (ret)
+ return ret;
+
+ ret = regulator_enable(ldo);
+
+ return ret;
+}
+
static int msm_ssusb_qmp_ldo_enable(struct msm_ssphy_qmp *phy, int on)
{
int min, rc = 0;
@@ -245,74 +277,65 @@
if (!on)
goto disable_regulators;
- rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
- phy->vdd_levels[2]);
- if (rc) {
- dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
- return rc;
+ if (phy->fpc_redrive_ldo) {
+ rc = msm_ldo_enable(phy, phy->fpc_redrive_ldo,
+ phy->redrive_voltage_levels,
+ phy->redrive_load);
+ if (rc < 0) {
+ dev_err(phy->phy.dev,
+ "enable phy->fpc_redrive_ldo failed\n");
+ return rc;
+ }
+
+ dev_dbg(phy->phy.dev,
+ "fpc redrive ldo: min_vol:%duV max_vol:%duV\n",
+ phy->redrive_voltage_levels[VOLTAGE_LEVEL_MIN],
+ phy->redrive_voltage_levels[VOLTAGE_LEVEL_MAX]);
}
- dev_dbg(phy->phy.dev, "min_vol:%d max_vol:%d\n",
- phy->vdd_levels[min], phy->vdd_levels[2]);
-
- rc = regulator_enable(phy->vdd);
- if (rc) {
- dev_err(phy->phy.dev,
- "regulator_enable(phy->vdd) failed, ret=%d",
- rc);
- goto unconfig_vdd;
- }
-
- rc = regulator_set_load(phy->core_ldo, USB_SSPHY_HPM_LOAD);
+ rc = msm_ldo_enable(phy, phy->vdd, phy->vdd_levels,
+ USB_SSPHY_LOAD_DEFAULT);
if (rc < 0) {
- dev_err(phy->phy.dev, "Unable to set HPM of core_ldo\n");
+ dev_err(phy->phy.dev, "enable phy->vdd failed\n");
+ goto disable_fpc_redrive;
+ }
+
+ dev_dbg(phy->phy.dev,
+ "vdd ldo: min_vol:%duV max_vol:%duV\n",
+ phy->vdd_levels[VOLTAGE_LEVEL_MIN],
+ phy->vdd_levels[VOLTAGE_LEVEL_MAX]);
+
+ rc = msm_ldo_enable(phy, phy->core_ldo, phy->core_voltage_levels,
+ USB_SSPHY_HPM_LOAD);
+ if (rc < 0) {
+ dev_err(phy->phy.dev, "enable phy->core_ldo failed\n");
goto disable_vdd;
}
- rc = regulator_set_voltage(phy->core_ldo,
- phy->core_voltage_levels[CORE_LEVEL_MIN],
- phy->core_voltage_levels[CORE_LEVEL_MAX]);
- if (rc) {
- dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
- goto put_core_ldo_lpm;
- }
-
- rc = regulator_enable(phy->core_ldo);
- if (rc) {
- dev_err(phy->phy.dev, "Unable to enable core_ldo\n");
- goto unset_core_ldo;
- }
+ dev_dbg(phy->phy.dev,
+ "core ldo: min_vol:%duV max_vol:%duV\n",
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MIN],
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MAX]);
return 0;
disable_regulators:
rc = regulator_disable(phy->core_ldo);
if (rc)
- dev_err(phy->phy.dev, "Unable to disable core_ldo\n");
-
-unset_core_ldo:
- rc = regulator_set_voltage(phy->core_ldo,
- phy->core_voltage_levels[CORE_LEVEL_NONE],
- phy->core_voltage_levels[CORE_LEVEL_MAX]);
- if (rc)
- dev_err(phy->phy.dev, "unable to set voltage for core_ldo\n");
-
-put_core_ldo_lpm:
- rc = regulator_set_load(phy->core_ldo, 0);
- if (rc < 0)
- dev_err(phy->phy.dev, "Unable to set LPM of core_ldo\n");
+ dev_err(phy->phy.dev, "disable phy->core_ldo failed\n");
disable_vdd:
rc = regulator_disable(phy->vdd);
if (rc)
- dev_err(phy->phy.dev, "regulator_disable(phy->vdd) failed, ret=%d",
- rc);
+ dev_err(phy->phy.dev, "disable phy->vdd failed\n");
-unconfig_vdd:
- rc = regulator_set_voltage(phy->vdd, phy->vdd_levels[min],
- phy->vdd_levels[2]);
- if (rc)
- dev_err(phy->phy.dev, "unable to set voltage for ssusb vdd\n");
+disable_fpc_redrive:
+ if (phy->fpc_redrive_ldo) {
+ rc = regulator_disable(phy->fpc_redrive_ldo);
+ if (rc)
+ dev_err(phy->phy.dev,
+ "disable phy->fpc_redrive_ldo failed\n");
+ }
return rc < 0 ? rc : 0;
}
@@ -634,6 +657,9 @@
if (suspend) {
if (phy->cable_connected)
msm_ssusb_qmp_enable_autonomous(phy, 1);
+ else
+ writel_relaxed(0x00,
+ phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]);
/* Make sure above write completed with PHY */
wmb();
@@ -944,9 +970,9 @@
}
/* Set default core voltage values */
- phy->core_voltage_levels[CORE_LEVEL_NONE] = 0;
- phy->core_voltage_levels[CORE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
- phy->core_voltage_levels[CORE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
+ phy->core_voltage_levels[VOLTAGE_LEVEL_NONE] = 0;
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MIN] = USB_SSPHY_1P2_VOL_MIN;
+ phy->core_voltage_levels[VOLTAGE_LEVEL_MAX] = USB_SSPHY_1P2_VOL_MAX;
if (of_get_property(dev->of_node, "qcom,core-voltage-level", &len) &&
len == sizeof(phy->core_voltage_levels)) {
@@ -990,6 +1016,39 @@
goto err;
}
+ phy->fpc_redrive_ldo = devm_regulator_get_optional(dev, "fpc-redrive");
+ if (IS_ERR(phy->fpc_redrive_ldo)) {
+ phy->fpc_redrive_ldo = NULL;
+ dev_dbg(dev, "no FPC re-drive ldo regulator\n");
+ } else {
+ if (of_get_property(dev->of_node,
+ "qcom,redrive-voltage-level", &len) &&
+ len == sizeof(phy->redrive_voltage_levels)) {
+ ret = of_property_read_u32_array(dev->of_node,
+ "qcom,redrive-voltage-level",
+ (u32 *) phy->redrive_voltage_levels,
+ len / sizeof(u32));
+ if (ret) {
+ dev_err(dev,
+ "err qcom,redrive-voltage-level\n");
+ goto err;
+ }
+ } else {
+ ret = -EINVAL;
+ dev_err(dev, "err inputs for redrive-voltage-level\n");
+ goto err;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "qcom,redrive-load",
+ &phy->redrive_load);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to read redrive load\n");
+ goto err;
+ }
+
+ dev_dbg(dev, "Get FPC re-drive ldo regulator\n");
+ }
+
platform_set_drvdata(pdev, phy);
if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override"))
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 3178d8a..cab80ac 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -152,6 +152,7 @@
{ USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */
{ USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */
{ USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */
+ { USB_DEVICE(0x155A, 0x1006) }, /* ELDAT Easywave RX09 */
{ USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */
{ USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 0c743e4..71cbc68 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -773,6 +773,7 @@
.driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk },
{ USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) },
{ USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) },
+ { USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) },
{ USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) },
@@ -935,6 +936,7 @@
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_FHE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) },
{ USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 543d280..76a10b2 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -922,6 +922,9 @@
/*
* RT Systems programming cables for various ham radios
*/
+/* This device uses the VID of FTDI */
+#define RTSYSTEMS_USB_VX8_PID 0x9e50 /* USB-VX8 USB to 7 pin modular plug for Yaesu VX-8 radio */
+
#define RTSYSTEMS_VID 0x2100 /* Vendor ID */
#define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */
#define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */
@@ -1441,6 +1444,12 @@
#define FTDI_CINTERION_MC55I_PID 0xA951
/*
+ * Product: FirmwareHubEmulator
+ * Manufacturer: Harman Becker Automotive Systems
+ */
+#define FTDI_FHE_PID 0xA9A0
+
+/*
* Product: Comet Caller ID decoder
* Manufacturer: Crucible Technologies
*/
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index 4340b49..4d6eb48 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -1942,6 +1942,8 @@
bcb->CDB[0] = 0xEF;
result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
+ if (us->srb != NULL)
+ scsi_set_resid(us->srb, 0);
info->BIN_FLAG = flag;
kfree(buf);
@@ -2295,21 +2297,22 @@
static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
{
- int result = 0;
+ int result = USB_STOR_XFER_GOOD;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
/*US_DEBUG(usb_stor_show_command(us, srb)); */
scsi_set_resid(srb, 0);
- if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) {
+ if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready)))
result = ene_init(us);
- } else {
+ if (result == USB_STOR_XFER_GOOD) {
+ result = USB_STOR_TRANSPORT_ERROR;
if (info->SD_Status.Ready)
result = sd_scsi_irp(us, srb);
if (info->MS_Status.Ready)
result = ms_scsi_irp(us, srb);
}
- return 0;
+ return result;
}
static struct scsi_host_template ene_ub6250_host_template;
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index 9f1ec43..7b8a957 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -810,6 +810,7 @@
{
__le16 *ctrl = (__le16 *)(vdev->vconfig + pos -
offset + PCI_EXP_DEVCTL);
+ int readrq = le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ;
count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
if (count < 0)
@@ -835,6 +836,27 @@
pci_try_reset_function(vdev->pdev);
}
+ /*
+ * MPS is virtualized to the user, writes do not change the physical
+ * register since determining a proper MPS value requires a system wide
+ * device view. The MRRS is largely independent of MPS, but since the
+ * user does not have that system-wide view, they might set a safe, but
+ * inefficiently low value. Here we allow writes through to hardware,
+ * but we set the floor to the physical device MPS setting, so that
+ * we can at least use full TLPs, as defined by the MPS value.
+ *
+ * NB, if any devices actually depend on an artificially low MRRS
+ * setting, this will need to be revisited, perhaps with a quirk
+ * though pcie_set_readrq().
+ */
+ if (readrq != (le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ)) {
+ readrq = 128 <<
+ ((le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ) >> 12);
+ readrq = max(readrq, pcie_get_mps(vdev->pdev));
+
+ pcie_set_readrq(vdev->pdev, readrq);
+ }
+
return count;
}
@@ -853,11 +875,12 @@
* Allow writes to device control fields, except devctl_phantom,
* which could confuse IOMMU, MPS, which can break communication
* with other physical devices, and the ARI bit in devctl2, which
- * is set at probe time. FLR gets virtualized via our writefn.
+ * is set at probe time. FLR and MRRS get virtualized via our
+ * writefn.
*/
p_setw(perm, PCI_EXP_DEVCTL,
- PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD,
- ~PCI_EXP_DEVCTL_PHANTOM);
+ PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD |
+ PCI_EXP_DEVCTL_READRQ, ~PCI_EXP_DEVCTL_PHANTOM);
p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI);
return 0;
}
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index e5b7652..487586e 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -524,7 +524,7 @@
if (!len && vq->busyloop_timeout) {
/* Both tx vq and rx socket were polled here */
- mutex_lock(&vq->mutex);
+ mutex_lock_nested(&vq->mutex, 1);
vhost_disable_notify(&net->dev, vq);
preempt_disable();
@@ -657,7 +657,7 @@
struct iov_iter fixup;
__virtio16 num_buffers;
- mutex_lock(&vq->mutex);
+ mutex_lock_nested(&vq->mutex, 0);
sock = vq->private_data;
if (!sock)
goto out;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index cd38f5a..fce49eb 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -211,8 +211,7 @@
if (mask)
vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask);
if (mask & POLLERR) {
- if (poll->wqh)
- remove_wait_queue(poll->wqh, &poll->wait);
+ vhost_poll_stop(poll);
ret = -EINVAL;
}
@@ -1176,14 +1175,14 @@
/* Caller should have vq mutex and device mutex */
int vhost_vq_access_ok(struct vhost_virtqueue *vq)
{
- if (vq->iotlb) {
- /* When device IOTLB was used, the access validation
- * will be validated during prefetching.
- */
+ if (!vq_log_access_ok(vq, vq->log_base))
+ return 0;
+
+ /* Access validation occurs at prefetch time with IOTLB */
+ if (vq->iotlb)
return 1;
- }
- return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) &&
- vq_log_access_ok(vq, vq->log_base);
+
+ return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used);
}
EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 16c8fcf..8c835f1 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -134,7 +134,7 @@
{
int rc;
struct backlight_device *bd = to_backlight_device(dev);
- unsigned long power;
+ unsigned long power, old_power;
rc = kstrtoul(buf, 0, &power);
if (rc)
@@ -145,10 +145,16 @@
if (bd->ops) {
pr_debug("set power to %lu\n", power);
if (bd->props.power != power) {
+ old_power = bd->props.power;
bd->props.power = power;
- backlight_update_status(bd);
+ rc = backlight_update_status(bd);
+ if (rc)
+ bd->props.power = old_power;
+ else
+ rc = count;
+ } else {
+ rc = count;
}
- rc = count;
}
mutex_unlock(&bd->ops_lock);
@@ -176,8 +182,7 @@
else {
pr_debug("set brightness to %lu\n", brightness);
bd->props.brightness = brightness;
- backlight_update_status(bd);
- rc = 0;
+ rc = backlight_update_status(bd);
}
}
mutex_unlock(&bd->ops_lock);
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index d7c239e..f557406 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -177,7 +177,7 @@
struct spi_message msg;
struct spi_transfer xfer = {
.len = 1,
- .cs_change = 1,
+ .cs_change = 0,
.tx_buf = lcd->buf,
};
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index eab1f84..e4bd63e 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -369,7 +369,7 @@
spi_message_init(m);
- x->cs_change = 1;
+ x->cs_change = 0;
x->tx_buf = &lcd->buf[0];
spi_message_add_tail(x, m);
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 6a41ea9..4dc5ee8 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -49,7 +49,7 @@
struct spi_message msg;
struct spi_transfer xfer = {
.len = 1,
- .cs_change = 1,
+ .cs_change = 0,
.tx_buf = buf,
};
diff --git a/drivers/video/fbdev/msm/dsi_host_v2.c b/drivers/video/fbdev/msm/dsi_host_v2.c
index 33775ec..2cca469 100644
--- a/drivers/video/fbdev/msm/dsi_host_v2.c
+++ b/drivers/video/fbdev/msm/dsi_host_v2.c
@@ -753,8 +753,8 @@
}
if (dchdr->wait)
- usleep_range(dchdr->wait * 1000,
- dchdr->wait * 1000);
+ usleep_range((dchdr->wait * 1000),
+ (dchdr->wait * 1000) + 10);
mdss_dsi_buf_init(tp);
len = 0;
diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c
index 591c240..c9db88e 100644
--- a/drivers/video/fbdev/msm/mdp3.c
+++ b/drivers/video/fbdev/msm/mdp3.c
@@ -2111,9 +2111,41 @@
static DEVICE_ATTR(smart_blit, 0664,
mdp3_show_smart_blit, mdp3_store_smart_blit);
+static ssize_t mdp3_store_twm(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ u32 data = -1;
+ ssize_t rc = 0;
+
+ rc = kstrtoint(buf, 10, &data);
+ if (rc) {
+ pr_err("kstrtoint failed. rc=%d\n", rc);
+ return rc;
+ }
+ mdp3_res->twm_en = data ? true : false;
+ pr_err("TWM : %s\n", (mdp3_res->twm_en) ?
+ "ENABLED" : "DISABLED");
+ return len;
+}
+
+static ssize_t mdp3_show_twm(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+
+ pr_err("TWM : %s\n", (mdp3_res->twm_en) ?
+ "ENABLED" : "DISABLED");
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", mdp3_res->twm_en);
+ return ret;
+}
+
+static DEVICE_ATTR(twm_enable, 0664,
+ mdp3_show_twm, mdp3_store_twm);
+
static struct attribute *mdp3_fs_attrs[] = {
&dev_attr_caps.attr,
&dev_attr_smart_blit.attr,
+ &dev_attr_twm_enable.attr,
NULL
};
@@ -2378,6 +2410,7 @@
mdp3_dynamic_clock_gating_ctrl;
mdp3_res->mdss_util->panel_intf_type = mdp3_panel_intf_type;
mdp3_res->mdss_util->panel_intf_status = mdp3_panel_get_intf_status;
+ mdp3_res->twm_en = false;
if (mdp3_res->mdss_util->param_check(mdss_mdp3_panel)) {
mdp3_res->mdss_util->display_disabled = true;
diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h
index 6fb39a7..7132dee 100644
--- a/drivers/video/fbdev/msm/mdp3.h
+++ b/drivers/video/fbdev/msm/mdp3.h
@@ -208,7 +208,7 @@
bool solid_fill_vote_en;
struct list_head reg_bus_clist;
struct mutex reg_bus_lock;
-
+ bool twm_en;
u32 max_bw;
u8 ppp_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)];
diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c
index 589f2df..2d13210 100644
--- a/drivers/video/fbdev/msm/mdp3_ctrl.c
+++ b/drivers/video/fbdev/msm/mdp3_ctrl.c
@@ -983,6 +983,11 @@
return rc;
}
+static bool mdp3_is_twm_en(void)
+{
+ return mdp3_res->twm_en;
+}
+
static int mdp3_ctrl_off(struct msm_fb_data_type *mfd)
{
int rc = 0;
@@ -1025,8 +1030,10 @@
pr_debug("fb%d is off already", mfd->index);
goto off_error;
}
- if (panel && panel->set_backlight)
+ if (panel && panel->set_backlight) {
+ if (!mdp3_is_twm_en())
panel->set_backlight(panel, 0);
+ }
}
/*
@@ -1034,12 +1041,13 @@
* events need to be sent to the interface so that the
* panel can be configured in low power mode
*/
- if (panel->event_handler)
- rc = panel->event_handler(panel, MDSS_EVENT_BLANK,
- (void *) (long int)mfd->panel_power_state);
- if (rc)
- pr_err("EVENT_BLANK error (%d)\n", rc);
-
+ if (!mdp3_is_twm_en()) {
+ if (panel->event_handler)
+ rc = panel->event_handler(panel, MDSS_EVENT_BLANK,
+ (void *) (long int)mfd->panel_power_state);
+ if (rc)
+ pr_err("EVENT_BLANK error (%d)\n", rc);
+ }
if (intf_stopped) {
if (!mdp3_session->clk_on)
mdp3_ctrl_clk_enable(mfd, 1);
@@ -1065,9 +1073,27 @@
mdp3_irq_deregister();
}
- if (panel->event_handler)
- rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF,
- (void *) (long int)mfd->panel_power_state);
+ if (panel->event_handler) {
+ if (mdp3_is_twm_en()) {
+ pr_info("TWM active skip panel off, disable disp_en\n");
+ if (gpio_is_valid(panel->panel_en_gpio)) {
+ rc = gpio_direction_output(
+ panel->panel_en_gpio, 1);
+ if (rc) {
+ pr_err("%s:set dir for gpio(%d) FAIL\n",
+ __func__, panel->panel_en_gpio);
+ } else {
+ gpio_set_value((panel->panel_en_gpio), 0);
+ usleep_range(100, 110);
+ pr_debug("%s:set disp_en_gpio_%d Low\n",
+ __func__, panel->panel_en_gpio);
+ }
+ }
+ } else {
+ rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF,
+ (void *) (long int)mfd->panel_power_state);
+ }
+ }
if (rc)
pr_err("EVENT_PANEL_OFF error (%d)\n", rc);
@@ -2870,6 +2896,7 @@
mdp3_interface->configure_panel = mdp3_update_panel_info;
mdp3_interface->input_event_handler = NULL;
mdp3_interface->signal_retire_fence = NULL;
+ mdp3_interface->is_twm_en = mdp3_is_twm_en;
mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL);
if (!mdp3_session)
diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c
index 9253a69..6095073 100644
--- a/drivers/video/fbdev/msm/mdp3_ppp.c
+++ b/drivers/video/fbdev/msm/mdp3_ppp.c
@@ -196,12 +196,20 @@
if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
((req->src_rect.y + req->src_rect.h) > req->src.height)) {
+ pr_err("%s: src roi (x=%d,y=%d,w=%d, h=%d) WxH(%dx%d)\n",
+ __func__, req->src_rect.x, req->src_rect.y,
+ req->src_rect.w, req->src_rect.h, req->src.width,
+ req->src.height);
pr_err("%s: src roi larger than boundary\n", __func__);
return -EINVAL;
}
if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) {
+ pr_err("%s: dst roi (x=%d,y=%d,w=%d, h=%d) WxH(%dx%d)\n",
+ __func__, req->dst_rect.x, req->dst_rect.y,
+ req->dst_rect.w, req->dst_rect.h, req->dst.width,
+ req->dst.height);
pr_err("%s: dst roi larger than boundary\n", __func__);
return -EINVAL;
}
diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c
index f38d40c..7d07040 100644
--- a/drivers/video/fbdev/msm/mdss_debug.c
+++ b/drivers/video/fbdev/msm/mdss_debug.c
@@ -46,6 +46,42 @@
#define INVALID_XIN_ID 0xFF
+static u32 dsi_dbg_bus_sdm660[] = {
+ 0x0001, 0x1001, 0x0001, 0x0011,
+ 0x1021, 0x0021, 0x0031, 0x0041,
+ 0x0051, 0x0061, 0x3061, 0x0061,
+ 0x2061, 0x2061, 0x1061, 0x1061,
+ 0x1061, 0x0071, 0x0071, 0x0071,
+ 0x0081, 0x0081, 0x00A1, 0x00A1,
+ 0x10A1, 0x20A1, 0x30A1, 0x10A1,
+ 0x10A1, 0x30A1, 0x20A1, 0x00B1,
+ 0x00C1, 0x00C1, 0x10C1, 0x20C1,
+ 0x30C1, 0x00D1, 0x00D1, 0x20D1,
+ 0x30D1, 0x00E1, 0x00E1, 0x00E1,
+ 0x00F1, 0x00F1, 0x0101, 0x0101,
+ 0x1101, 0x2101, 0x3101, 0x0111,
+ 0x0141, 0x1141, 0x0141, 0x1141,
+ 0x1141, 0x0151, 0x0151, 0x1151,
+ 0x2151, 0x3151, 0x0161, 0x0161,
+ 0x1161, 0x0171, 0x0171, 0x0181,
+ 0x0181, 0x0191, 0x0191, 0x01A1,
+ 0x01A1, 0x01B1, 0x01B1, 0x11B1,
+ 0x21B1, 0x01C1, 0x01C1, 0x11C1,
+ 0x21C1, 0x31C1, 0x01D1, 0x01D1,
+ 0x01D1, 0x01D1, 0x11D1, 0x21D1,
+ 0x21D1, 0x01E1, 0x01E1, 0x01F1,
+ 0x01F1, 0x0201, 0x0201, 0x0211,
+ 0x0221, 0x0231, 0x0241, 0x0251,
+ 0x0281, 0x0291, 0x0281, 0x0291,
+ 0x02A1, 0x02B1, 0x02C1, 0x0321,
+ 0x0321, 0x1321, 0x2321, 0x3321,
+ 0x0331, 0x0331, 0x1331, 0x0341,
+ 0x0341, 0x1341, 0x2341, 0x3341,
+ 0x0351, 0x0361, 0x0361, 0x1361,
+ 0x2361, 0x0371, 0x0381, 0x0391,
+ 0x03C1, 0x03D1, 0x03E1, 0x03F1,
+};
+
static DEFINE_MUTEX(mdss_debug_lock);
static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00};
@@ -1377,6 +1413,38 @@
}
} else {
if (block_id <= DISPLAY_MISR_HDMI) {
+ /*
+ * In Dual LM single display configuration,
+ * the interface number (i.e. block_id)
+ * might not be the one given from ISR.
+ * We should always check with the actual
+ * intf_num from ctl.
+ */
+ struct msm_fb_data_type *mfd = NULL;
+
+ /*
+ * ISR pass in NULL ctl, so we need to get it
+ * from the mdata.
+ */
+ if (!ctl && mdata->mixer_intf)
+ ctl = mdata->mixer_intf->ctl;
+ if (ctl)
+ mfd = ctl->mfd;
+ if (mfd && is_dual_lm_single_display(mfd)) {
+ switch (ctl->intf_num) {
+ case MDSS_MDP_INTF1:
+ block_id = DISPLAY_MISR_DSI0;
+ break;
+ case MDSS_MDP_INTF2:
+ block_id = DISPLAY_MISR_DSI1;
+ break;
+ default:
+ pr_err("Unmatch INTF for Dual LM single display configuration, INTF:%d\n",
+ ctl->intf_num);
+ return NULL;
+ }
+ }
+
intf_base = (char *)mdss_mdp_get_intf_base_addr(
mdata, block_id);
@@ -1390,11 +1458,15 @@
/*
* extra offset required for
- * cmd misr in 8996
+ * cmd misr in 8996 and mdss3.x
*/
if (IS_MDSS_MAJOR_MINOR_SAME(
mdata->mdp_rev,
- MDSS_MDP_HW_REV_107)) {
+ MDSS_MDP_HW_REV_107) ||
+ (mdata->mdp_rev ==
+ MDSS_MDP_HW_REV_300) ||
+ (mdata->mdp_rev ==
+ MDSS_MDP_HW_REV_301)) {
ctrl_reg += 0x8;
value_reg += 0x8;
}
@@ -1786,6 +1858,24 @@
}
+void mdss_dsi_debug_bus_init(struct mdss_dsi_data *sdata)
+{
+ if (!sdata)
+ return;
+
+ sdata->dbg_bus = NULL;
+ sdata->dbg_bus_size = 0;
+
+ switch (sdata->shared_data->hw_rev) {
+ case MDSS_DSI_HW_REV_201:
+ sdata->dbg_bus = dsi_dbg_bus_sdm660;
+ sdata->dbg_bus_size = ARRAY_SIZE(dsi_dbg_bus_sdm660);
+ break;
+ default:
+ break;
+ }
+}
+
int mdss_dump_misr_data(char **buf, u32 size)
{
struct mdss_mdp_misr_map *dsi0_map;
diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h
index 0d482c0..64df339 100644
--- a/drivers/video/fbdev/msm/mdss_debug.h
+++ b/drivers/video/fbdev/msm/mdss_debug.h
@@ -78,8 +78,8 @@
#define MDSS_XLOG_IOMMU(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_IOMMU, \
##__VA_ARGS__, DATA_LIMITER)
-#define ATRACE_END(name) trace_mdss_mark_write(current->tgid, name, 0)
-#define ATRACE_BEGIN(name) trace_mdss_mark_write(current->tgid, name, 1)
+#define ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0)
+#define ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1)
#define ATRACE_FUNC() ATRACE_BEGIN(__func__)
#define ATRACE_INT(name, value) \
@@ -173,6 +173,7 @@
void mdss_dump_reg(const char *dump_name, u32 reg_dump_flag, char *addr,
int len, u32 **dump_mem, bool from_isr);
void mdss_mdp_debug_mid(u32 mid);
+void mdss_dump_dsi_debug_bus(u32 bus_dump_flag, u32 **dump_mem);
#else
struct mdss_debug_base;
struct dump_offset;
diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c
index a651b55..7bf4f11 100644
--- a/drivers/video/fbdev/msm/mdss_debug_xlog.c
+++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c
@@ -32,6 +32,7 @@
#define XLOG_DEFAULT_REGDUMP 0x2 /* dump in RAM */
#define XLOG_DEFAULT_DBGBUSDUMP 0x2 /* dump in RAM */
#define XLOG_DEFAULT_VBIF_DBGBUSDUMP 0x2 /* dump in RAM */
+#define XLOG_DEFAULT_DSI_DBGBUSDUMP 0x2 /* dump in RAM */
/*
* xlog will print this number of entries when it is called through
@@ -73,14 +74,17 @@
u32 enable_reg_dump;
u32 enable_dbgbus_dump;
u32 enable_vbif_dbgbus_dump;
+ u32 enable_dsi_dbgbus_dump;
struct work_struct xlog_dump_work;
struct mdss_debug_base *blk_arr[MDSS_DEBUG_BASE_MAX];
bool work_panic;
bool work_dbgbus;
bool work_vbif_dbgbus;
+ bool work_dsi_dbgbus;
u32 *dbgbus_dump; /* address for the debug bus dump */
u32 *vbif_dbgbus_dump; /* address for the vbif debug bus dump */
u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */
+ u32 *dsi_dbgbus_dump; /* address for the dsi debug bus dump */
} mdss_dbg_xlog;
static inline bool mdss_xlog_is_enabled(u32 flag)
@@ -572,7 +576,7 @@
static void mdss_xlog_dump_array(struct mdss_debug_base *blk_arr[],
u32 len, bool dead, const char *name, bool dump_dbgbus,
- bool dump_vbif_dbgbus)
+ bool dump_vbif_dbgbus, bool dump_dsi_dbgbus)
{
int i;
@@ -596,6 +600,10 @@
&mdss_dbg_xlog.nrt_vbif_dbgbus_dump, false);
}
+ if (dump_dsi_dbgbus)
+ mdss_dump_dsi_debug_bus(mdss_dbg_xlog.enable_dsi_dbgbus_dump,
+ &mdss_dbg_xlog.dsi_dbgbus_dump);
+
if (dead && mdss_dbg_xlog.panic_on_err)
panic(name);
}
@@ -607,7 +615,8 @@
ARRAY_SIZE(mdss_dbg_xlog.blk_arr),
mdss_dbg_xlog.work_panic, "xlog_workitem",
mdss_dbg_xlog.work_dbgbus,
- mdss_dbg_xlog.work_vbif_dbgbus);
+ mdss_dbg_xlog.work_vbif_dbgbus,
+ mdss_dbg_xlog.work_dsi_dbgbus);
}
void mdss_xlog_tout_handler_default(bool queue, const char *name, ...)
@@ -615,6 +624,7 @@
int i, index = 0;
bool dead = false;
bool dump_dbgbus = false, dump_vbif_dbgbus = false;
+ bool dump_dsi_dbgbus = false;
va_list args;
char *blk_name = NULL;
struct mdss_debug_base *blk_base = NULL;
@@ -650,6 +660,9 @@
if (!strcmp(blk_name, "vbif_dbg_bus"))
dump_vbif_dbgbus = true;
+ if (!strcmp(blk_name, "dsi_dbg_bus"))
+ dump_dsi_dbgbus = true;
+
if (!strcmp(blk_name, "panic"))
dead = true;
}
@@ -660,10 +673,11 @@
mdss_dbg_xlog.work_panic = dead;
mdss_dbg_xlog.work_dbgbus = dump_dbgbus;
mdss_dbg_xlog.work_vbif_dbgbus = dump_vbif_dbgbus;
+ mdss_dbg_xlog.work_dsi_dbgbus = dump_dsi_dbgbus;
schedule_work(&mdss_dbg_xlog.xlog_dump_work);
} else {
mdss_xlog_dump_array(blk_arr, blk_len, dead, name, dump_dbgbus,
- dump_vbif_dbgbus);
+ dump_vbif_dbgbus, dump_dsi_dbgbus);
}
}
@@ -752,6 +766,7 @@
mdss_dbg_xlog.enable_reg_dump = XLOG_DEFAULT_REGDUMP;
mdss_dbg_xlog.enable_dbgbus_dump = XLOG_DEFAULT_DBGBUSDUMP;
mdss_dbg_xlog.enable_vbif_dbgbus_dump = XLOG_DEFAULT_VBIF_DBGBUSDUMP;
+ mdss_dbg_xlog.enable_dsi_dbgbus_dump = XLOG_DEFAULT_DSI_DBGBUSDUMP;
pr_info("xlog_status: enable:%d, panic:%d, dump:%d\n",
mdss_dbg_xlog.xlog_enable, mdss_dbg_xlog.panic_on_err,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index d8e74da..d3e5269 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -27,6 +27,7 @@
#include <linux/msm-bus.h>
#include <linux/pm_qos.h>
#include <linux/mdss_io_util.h>
+#include <linux/dma-buf.h>
#include "mdss.h"
#include "mdss_panel.h"
@@ -46,6 +47,97 @@
static struct pm_qos_request mdss_dsi_pm_qos_request;
+void mdss_dump_dsi_debug_bus(u32 bus_dump_flag,
+ u32 **dump_mem)
+{
+ struct mdss_dsi_data *sdata = mdss_dsi_res;
+ struct mdss_dsi_ctrl_pdata *m_ctrl, *s_ctrl;
+ bool in_log, in_mem;
+ u32 *dump_addr = NULL;
+ u32 status0 = 0, status1 = 0;
+ phys_addr_t phys = 0;
+ int list_size = 0;
+ int i;
+ bool dsi0_active = false, dsi1_active = false;
+
+ if (!sdata || !sdata->dbg_bus || !sdata->dbg_bus_size)
+ return;
+
+ m_ctrl = sdata->ctrl_pdata[0];
+ s_ctrl = sdata->ctrl_pdata[1];
+
+ if (!m_ctrl)
+ return;
+
+ if (m_ctrl && m_ctrl->shared_data->dsi0_active)
+ dsi0_active = true;
+ if (s_ctrl && s_ctrl->shared_data->dsi1_active)
+ dsi1_active = true;
+
+ list_size = (sdata->dbg_bus_size * sizeof(sdata->dbg_bus[0]) * 4);
+
+ in_log = (bus_dump_flag & MDSS_DBG_DUMP_IN_LOG);
+ in_mem = (bus_dump_flag & MDSS_DBG_DUMP_IN_MEM);
+
+ if (in_mem) {
+ if (!(*dump_mem))
+ *dump_mem = dma_alloc_coherent(&sdata->pdev->dev,
+ list_size, &phys, GFP_KERNEL);
+
+ if (*dump_mem) {
+ dump_addr = *dump_mem;
+ pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n",
+ __func__, dump_addr, dump_addr + list_size);
+ } else {
+ in_mem = false;
+ pr_err("dump_mem: allocation fails\n");
+ }
+ }
+
+ pr_info("========= Start DSI Debug Bus =========\n");
+
+ mdss_dsi_clk_ctrl(m_ctrl, m_ctrl->dsi_clk_handle,
+ MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_ON);
+
+ for (i = 0; i < sdata->dbg_bus_size; i++) {
+ if (dsi0_active) {
+ writel_relaxed(sdata->dbg_bus[i],
+ m_ctrl->ctrl_base + 0x124);
+ wmb(); /* ensure regsiter is committed */
+ }
+ if (dsi1_active) {
+ writel_relaxed(sdata->dbg_bus[i],
+ s_ctrl->ctrl_base + 0x124);
+ wmb(); /* ensure register is committed */
+ }
+
+ if (dsi0_active) {
+ status0 = readl_relaxed(m_ctrl->ctrl_base + 0x128);
+ if (in_log)
+ pr_err("CTRL:0 bus_ctrl: 0x%x status: 0x%x\n",
+ sdata->dbg_bus[i], status0);
+ }
+ if (dsi1_active) {
+ status1 = readl_relaxed(s_ctrl->ctrl_base + 0x128);
+ if (in_log)
+ pr_err("CTRL:1 bus_ctrl: 0x%x status: 0x%x\n",
+ sdata->dbg_bus[i], status1);
+ }
+
+ if (dump_addr && in_mem) {
+ dump_addr[i*4] = sdata->dbg_bus[i];
+ dump_addr[i*4 + 1] = status0;
+ dump_addr[i*4 + 2] = status1;
+ dump_addr[i*4 + 3] = 0x0;
+ }
+ }
+
+ mdss_dsi_clk_ctrl(m_ctrl, m_ctrl->dsi_clk_handle,
+ MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF);
+
+ pr_info("========End DSI Debug Bus=========\n");
+}
+
static void mdss_dsi_pm_qos_add_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
struct irq_info *irq_info;
@@ -1704,7 +1796,8 @@
ATRACE_BEGIN("dsi_panel_off");
ret = ctrl_pdata->off(pdata);
if (ret) {
- pr_err("%s: Panel OFF failed\n", __func__);
+ pr_err("%s: Panel OFF failed\n",
+ __func__);
goto error;
}
ATRACE_END("dsi_panel_off");
@@ -3340,6 +3433,8 @@
else
ctrl_pdata->shared_data->dsi1_active = true;
+ mdss_dsi_debug_bus_init(mdss_dsi_res);
+
return 0;
error_shadow_clk_deinit:
@@ -4069,6 +4164,7 @@
if (!gpio_is_valid(ctrl_pdata->disp_en_gpio))
pr_debug("%s:%d, Disp_en gpio not specified\n",
__func__, __LINE__);
+ pdata->panel_en_gpio = ctrl_pdata->disp_en_gpio;
}
ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node,
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index fd6c4d9..5e921ff 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -57,7 +57,7 @@
#define MDSS_DSI_HW_REV_104 0x10040000 /* 8996 */
#define MDSS_DSI_HW_REV_104_1 0x10040001 /* 8996 */
#define MDSS_DSI_HW_REV_104_2 0x10040002 /* 8937 */
-
+#define MDSS_DSI_HW_REV_201 20010000 /* 660 */
#define MDSS_DSI_HW_REV_STEP_0 0x0
#define MDSS_DSI_HW_REV_STEP_1 0x1
#define MDSS_DSI_HW_REV_STEP_2 0x2
@@ -297,6 +297,8 @@
* mutex, clocks, regulator information, setup information
*/
struct dsi_shared_data *shared_data;
+ u32 *dbg_bus;
+ int dbg_bus_size;
};
/*
@@ -407,7 +409,7 @@
int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
void (*switch_mode)(struct mdss_panel_data *pdata, int mode);
struct mdss_panel_data panel_data;
- unsigned char *ctrl_base;
+ unsigned char __iomem *ctrl_base;
struct mdss_io_data ctrl_io;
struct mdss_io_data mmss_misc_io;
struct mdss_io_data phy_io;
@@ -684,6 +686,8 @@
int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata, int power_state);
+void mdss_dsi_debug_bus_init(struct mdss_dsi_data *sdata);
+
static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module)
{
switch (module) {
diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c
index 7d737b5..f425620 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_host.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_host.c
@@ -161,7 +161,14 @@
MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid,
client);
- if (enable == 0) {
+ /*
+ * ensure that before going into ecg or turning
+ * off the clocks, cmd_mdp_busy is not true. During a
+ * race condition, clocks are turned off and so the
+ * isr for cmd_mdp_busy does not get cleared in hw.
+ */
+ if (enable == MDSS_DSI_CLK_OFF ||
+ enable == MDSS_DSI_CLK_EARLY_GATE) {
/* need wait before disable */
mutex_lock(&ctrl->cmd_mutex);
mdss_dsi_cmd_mdp_busy(ctrl);
@@ -1155,6 +1162,8 @@
rc = mdss_dsi_cmdlist_put(ctrl, &cmdreq);
if (rc <= 0) {
+ if (!mdss_dsi_sync_wait_enable(ctrl) ||
+ mdss_dsi_sync_wait_trigger(ctrl))
pr_err("%s: get status: fail\n", __func__);
return rc;
}
@@ -1242,6 +1251,15 @@
{
u32 data, offset;
+ if (!dsc) {
+ if (ctrl->panel_mode == DSI_VIDEO_MODE)
+ offset = MDSS_DSI_VIDEO_COMPRESSION_MODE_CTRL;
+ else
+ offset = MDSS_DSI_COMMAND_COMPRESSION_MODE_CTRL;
+ MIPI_OUTP((ctrl->ctrl_base) + offset, 0);
+ return;
+ }
+
if (dsc->pkt_per_line <= 0) {
pr_err("%s: Error: pkt_per_line cannot be negative or 0\n",
__func__);
@@ -1430,8 +1448,7 @@
MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, stream_total);
}
- if (dsc) /* compressed */
- mdss_dsi_dsc_config(ctrl_pdata, dsc);
+ mdss_dsi_dsc_config(ctrl_pdata, dsc);
}
void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl)
@@ -1488,6 +1505,8 @@
/* mask out overflow errors */
if (ignore_underflow)
mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0x0f0000);
+
+ MDSS_XLOG(ctrl_pdata->ndx, ctrl_pdata->mdp_busy);
MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger */
wmb(); /* ensure write is finished before progressing */
@@ -1689,8 +1708,8 @@
__func__, cm->payload[0], len);
if (!wait || dchdr->wait > VSYNC_PERIOD)
- usleep_range(dchdr->wait * 1000,
- dchdr->wait * 1000);
+ usleep_range((dchdr->wait * 1000),
+ (dchdr->wait * 1000) + 10);
mdss_dsi_buf_init(tp);
len = 0;
@@ -2108,6 +2127,7 @@
MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01);
wmb(); /* ensure write is finished before progressing */
+ MDSS_XLOG(ctrl->dma_addr, len);
if (ctrl->do_unicast) {
/* let cmd_trigger to kickoff later */
@@ -2186,6 +2206,7 @@
bool ack_error = false;
char reg[16];
int repeated_bytes = 0;
+ struct mdss_dsi_ctrl_pdata *mctrl = mdss_dsi_get_other_ctrl(ctrl);
lp = (u32 *)rp->data;
temp = (u32 *)reg;
@@ -2246,7 +2267,11 @@
off += ((cnt - 1) * 4);
for (i = 0; i < cnt; i++) {
- data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
+ if (mdss_dsi_sync_wait_trigger(ctrl))
+ data = (u32)MIPI_INP((mctrl->ctrl_base) + off);
+ else
+ data = (u32)MIPI_INP((ctrl->ctrl_base) + off);
+
/* to network byte order */
if (!repeated_bytes)
*lp++ = ntohl(data);
@@ -2974,7 +2999,10 @@
* warning message is ignored.
*/
if (ctrl->panel_data.panel_info.esd_check_enabled &&
- (ctrl->status_mode == ESD_BTA) && (status & 0x1008000))
+ ((ctrl->status_mode == ESD_BTA) ||
+ (ctrl->status_mode == ESD_REG) ||
+ (ctrl->status_mode == ESD_REG_NT35596)) &&
+ (status & 0x1008000))
return false;
pr_err("%s: status=%x\n", __func__, status);
@@ -3127,7 +3155,7 @@
pr_err("%s: panic in WQ as dsi error intrs within:%dms\n",
__func__, err_container->err_time_delta);
MDSS_XLOG_TOUT_HANDLER_WQ("mdp", "dsi0_ctrl", "dsi0_phy",
- "dsi1_ctrl", "dsi1_phy");
+ "dsi1_ctrl", "dsi1_phy", "dsi_dbg_bus", "panic");
}
}
@@ -3205,8 +3233,10 @@
* cleared.
*/
if (ctrl->panel_data.panel_info.esd_check_enabled &&
- (ctrl->status_mode == ESD_BTA) &&
- (ctrl->panel_mode == DSI_VIDEO_MODE)) {
+ ((ctrl->status_mode == ESD_BTA) ||
+ (ctrl->status_mode == ESD_REG) ||
+ (ctrl->status_mode == ESD_REG_NT35596)) &&
+ (ctrl->panel_mode == DSI_VIDEO_MODE)) {
isr &= ~DSI_INTR_ERROR;
/* clear only overflow */
mdss_dsi_set_reg(ctrl, 0x0c, 0x44440000, 0x44440000);
@@ -3215,6 +3245,7 @@
}
if (isr & DSI_INTR_VIDEO_DONE) {
+ MDSS_XLOG(ctrl->ndx, isr, 0x111);
spin_lock(&ctrl->mdp_lock);
mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM);
complete(&ctrl->video_comp);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 1688503..e586667 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -427,6 +427,8 @@
__func__);
goto exit;
}
+ gpio_set_value((ctrl_pdata->disp_en_gpio), 1);
+ usleep_range(100, 110);
}
if (pdata->panel_info.rst_seq_len) {
@@ -443,8 +445,8 @@
gpio_set_value((ctrl_pdata->rst_gpio),
pdata->panel_info.rst_seq[i]);
if (pdata->panel_info.rst_seq[++i])
- usleep_range(pinfo->rst_seq[i] * 1000,
- pinfo->rst_seq[i] * 1000);
+ usleep_range((pinfo->rst_seq[i] * 1000),
+ (pinfo->rst_seq[i] * 1000) + 10);
}
if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) {
@@ -497,6 +499,7 @@
}
if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) {
gpio_set_value((ctrl_pdata->disp_en_gpio), 0);
+ usleep_range(100, 110);
gpio_free(ctrl_pdata->disp_en_gpio);
}
gpio_set_value((ctrl_pdata->rst_gpio), 0);
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 27299d10..72f651e 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1161,11 +1161,24 @@
if (pdata->next) {
spt = mdss_panel_get_timing_by_name(pdata->next,
modedb[i].name);
- if (!IS_ERR_OR_NULL(spt))
+ /* for split config, recalculate xres and pixel clock */
+ if (!IS_ERR_OR_NULL(spt)) {
+ unsigned long pclk, h_total, v_total;
modedb[i].xres += spt->xres;
- else
+ h_total = modedb[i].xres +
+ modedb[i].left_margin +
+ modedb[i].right_margin +
+ modedb[i].hsync_len;
+ v_total = modedb[i].yres +
+ modedb[i].lower_margin +
+ modedb[i].upper_margin +
+ modedb[i].vsync_len;
+ pclk = h_total * v_total * modedb[i].refresh;
+ modedb[i].pixclock = KHZ2PICOS(pclk / 1000);
+ } else {
pr_debug("no matching split config for %s\n",
modedb[i].name);
+ }
/*
* if no panel timing found for current, need to
@@ -1653,6 +1666,7 @@
u32 temp = bkl_lvl;
bool ad_bl_notify_needed = false;
bool bl_notify_needed = false;
+ bool twm_en = false;
if ((((mdss_fb_is_power_off(mfd) && mfd->dcm_state != DCM_ENTER)
|| !mfd->allow_bl_update) && !IS_CALIB_MODE_BL(mfd)) ||
@@ -1687,9 +1701,17 @@
if (mfd->bl_level != bkl_lvl)
bl_notify_needed = true;
pr_debug("backlight sent to panel :%d\n", temp);
- pdata->set_backlight(pdata, temp);
- mfd->bl_level = bkl_lvl;
- mfd->bl_level_scaled = temp;
+
+ if (mfd->mdp.is_twm_en)
+ twm_en = mfd->mdp.is_twm_en();
+
+ if (twm_en) {
+ pr_info("TWM Enabled skip backlight update\n");
+ } else {
+ pdata->set_backlight(pdata, temp);
+ mfd->bl_level = bkl_lvl;
+ mfd->bl_level_scaled = temp;
+ }
}
if (ad_bl_notify_needed)
mdss_fb_bl_update_notify(mfd,
@@ -4730,6 +4752,9 @@
if (!mfd || !mfd->panel_info)
return -EINVAL;
+ /* make sure that we are idle while switching */
+ mdss_fb_wait_for_kickoff(mfd);
+
pinfo = mfd->panel_info;
if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_SUSPEND_RESUME) {
ret = mdss_fb_blanking_mode_switch(mfd, mode);
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index c85f033..5f2baef 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -236,6 +236,7 @@
int (*pp_release_fnc)(struct msm_fb_data_type *mfd);
void (*signal_retire_fence)(struct msm_fb_data_type *mfd,
int retire_cnt);
+ bool (*is_twm_en)(void);
void *private1;
};
diff --git a/drivers/video/fbdev/msm/mdss_io_util.c b/drivers/video/fbdev/msm/mdss_io_util.c
index 3117793..2f70ad3 100644
--- a/drivers/video/fbdev/msm/mdss_io_util.c
+++ b/drivers/video/fbdev/msm/mdss_io_util.c
@@ -275,8 +275,8 @@
}
need_sleep = !regulator_is_enabled(in_vreg[i].vreg);
if (in_vreg[i].pre_on_sleep && need_sleep)
- usleep_range(in_vreg[i].pre_on_sleep * 1000,
- in_vreg[i].pre_on_sleep * 1000);
+ usleep_range((in_vreg[i].pre_on_sleep * 1000),
+ (in_vreg[i].pre_on_sleep * 1000) + 10);
rc = regulator_set_load(in_vreg[i].vreg,
in_vreg[i].load[DSS_REG_MODE_ENABLE]);
if (rc < 0) {
@@ -287,8 +287,8 @@
}
rc = regulator_enable(in_vreg[i].vreg);
if (in_vreg[i].post_on_sleep && need_sleep)
- usleep_range(in_vreg[i].post_on_sleep * 1000,
- in_vreg[i].post_on_sleep * 1000);
+ usleep_range((in_vreg[i].post_on_sleep * 1000),
+ (in_vreg[i].post_on_sleep * 1000) + 10);
if (rc < 0) {
DEV_ERR("%pS->%s: %s enable failed\n",
__builtin_return_address(0), __func__,
@@ -299,8 +299,8 @@
} else {
for (i = num_vreg-1; i >= 0; i--) {
if (in_vreg[i].pre_off_sleep)
- usleep_range(in_vreg[i].pre_off_sleep * 1000,
- in_vreg[i].pre_off_sleep * 1000);
+ usleep_range((in_vreg[i].pre_off_sleep * 1000),
+ (in_vreg[i].pre_off_sleep * 1000) + 10);
regulator_set_load(in_vreg[i].vreg,
in_vreg[i].load[DSS_REG_MODE_DISABLE]);
@@ -308,8 +308,8 @@
regulator_disable(in_vreg[i].vreg);
if (in_vreg[i].post_off_sleep)
- usleep_range(in_vreg[i].post_off_sleep * 1000,
- in_vreg[i].post_off_sleep * 1000);
+ usleep_range((in_vreg[i].post_off_sleep * 1000),
+ (in_vreg[i].post_off_sleep * 1000) + 10);
}
}
return rc;
@@ -321,14 +321,14 @@
vreg_set_opt_mode_fail:
for (i--; i >= 0; i--) {
if (in_vreg[i].pre_off_sleep)
- usleep_range(in_vreg[i].pre_off_sleep * 1000,
- in_vreg[i].pre_off_sleep * 1000);
+ usleep_range((in_vreg[i].pre_off_sleep * 1000),
+ (in_vreg[i].pre_off_sleep * 1000) + 10);
regulator_set_load(in_vreg[i].vreg,
in_vreg[i].load[DSS_REG_MODE_DISABLE]);
regulator_disable(in_vreg[i].vreg);
if (in_vreg[i].post_off_sleep)
- usleep_range(in_vreg[i].post_off_sleep * 1000,
- in_vreg[i].post_off_sleep * 1000);
+ usleep_range((in_vreg[i].post_off_sleep * 1000),
+ (in_vreg[i].post_off_sleep * 1000) + 10);
}
return rc;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c
index e472e7f..a6d43a6 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.c
+++ b/drivers/video/fbdev/msm/mdss_mdp.c
@@ -1456,6 +1456,35 @@
}
/**
+ * mdss_mdp_retention_init() - initialize retention setting
+ * @mdata: pointer to the global mdss data structure.
+ */
+static int mdss_mdp_retention_init(struct mdss_data_type *mdata)
+{
+ struct clk *mdss_axi_clk = mdss_mdp_get_clk(MDSS_CLK_AXI);
+ int rc;
+
+ if (!mdss_axi_clk) {
+ pr_err("failed to get AXI clock\n");
+ return -EINVAL;
+ }
+
+ rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_MEM);
+ if (rc) {
+ pr_err("failed to set AXI no memory retention %d\n", rc);
+ return rc;
+ }
+
+ rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_PERIPH);
+ if (rc) {
+ pr_err("failed to set AXI no periphery retention %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+/**
* mdss_bus_bandwidth_ctrl() -- place bus bandwidth request
* @enable: value of enable or disable
*
@@ -2695,6 +2724,12 @@
goto probe_done;
}
+ rc = mdss_mdp_retention_init(mdata);
+ if (rc) {
+ pr_err("unable to initialize mdss mdp retention\n");
+ goto probe_done;
+ }
+
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT_MS);
if (mdata->idle_pc_enabled)
pm_runtime_use_autosuspend(&pdev->dev);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 344d6ef..9de02d9 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -571,11 +571,12 @@
u32 fps, u32 v_total)
{
u32 active_line_cycle, backfill_cycle, total_cycle;
- u32 ver_dwnscale;
+ u64 ver_dwnscale;
u32 active_line;
u32 backfill_line;
- ver_dwnscale = (src_h << PHASE_STEP_SHIFT) / dst.h;
+ ver_dwnscale = src_h << PHASE_STEP_SHIFT;
+ do_div(ver_dwnscale, dst.h);
if (ver_dwnscale > (MDSS_MDP_QSEED3_VER_DOWNSCALE_LIM
<< PHASE_STEP_SHIFT)) {
@@ -599,7 +600,7 @@
total_cycle = active_line_cycle + backfill_cycle;
pr_debug("line: active=%d backfill=%d vds=%d\n",
- active_line, backfill_line, ver_dwnscale);
+ active_line, backfill_line, (u32)ver_dwnscale);
pr_debug("cycle: total=%d active=%d backfill=%d\n",
total_cycle, active_line_cycle, backfill_cycle);
@@ -4340,11 +4341,13 @@
return;
pr_debug("hw ctl reset is set for ctl:%d\n", ctl->num);
- status = mdss_mdp_poll_ctl_reset_status(ctl, 5);
+ /* poll for at least ~1 frame */
+ status = mdss_mdp_poll_ctl_reset_status(ctl, 320);
if (status) {
- pr_err("hw recovery is not complete for ctl:%d\n", ctl->num);
+ pr_err("hw recovery is not complete for ctl:%d status:0x%x\n",
+ ctl->num, status);
MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt", "dbg_bus",
- "vbif_dbg_bus", "panic");
+ "vbif_dbg_bus", "dsi_dbg_bus", "panic");
}
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 764b830..b49e954 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -1975,12 +1975,14 @@
MDSS_XLOG(0xbad);
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
"dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt",
- "dbg_bus", "vbif_dbg_bus", "panic");
+ "dbg_bus", "vbif_dbg_bus",
+ "dsi_dbg_bus", "panic");
} else if (ctx->pp_timeout_report_cnt == MAX_RECOVERY_TRIALS) {
MDSS_XLOG(0xbad2);
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
"dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt",
- "dbg_bus", "vbif_dbg_bus", "panic");
+ "dbg_bus", "vbif_dbg_bus",
+ "dsi_dbg_bus", "panic");
mdss_fb_report_panel_dead(ctl->mfd);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
index 7b69aa3..f18987c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c
@@ -1252,7 +1252,7 @@
pr_err("error polling for vsync\n");
MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy",
"dsi1_ctrl", "dsi1_phy", "vbif", "dbg_bus",
- "vbif_dbg_bus", "panic");
+ "vbif_dbg_bus", "dsi_dbg_bus", "panic");
}
} else {
rc = 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 80708aa..672b634 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -6603,6 +6603,7 @@
mdp5_interface->configure_panel = mdss_mdp_update_panel_info;
mdp5_interface->input_event_handler = mdss_mdp_input_event_handler;
mdp5_interface->signal_retire_fence = mdss_mdp_signal_retire_fence;
+ mdp5_interface->is_twm_en = NULL;
if (mfd->panel_info->type == WRITEBACK_PANEL) {
mdp5_interface->atomic_validate =
diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h
index f8a6baf..c100e9c 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_trace.h
+++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h
@@ -376,7 +376,7 @@
__entry->kickoff_cnt)
);
-TRACE_EVENT(mdss_mark_write,
+TRACE_EVENT(tracing_mark_write,
TP_PROTO(int pid, const char *name, bool trace_begin),
TP_ARGS(pid, name, trace_begin),
TP_STRUCT__entry(
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index a3f9349..c9e7e61 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -821,6 +821,7 @@
struct mdss_panel_data *next;
int panel_te_gpio;
+ int panel_en_gpio;
struct completion te_done;
};
diff --git a/drivers/video/fbdev/msm/mdss_qpic.c b/drivers/video/fbdev/msm/mdss_qpic.c
index aa8d783..2f170cc 100644
--- a/drivers/video/fbdev/msm/mdss_qpic.c
+++ b/drivers/video/fbdev/msm/mdss_qpic.c
@@ -231,6 +231,7 @@
qpic_interface->dma_fnc = mdss_qpic_pan_display;
qpic_interface->ioctl_handler = NULL;
qpic_interface->kickoff_fnc = NULL;
+ qpic_interface->is_twm_en = NULL;
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c
index 2d8b5d5..972c8de 100644
--- a/drivers/video/fbdev/msm/mdss_smmu.c
+++ b/drivers/video/fbdev/msm/mdss_smmu.c
@@ -693,13 +693,13 @@
}
static struct mdss_smmu_domain mdss_mdp_unsec = {
- "mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_1M, (SZ_4G - SZ_1M)};
+ "mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)};
static struct mdss_smmu_domain mdss_rot_unsec = {
- NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_1M, (SZ_4G - SZ_1M)};
+ NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)};
static struct mdss_smmu_domain mdss_mdp_sec = {
- "mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_1M, (SZ_4G - SZ_1M)};
+ "mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_128K, (SZ_4G - SZ_128M)};
static struct mdss_smmu_domain mdss_rot_sec = {
- NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_1M, (SZ_4G - SZ_1M)};
+ NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_128K, (SZ_4G - SZ_128M)};
static const struct of_device_id mdss_smmu_dt_match[] = {
{ .compatible = "qcom,smmu_mdp_unsec", .data = &mdss_mdp_unsec},
diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c
index a042329..026df9a 100644
--- a/drivers/video/fbdev/vfb.c
+++ b/drivers/video/fbdev/vfb.c
@@ -241,8 +241,23 @@
*/
static int vfb_set_par(struct fb_info *info)
{
+ switch (info->var.bits_per_pixel) {
+ case 1:
+ info->fix.visual = FB_VISUAL_MONO01;
+ break;
+ case 8:
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ break;
+ case 16:
+ case 24:
+ case 32:
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ break;
+ }
+
info->fix.line_length = get_line_length(info->var.xres_virtual,
info->var.bits_per_pixel);
+
return 0;
}
@@ -454,6 +469,8 @@
goto err2;
platform_set_drvdata(dev, info);
+ vfb_set_par(info);
+
fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n",
videomemorysize >> 10);
return 0;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3eb58cb..8f8909a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -799,11 +799,12 @@
the timeout module parameter.
config F71808E_WDT
- tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
+ tristate "Fintek F718xx, F818xx Super I/O Watchdog"
depends on X86
help
- This is the driver for the hardware watchdog on the Fintek
- F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
+ This is the driver for the hardware watchdog on the Fintek F71808E,
+ F71862FG, F71868, F71869, F71882FG, F71889FG, F81865 and F81866
+ Super I/O controllers.
You can compile this driver directly into the kernel, or use
it as a module. The module will be called f71808e_wdt.
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index 1b7e916..e682bf0 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -57,6 +57,7 @@
#define SIO_F71808_ID 0x0901 /* Chipset ID */
#define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */
+#define SIO_F71868_ID 0x1106 /* Chipset ID */
#define SIO_F71869_ID 0x0814 /* Chipset ID */
#define SIO_F71869A_ID 0x1007 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */
@@ -101,7 +102,7 @@
static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
module_param(pulse_width, uint, 0);
MODULE_PARM_DESC(pulse_width,
- "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms"
+ "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms"
" (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
@@ -119,13 +120,14 @@
MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
" given initial timeout. Zero (default) disables this feature.");
-enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg, f81865,
- f81866};
+enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg,
+ f81865, f81866};
static const char *f71808e_names[] = {
"f71808fg",
"f71858fg",
"f71862fg",
+ "f71868",
"f71869",
"f71882fg",
"f71889fg",
@@ -252,16 +254,23 @@
static int watchdog_set_pulse_width(unsigned int pw)
{
int err = 0;
+ unsigned int t1 = 25, t2 = 125, t3 = 5000;
+
+ if (watchdog.type == f71868) {
+ t1 = 30;
+ t2 = 150;
+ t3 = 6000;
+ }
mutex_lock(&watchdog.lock);
- if (pw <= 1) {
+ if (pw <= 1) {
watchdog.pulse_val = 0;
- } else if (pw <= 25) {
+ } else if (pw <= t1) {
watchdog.pulse_val = 1;
- } else if (pw <= 125) {
+ } else if (pw <= t2) {
watchdog.pulse_val = 2;
- } else if (pw <= 5000) {
+ } else if (pw <= t3) {
watchdog.pulse_val = 3;
} else {
pr_err("pulse width out of range\n");
@@ -354,6 +363,7 @@
goto exit_superio;
break;
+ case f71868:
case f71869:
/* GPIO14 --> WDTRST# */
superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4);
@@ -486,7 +496,7 @@
is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0))
&& (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF)
- & F71808FG_FLAG_WD_EN);
+ & BIT(F71808FG_FLAG_WD_EN));
superio_exit(watchdog.sioaddr);
@@ -792,6 +802,9 @@
watchdog.type = f71862fg;
err = f71862fg_pin_configure(0); /* validate module parameter */
break;
+ case SIO_F71868_ID:
+ watchdog.type = f71868;
+ break;
case SIO_F71869_ID:
case SIO_F71869A_ID:
watchdog.type = f71869;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index a11f731..6182d69 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -746,7 +746,7 @@
autofs4_del_active(dentry);
- inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555);
+ inode = autofs4_get_inode(dir->i_sb, S_IFDIR | mode);
if (!inode)
return -ENOMEM;
d_add(dentry, inode);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 8ed05d9..03ac3ab 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -2453,7 +2453,7 @@
if (!uptodate) {
ClearPageUptodate(page);
SetPageError(page);
- ret = ret < 0 ? ret : -EIO;
+ ret = err < 0 ? err : -EIO;
mapping_set_error(page->mapping, ret);
}
}
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 5539f0b..5240173 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -3664,7 +3664,7 @@
src_offset = btrfs_item_ptr_offset(src, start_slot + i);
- if ((i == (nr - 1)))
+ if (i == nr - 1)
last_key = ins_keys[i];
if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
diff --git a/fs/buffer.c b/fs/buffer.c
index 5d8f496..3a8064d 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1455,12 +1455,48 @@
return 0;
}
+static void __evict_bh_lru(void *arg)
+{
+ struct bh_lru *b = &get_cpu_var(bh_lrus);
+ struct buffer_head *bh = arg;
+ int i;
+
+ for (i = 0; i < BH_LRU_SIZE; i++) {
+ if (b->bhs[i] == bh) {
+ brelse(b->bhs[i]);
+ b->bhs[i] = NULL;
+ goto out;
+ }
+ }
+out:
+ put_cpu_var(bh_lrus);
+}
+
+static bool bh_exists_in_lru(int cpu, void *arg)
+{
+ struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu);
+ struct buffer_head *bh = arg;
+ int i;
+
+ for (i = 0; i < BH_LRU_SIZE; i++) {
+ if (b->bhs[i] == bh)
+ return 1;
+ }
+
+ return 0;
+
+}
void invalidate_bh_lrus(void)
{
on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(invalidate_bh_lrus);
+static void evict_bh_lrus(struct buffer_head *bh)
+{
+ on_each_cpu_cond(bh_exists_in_lru, __evict_bh_lru, bh, 1, GFP_ATOMIC);
+}
+
void set_bh_page(struct buffer_head *bh,
struct page *page, unsigned long offset)
{
@@ -3250,8 +3286,15 @@
do {
if (buffer_write_io_error(bh) && page->mapping)
mapping_set_error(page->mapping, -EIO);
- if (buffer_busy(bh))
- goto failed;
+ if (buffer_busy(bh)) {
+ /*
+ * Check if the busy failure was due to an
+ * outstanding LRU reference
+ */
+ evict_bh_lrus(bh);
+ if (buffer_busy(bh))
+ goto failed;
+ }
bh = bh->b_this_page;
} while (bh != head);
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index ca3f630..e7ddb23 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -598,7 +598,8 @@
struct ceph_aio_request {
struct kiocb *iocb;
size_t total_len;
- int write;
+ bool write;
+ bool should_dirty;
int error;
struct list_head osd_reqs;
unsigned num_reqs;
@@ -708,7 +709,7 @@
}
}
- ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write);
+ ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty);
ceph_osdc_put_request(req);
if (rc < 0)
@@ -890,6 +891,7 @@
size_t count = iov_iter_count(iter);
loff_t pos = iocb->ki_pos;
bool write = iov_iter_rw(iter) == WRITE;
+ bool should_dirty = !write && iter_is_iovec(iter);
if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP)
return -EROFS;
@@ -954,6 +956,7 @@
if (aio_req) {
aio_req->iocb = iocb;
aio_req->write = write;
+ aio_req->should_dirty = should_dirty;
INIT_LIST_HEAD(&aio_req->osd_reqs);
if (write) {
aio_req->mtime = mtime;
@@ -1012,7 +1015,7 @@
len = ret;
}
- ceph_put_page_vector(pages, num_pages, !write);
+ ceph_put_page_vector(pages, num_pages, should_dirty);
ceph_osdc_put_request(req);
if (ret < 0)
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 7b496a4..4ed4736 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1412,6 +1412,7 @@
#define CIFS_FATTR_NEED_REVAL 0x4
#define CIFS_FATTR_INO_COLLISION 0x8
#define CIFS_FATTR_UNKNOWN_NLINK 0x10
+#define CIFS_FATTR_FAKE_ROOT_INO 0x20
struct cifs_fattr {
u32 cf_flags;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 02e403a..49eeed2 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -589,7 +589,7 @@
struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
int rc = 0;
- down_read(&cinode->lock_sem);
+ down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING);
if (cinode->can_cache_brlcks) {
/* can cache locks - no need to relock */
up_read(&cinode->lock_sem);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 7ab5be7..24c19eb 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -701,6 +701,18 @@
return rc;
}
+/* Simple function to return a 64 bit hash of string. Rarely called */
+static __u64 simple_hashstr(const char *str)
+{
+ const __u64 hash_mult = 1125899906842597L; /* a big enough prime */
+ __u64 hash = 0;
+
+ while (*str)
+ hash = (hash + (__u64) *str++) * hash_mult;
+
+ return hash;
+}
+
int
cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb, int xid,
@@ -810,6 +822,14 @@
tmprc);
fattr.cf_uniqueid = iunique(sb, ROOT_I);
cifs_autodisable_serverino(cifs_sb);
+ } else if ((fattr.cf_uniqueid == 0) &&
+ strlen(full_path) == 0) {
+ /* some servers ret bad root ino ie 0 */
+ cifs_dbg(FYI, "Invalid (0) inodenum\n");
+ fattr.cf_flags |=
+ CIFS_FATTR_FAKE_ROOT_INO;
+ fattr.cf_uniqueid =
+ simple_hashstr(tcon->treeName);
}
}
} else
@@ -826,6 +846,16 @@
&fattr.cf_uniqueid, data);
if (tmprc)
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+ else if ((fattr.cf_uniqueid == 0) &&
+ strlen(full_path) == 0) {
+ /*
+ * Reuse existing root inode num since
+ * inum zero for root causes ls of . and .. to
+ * not be returned
+ */
+ cifs_dbg(FYI, "Srv ret 0 inode num for root\n");
+ fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
+ }
} else
fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid;
}
@@ -887,6 +917,9 @@
}
cgii_exit:
+ if ((*inode) && ((*inode)->i_ino == 0))
+ cifs_dbg(FYI, "inode number of zero returned\n");
+
kfree(buf);
cifs_put_tlink(tlink);
return rc;
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 7c26286..44b7ccb 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1151,15 +1151,19 @@
goto tcon_exit;
}
- if (rsp->ShareType & SMB2_SHARE_TYPE_DISK)
+ switch (rsp->ShareType) {
+ case SMB2_SHARE_TYPE_DISK:
cifs_dbg(FYI, "connection to disk share\n");
- else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) {
+ break;
+ case SMB2_SHARE_TYPE_PIPE:
tcon->ipc = true;
cifs_dbg(FYI, "connection to pipe share\n");
- } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) {
- tcon->print = true;
+ break;
+ case SMB2_SHARE_TYPE_PRINT:
+ tcon->ipc = true;
cifs_dbg(FYI, "connection to printer\n");
- } else {
+ break;
+ default:
cifs_dbg(VFS, "unknown share type %d\n", rsp->ShareType);
rc = -EOPNOTSUPP;
goto tcon_error_exit;
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index f2d7402..93c8e4a 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -833,7 +833,7 @@
*/
#define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff)
-#define COMPATIBLE_IOCTL(cmd) XFORM(cmd),
+#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd),
/* ioctl should not be warned about even if it's not implemented.
Valid reasons to use this:
- It is implemented with ->compat_ioctl on some device, but programs
diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
index 2596c9a..d7b4c48 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -25,15 +25,8 @@
#include <linux/namei.h>
#include "fscrypt_private.h"
-/*
- * Call fscrypt_decrypt_page on every single page, reusing the encryption
- * context.
- */
-static void completion_pages(struct work_struct *work)
+static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
{
- struct fscrypt_ctx *ctx =
- container_of(work, struct fscrypt_ctx, r.work);
- struct bio *bio = ctx->r.bio;
struct bio_vec *bv;
int i;
@@ -45,22 +38,38 @@
if (ret) {
WARN_ON_ONCE(1);
SetPageError(page);
- } else {
+ } else if (done) {
SetPageUptodate(page);
}
- unlock_page(page);
+ if (done)
+ unlock_page(page);
}
+}
+
+void fscrypt_decrypt_bio(struct bio *bio)
+{
+ __fscrypt_decrypt_bio(bio, false);
+}
+EXPORT_SYMBOL(fscrypt_decrypt_bio);
+
+static void completion_pages(struct work_struct *work)
+{
+ struct fscrypt_ctx *ctx =
+ container_of(work, struct fscrypt_ctx, r.work);
+ struct bio *bio = ctx->r.bio;
+
+ __fscrypt_decrypt_bio(bio, true);
fscrypt_release_ctx(ctx);
bio_put(bio);
}
-void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio)
+void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio)
{
INIT_WORK(&ctx->r.work, completion_pages);
ctx->r.bio = bio;
- queue_work(fscrypt_read_workqueue, &ctx->r.work);
+ fscrypt_enqueue_decrypt_work(&ctx->r.work);
}
-EXPORT_SYMBOL(fscrypt_decrypt_bio_pages);
+EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio);
void fscrypt_pullback_bio_page(struct page **page, bool restore)
{
diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
index 732a786..0758d32 100644
--- a/fs/crypto/crypto.c
+++ b/fs/crypto/crypto.c
@@ -27,6 +27,7 @@
#include <linux/dcache.h>
#include <linux/namei.h>
#include <crypto/aes.h>
+#include <crypto/skcipher.h>
#include "fscrypt_private.h"
static unsigned int num_prealloc_crypto_pages = 32;
@@ -44,12 +45,18 @@
static LIST_HEAD(fscrypt_free_ctxs);
static DEFINE_SPINLOCK(fscrypt_ctx_lock);
-struct workqueue_struct *fscrypt_read_workqueue;
+static struct workqueue_struct *fscrypt_read_workqueue;
static DEFINE_MUTEX(fscrypt_init_mutex);
static struct kmem_cache *fscrypt_ctx_cachep;
struct kmem_cache *fscrypt_info_cachep;
+void fscrypt_enqueue_decrypt_work(struct work_struct *work)
+{
+ queue_work(fscrypt_read_workqueue, work);
+}
+EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work);
+
/**
* fscrypt_release_ctx() - Releases an encryption context
* @ctx: The encryption context to release.
diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c
index 6eb4343..b18fa32 100644
--- a/fs/crypto/fname.c
+++ b/fs/crypto/fname.c
@@ -12,42 +12,46 @@
#include <linux/scatterlist.h>
#include <linux/ratelimit.h>
+#include <crypto/skcipher.h>
#include "fscrypt_private.h"
+static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
+{
+ if (str->len == 1 && str->name[0] == '.')
+ return true;
+
+ if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
+ return true;
+
+ return false;
+}
+
/**
* fname_encrypt() - encrypt a filename
*
- * The caller must have allocated sufficient memory for the @oname string.
+ * The output buffer must be at least as large as the input buffer.
+ * Any extra space is filled with NUL padding before encryption.
*
* Return: 0 on success, -errno on failure
*/
-static int fname_encrypt(struct inode *inode,
- const struct qstr *iname, struct fscrypt_str *oname)
+int fname_encrypt(struct inode *inode, const struct qstr *iname,
+ u8 *out, unsigned int olen)
{
struct skcipher_request *req = NULL;
DECLARE_CRYPTO_WAIT(wait);
- struct fscrypt_info *ci = inode->i_crypt_info;
- struct crypto_skcipher *tfm = ci->ci_ctfm;
+ struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm;
int res = 0;
char iv[FS_CRYPTO_BLOCK_SIZE];
struct scatterlist sg;
- int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
- unsigned int lim;
- unsigned int cryptlen;
-
- lim = inode->i_sb->s_cop->max_namelen(inode);
- if (iname->len <= 0 || iname->len > lim)
- return -EIO;
/*
* Copy the filename to the output buffer for encrypting in-place and
* pad it with the needed number of NUL bytes.
*/
- cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
- cryptlen = round_up(cryptlen, padding);
- cryptlen = min(cryptlen, lim);
- memcpy(oname->name, iname->name, iname->len);
- memset(oname->name + iname->len, 0, cryptlen - iname->len);
+ if (WARN_ON(olen < iname->len))
+ return -ENOBUFS;
+ memcpy(out, iname->name, iname->len);
+ memset(out + iname->len, 0, olen - iname->len);
/* Initialize the IV */
memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
@@ -62,8 +66,8 @@
skcipher_request_set_callback(req,
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &wait);
- sg_init_one(&sg, oname->name, cryptlen);
- skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
+ sg_init_one(&sg, out, olen);
+ skcipher_request_set_crypt(req, &sg, &sg, olen, iv);
/* Do the encryption */
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
@@ -74,7 +78,6 @@
return res;
}
- oname->len = cryptlen;
return 0;
}
@@ -187,50 +190,52 @@
return cp - dst;
}
-u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen)
+bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len,
+ u32 max_len, u32 *encrypted_len_ret)
{
- int padding = 32;
- struct fscrypt_info *ci = inode->i_crypt_info;
+ int padding = 4 << (inode->i_crypt_info->ci_flags &
+ FS_POLICY_FLAGS_PAD_MASK);
+ u32 encrypted_len;
- if (ci)
- padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
- ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE);
- return round_up(ilen, padding);
+ if (orig_len > max_len)
+ return false;
+ encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE);
+ encrypted_len = round_up(encrypted_len, padding);
+ *encrypted_len_ret = min(encrypted_len, max_len);
+ return true;
}
-EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
/**
- * fscrypt_fname_crypto_alloc_obuff() -
+ * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames
*
- * Allocates an output buffer that is sufficient for the crypto operation
- * specified by the context and the direction.
+ * Allocate a buffer that is large enough to hold any decrypted or encoded
+ * filename (null-terminated), for the given maximum encrypted filename length.
+ *
+ * Return: 0 on success, -errno on failure
*/
int fscrypt_fname_alloc_buffer(const struct inode *inode,
- u32 ilen, struct fscrypt_str *crypto_str)
+ u32 max_encrypted_len,
+ struct fscrypt_str *crypto_str)
{
- u32 olen = fscrypt_fname_encrypted_size(inode, ilen);
const u32 max_encoded_len =
max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
+ u32 max_presented_len;
- crypto_str->len = olen;
- olen = max(olen, max_encoded_len);
+ max_presented_len = max(max_encoded_len, max_encrypted_len);
- /*
- * Allocated buffer can hold one more character to null-terminate the
- * string
- */
- crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
- if (!(crypto_str->name))
+ crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS);
+ if (!crypto_str->name)
return -ENOMEM;
+ crypto_str->len = max_presented_len;
return 0;
}
EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
/**
- * fscrypt_fname_crypto_free_buffer() -
+ * fscrypt_fname_free_buffer - free the buffer for presented filenames
*
- * Frees the buffer allocated for crypto operation.
+ * Free the buffer allocated by fscrypt_fname_alloc_buffer().
*/
void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
{
@@ -297,35 +302,6 @@
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
/**
- * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
- * space
- *
- * The caller must have allocated sufficient memory for the @oname string.
- *
- * Return: 0 on success, -errno on failure
- */
-int fscrypt_fname_usr_to_disk(struct inode *inode,
- const struct qstr *iname,
- struct fscrypt_str *oname)
-{
- if (fscrypt_is_dot_dotdot(iname)) {
- oname->name[0] = '.';
- oname->name[iname->len - 1] = '.';
- oname->len = iname->len;
- return 0;
- }
- if (inode->i_crypt_info)
- return fname_encrypt(inode, iname, oname);
- /*
- * Without a proper key, a user is not allowed to modify the filenames
- * in a directory. Consequently, a user space name cannot be mapped to
- * a disk-space name
- */
- return -ENOKEY;
-}
-EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
-
-/**
* fscrypt_setup_filename() - prepare to search a possibly encrypted directory
* @dir: the directory that will be searched
* @iname: the user-provided filename being searched for
@@ -368,11 +344,17 @@
return ret;
if (dir->i_crypt_info) {
- ret = fscrypt_fname_alloc_buffer(dir, iname->len,
- &fname->crypto_buf);
- if (ret)
- return ret;
- ret = fname_encrypt(dir, iname, &fname->crypto_buf);
+ if (!fscrypt_fname_encrypted_size(dir, iname->len,
+ dir->i_sb->s_cop->max_namelen(dir),
+ &fname->crypto_buf.len))
+ return -ENAMETOOLONG;
+ fname->crypto_buf.name = kmalloc(fname->crypto_buf.len,
+ GFP_NOFS);
+ if (!fname->crypto_buf.name)
+ return -ENOMEM;
+
+ ret = fname_encrypt(dir, iname, fname->crypto_buf.name,
+ fname->crypto_buf.len);
if (ret)
goto errout;
fname->disk_name.name = fname->crypto_buf.name;
@@ -424,7 +406,7 @@
return 0;
errout:
- fscrypt_fname_free_buffer(&fname->crypto_buf);
+ kfree(fname->crypto_buf.name);
return ret;
}
EXPORT_SYMBOL(fscrypt_setup_filename);
diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h
index 4688a64..d36a648 100644
--- a/fs/crypto/fscrypt_private.h
+++ b/fs/crypto/fscrypt_private.h
@@ -49,6 +49,15 @@
#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1
+/**
+ * For encrypted symlinks, the ciphertext length is stored at the beginning
+ * of the string in little-endian format.
+ */
+struct fscrypt_symlink_data {
+ __le16 len;
+ char encrypted_path[1];
+} __packed;
+
/*
* A pointer to this structure is stored in the file system's in-core
* representation of an inode.
@@ -70,9 +79,23 @@
#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001
#define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002
+static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
+ u32 filenames_mode)
+{
+ if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
+ filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
+ return true;
+
+ if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
+ filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
+ return true;
+
+ return false;
+}
+
/* crypto.c */
+extern struct kmem_cache *fscrypt_info_cachep;
extern int fscrypt_initialize(unsigned int cop_flags);
-extern struct workqueue_struct *fscrypt_read_workqueue;
extern int fscrypt_do_page_crypto(const struct inode *inode,
fscrypt_direction_t rw, u64 lblk_num,
struct page *src_page,
@@ -82,6 +105,13 @@
extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx,
gfp_t gfp_flags);
+/* fname.c */
+extern int fname_encrypt(struct inode *inode, const struct qstr *iname,
+ u8 *out, unsigned int olen);
+extern bool fscrypt_fname_encrypted_size(const struct inode *inode,
+ u32 orig_len, u32 max_len,
+ u32 *encrypted_len_ret);
+
/* keyinfo.c */
extern void __exit fscrypt_essiv_cleanup(void);
diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c
index 9f5fb2e..bec0649 100644
--- a/fs/crypto/hooks.c
+++ b/fs/crypto/hooks.c
@@ -110,3 +110,161 @@
return 0;
}
EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup);
+
+int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
+ unsigned int max_len,
+ struct fscrypt_str *disk_link)
+{
+ int err;
+
+ /*
+ * To calculate the size of the encrypted symlink target we need to know
+ * the amount of NUL padding, which is determined by the flags set in
+ * the encryption policy which will be inherited from the directory.
+ * The easiest way to get access to this is to just load the directory's
+ * fscrypt_info, since we'll need it to create the dir_entry anyway.
+ *
+ * Note: in test_dummy_encryption mode, @dir may be unencrypted.
+ */
+ err = fscrypt_get_encryption_info(dir);
+ if (err)
+ return err;
+ if (!fscrypt_has_encryption_key(dir))
+ return -ENOKEY;
+
+ /*
+ * Calculate the size of the encrypted symlink and verify it won't
+ * exceed max_len. Note that for historical reasons, encrypted symlink
+ * targets are prefixed with the ciphertext length, despite this
+ * actually being redundant with i_size. This decreases by 2 bytes the
+ * longest symlink target we can accept.
+ *
+ * We could recover 1 byte by not counting a null terminator, but
+ * counting it (even though it is meaningless for ciphertext) is simpler
+ * for now since filesystems will assume it is there and subtract it.
+ */
+ if (!fscrypt_fname_encrypted_size(dir, len,
+ max_len - sizeof(struct fscrypt_symlink_data),
+ &disk_link->len))
+ return -ENAMETOOLONG;
+ disk_link->len += sizeof(struct fscrypt_symlink_data);
+
+ disk_link->name = NULL;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink);
+
+int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
+ unsigned int len, struct fscrypt_str *disk_link)
+{
+ int err;
+ struct qstr iname = QSTR_INIT(target, len);
+ struct fscrypt_symlink_data *sd;
+ unsigned int ciphertext_len;
+
+ err = fscrypt_require_key(inode);
+ if (err)
+ return err;
+
+ if (disk_link->name) {
+ /* filesystem-provided buffer */
+ sd = (struct fscrypt_symlink_data *)disk_link->name;
+ } else {
+ sd = kmalloc(disk_link->len, GFP_NOFS);
+ if (!sd)
+ return -ENOMEM;
+ }
+ ciphertext_len = disk_link->len - sizeof(*sd);
+ sd->len = cpu_to_le16(ciphertext_len);
+
+ err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len);
+ if (err) {
+ if (!disk_link->name)
+ kfree(sd);
+ return err;
+ }
+ /*
+ * Null-terminating the ciphertext doesn't make sense, but we still
+ * count the null terminator in the length, so we might as well
+ * initialize it just in case the filesystem writes it out.
+ */
+ sd->encrypted_path[ciphertext_len] = '\0';
+
+ if (!disk_link->name)
+ disk_link->name = (unsigned char *)sd;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink);
+
+/**
+ * fscrypt_get_symlink - get the target of an encrypted symlink
+ * @inode: the symlink inode
+ * @caddr: the on-disk contents of the symlink
+ * @max_size: size of @caddr buffer
+ * @done: if successful, will be set up to free the returned target
+ *
+ * If the symlink's encryption key is available, we decrypt its target.
+ * Otherwise, we encode its target for presentation.
+ *
+ * This may sleep, so the filesystem must have dropped out of RCU mode already.
+ *
+ * Return: the presentable symlink target or an ERR_PTR()
+ */
+const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
+ unsigned int max_size,
+ struct delayed_call *done)
+{
+ const struct fscrypt_symlink_data *sd;
+ struct fscrypt_str cstr, pstr;
+ int err;
+
+ /* This is for encrypted symlinks only */
+ if (WARN_ON(!IS_ENCRYPTED(inode)))
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * Try to set up the symlink's encryption key, but we can continue
+ * regardless of whether the key is available or not.
+ */
+ err = fscrypt_get_encryption_info(inode);
+ if (err)
+ return ERR_PTR(err);
+
+ /*
+ * For historical reasons, encrypted symlink targets are prefixed with
+ * the ciphertext length, even though this is redundant with i_size.
+ */
+
+ if (max_size < sizeof(*sd))
+ return ERR_PTR(-EUCLEAN);
+ sd = caddr;
+ cstr.name = (unsigned char *)sd->encrypted_path;
+ cstr.len = le16_to_cpu(sd->len);
+
+ if (cstr.len == 0)
+ return ERR_PTR(-EUCLEAN);
+
+ if (cstr.len + sizeof(*sd) - 1 > max_size)
+ return ERR_PTR(-EUCLEAN);
+
+ err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
+ if (err)
+ return ERR_PTR(err);
+
+ err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
+ if (err)
+ goto err_kfree;
+
+ err = -EUCLEAN;
+ if (pstr.name[0] == '\0')
+ goto err_kfree;
+
+ pstr.name[pstr.len] = '\0';
+ set_delayed_call(done, kfree_link, pstr.name);
+ return pstr.name;
+
+err_kfree:
+ kfree(pstr.name);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(fscrypt_get_symlink);
diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c
index c891d2e..aae68c0 100644
--- a/fs/crypto/keyinfo.c
+++ b/fs/crypto/keyinfo.c
@@ -13,6 +13,7 @@
#include <linux/ratelimit.h>
#include <crypto/aes.h>
#include <crypto/sha.h>
+#include <crypto/skcipher.h>
#include "fscrypt_private.h"
static struct crypto_shash *essiv_hash_tfm;
@@ -353,19 +354,9 @@
}
EXPORT_SYMBOL(fscrypt_get_encryption_info);
-void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci)
+void fscrypt_put_encryption_info(struct inode *inode)
{
- struct fscrypt_info *prev;
-
- if (ci == NULL)
- ci = ACCESS_ONCE(inode->i_crypt_info);
- if (ci == NULL)
- return;
-
- prev = cmpxchg(&inode->i_crypt_info, ci, NULL);
- if (prev != ci)
- return;
-
- put_crypt_info(ci);
+ put_crypt_info(inode->i_crypt_info);
+ inode->i_crypt_info = NULL;
}
EXPORT_SYMBOL(fscrypt_put_encryption_info);
diff --git a/fs/dcache.c b/fs/dcache.c
index 210a135..885f74e 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -461,9 +461,11 @@
* d_drop() is used mainly for stuff that wants to invalidate a dentry for some
* reason (NFS timeouts or autofs deletes).
*
- * __d_drop requires dentry->d_lock.
+ * __d_drop requires dentry->d_lock
+ * ___d_drop doesn't mark dentry as "unhashed"
+ * (dentry->d_hash.pprev will be LIST_POISON2, not NULL).
*/
-void __d_drop(struct dentry *dentry)
+static void ___d_drop(struct dentry *dentry)
{
if (!d_unhashed(dentry)) {
struct hlist_bl_head *b;
@@ -479,12 +481,17 @@
hlist_bl_lock(b);
__hlist_bl_del(&dentry->d_hash);
- dentry->d_hash.pprev = NULL;
hlist_bl_unlock(b);
/* After this call, in-progress rcu-walk path lookup will fail. */
write_seqcount_invalidate(&dentry->d_seq);
}
}
+
+void __d_drop(struct dentry *dentry)
+{
+ ___d_drop(dentry);
+ dentry->d_hash.pprev = NULL;
+}
EXPORT_SYMBOL(__d_drop);
void d_drop(struct dentry *dentry)
@@ -2378,7 +2385,7 @@
static void __d_rehash(struct dentry *entry)
{
struct hlist_bl_head *b = d_hash(entry->d_name.hash);
- BUG_ON(!d_unhashed(entry));
+
hlist_bl_lock(b);
hlist_bl_add_head_rcu(&entry->d_hash, b);
hlist_bl_unlock(b);
@@ -2815,9 +2822,9 @@
write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED);
/* unhash both */
- /* __d_drop does write_seqcount_barrier, but they're OK to nest. */
- __d_drop(dentry);
- __d_drop(target);
+ /* ___d_drop does write_seqcount_barrier, but they're OK to nest. */
+ ___d_drop(dentry);
+ ___d_drop(target);
/* Switch the names.. */
if (exchange)
@@ -2829,6 +2836,8 @@
__d_rehash(dentry);
if (exchange)
__d_rehash(target);
+ else
+ target->d_hash.pprev = NULL;
/* ... and switch them in the tree */
if (IS_ROOT(dentry)) {
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index e04ec86..176b4b2 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -242,8 +242,6 @@
*/
ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group),
sb->s_blocksize * 8, bh->b_data);
- ext4_block_bitmap_csum_set(sb, block_group, gdp, bh);
- ext4_group_desc_csum_set(sb, block_group, gdp);
return 0;
}
@@ -447,6 +445,7 @@
err = ext4_init_block_bitmap(sb, bh, block_group, desc);
set_bitmap_uptodate(bh);
set_buffer_uptodate(bh);
+ set_buffer_verified(bh);
ext4_unlock_group(sb, block_group);
unlock_buffer(bh);
if (err) {
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 510e664..08fca4a 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -429,7 +429,7 @@
int i, num;
unsigned long nr_pages;
- num = min_t(pgoff_t, end - index, PAGEVEC_SIZE);
+ num = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1;
nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index,
(pgoff_t)num);
if (nr_pages == 0)
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 2cec605..ef76b83 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -63,44 +63,6 @@
memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
}
-/* Initializes an uninitialized inode bitmap */
-static int ext4_init_inode_bitmap(struct super_block *sb,
- struct buffer_head *bh,
- ext4_group_t block_group,
- struct ext4_group_desc *gdp)
-{
- struct ext4_group_info *grp;
- struct ext4_sb_info *sbi = EXT4_SB(sb);
- J_ASSERT_BH(bh, buffer_locked(bh));
-
- /* If checksum is bad mark all blocks and inodes use to prevent
- * allocation, essentially implementing a per-group read-only flag. */
- if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
- grp = ext4_get_group_info(sb, block_group);
- if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
- percpu_counter_sub(&sbi->s_freeclusters_counter,
- grp->bb_free);
- set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
- if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
- int count;
- count = ext4_free_inodes_count(sb, gdp);
- percpu_counter_sub(&sbi->s_freeinodes_counter,
- count);
- }
- set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
- return -EFSBADCRC;
- }
-
- 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);
- ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh,
- EXT4_INODES_PER_GROUP(sb) / 8);
- ext4_group_desc_csum_set(sb, block_group, gdp);
-
- return 0;
-}
-
void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate)
{
if (uptodate) {
@@ -184,17 +146,14 @@
ext4_lock_group(sb, block_group);
if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
- err = ext4_init_inode_bitmap(sb, bh, block_group, desc);
+ 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);
set_bitmap_uptodate(bh);
set_buffer_uptodate(bh);
set_buffer_verified(bh);
ext4_unlock_group(sb, block_group);
unlock_buffer(bh);
- if (err) {
- ext4_error(sb, "Failed to init inode bitmap for group "
- "%u: %d", block_group, err);
- goto out;
- }
return bh;
}
ext4_unlock_group(sb, block_group);
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 21c0670..2bf83d0 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3421,7 +3421,6 @@
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
- struct ext4_inode_info *ei = EXT4_I(inode);
ssize_t ret;
loff_t offset = iocb->ki_pos;
size_t count = iov_iter_count(iter);
@@ -3445,7 +3444,7 @@
goto out;
}
orphan = 1;
- ei->i_disksize = inode->i_size;
+ ext4_update_i_disksize(inode, inode->i_size);
ext4_journal_stop(handle);
}
@@ -3573,7 +3572,7 @@
if (ret > 0) {
loff_t end = offset + ret;
if (end > inode->i_size) {
- ei->i_disksize = end;
+ ext4_update_i_disksize(inode, end);
i_size_write(inode, end);
/*
* We're going to return a positive `ret'
@@ -4561,6 +4560,12 @@
goto bad_inode;
raw_inode = ext4_raw_inode(&iloc);
+ if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) {
+ EXT4_ERROR_INODE(inode, "root inode unallocated");
+ ret = -EFSCORRUPTED;
+ goto bad_inode;
+ }
+
if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index e5e99a7..4beca06 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -3878,7 +3878,8 @@
err = ext4_mb_load_buddy(sb, group, &e4b);
if (err) {
- ext4_error(sb, "Error loading buddy information for %u", group);
+ ext4_warning(sb, "Error %d loading buddy information for %u",
+ err, group);
put_bh(bitmap_bh);
return 0;
}
@@ -4035,10 +4036,11 @@
BUG_ON(pa->pa_type != MB_INODE_PA);
group = ext4_get_group_number(sb, pa->pa_pstart);
- err = ext4_mb_load_buddy(sb, group, &e4b);
+ err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
+ GFP_NOFS|__GFP_NOFAIL);
if (err) {
- ext4_error(sb, "Error loading buddy information for %u",
- group);
+ ext4_error(sb, "Error %d loading buddy information for %u",
+ err, group);
continue;
}
@@ -4294,11 +4296,14 @@
spin_unlock(&lg->lg_prealloc_lock);
list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) {
+ int err;
group = ext4_get_group_number(sb, pa->pa_pstart);
- if (ext4_mb_load_buddy(sb, group, &e4b)) {
- ext4_error(sb, "Error loading buddy information for %u",
- group);
+ err = ext4_mb_load_buddy_gfp(sb, group, &e4b,
+ GFP_NOFS|__GFP_NOFAIL);
+ if (err) {
+ ext4_error(sb, "Error %d loading buddy information for %u",
+ err, group);
continue;
}
ext4_lock_group(sb, group);
@@ -5122,8 +5127,8 @@
ret = ext4_mb_load_buddy(sb, group, &e4b);
if (ret) {
- ext4_error(sb, "Error in loading buddy "
- "information for %u", group);
+ ext4_warning(sb, "Error %d loading buddy information for %u",
+ ret, group);
return ret;
}
bitmap = e4b.bd_bitmap;
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 8338cd4..e3183e8 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3027,36 +3027,16 @@
struct inode *inode;
int err, len = strlen(symname);
int credits;
- bool encryption_required;
struct fscrypt_str disk_link;
- struct fscrypt_symlink_data *sd = NULL;
- disk_link.len = len + 1;
- disk_link.name = (char *) symname;
-
- encryption_required = (ext4_encrypted_inode(dir) ||
- DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb)));
- if (encryption_required) {
- err = fscrypt_get_encryption_info(dir);
- if (err)
- return err;
- if (!fscrypt_has_encryption_key(dir))
- return -ENOKEY;
- disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
- sizeof(struct fscrypt_symlink_data));
- sd = kzalloc(disk_link.len, GFP_KERNEL);
- if (!sd)
- return -ENOMEM;
- }
-
- if (disk_link.len > dir->i_sb->s_blocksize) {
- err = -ENAMETOOLONG;
- goto err_free_sd;
- }
+ err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
+ &disk_link);
+ if (err)
+ return err;
err = dquot_initialize(dir);
if (err)
- goto err_free_sd;
+ return err;
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
/*
@@ -3085,27 +3065,18 @@
if (IS_ERR(inode)) {
if (handle)
ext4_journal_stop(handle);
- err = PTR_ERR(inode);
- goto err_free_sd;
+ return PTR_ERR(inode);
}
- if (encryption_required) {
- struct qstr istr;
- struct fscrypt_str ostr =
- FSTR_INIT(sd->encrypted_path, disk_link.len);
-
- istr.name = (const unsigned char *) symname;
- istr.len = len;
- err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
+ if (IS_ENCRYPTED(inode)) {
+ err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
if (err)
goto err_drop_inode;
- sd->len = cpu_to_le16(ostr.len);
- disk_link.name = (char *) sd;
inode->i_op = &ext4_encrypted_symlink_inode_operations;
}
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
- if (!encryption_required)
+ if (!IS_ENCRYPTED(inode))
inode->i_op = &ext4_symlink_inode_operations;
inode_nohighmem(inode);
ext4_set_aops(inode);
@@ -3147,7 +3118,7 @@
} else {
/* clear the extent format for fast symlink */
ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
- if (!encryption_required) {
+ if (!IS_ENCRYPTED(inode)) {
inode->i_op = &ext4_fast_symlink_inode_operations;
inode->i_link = (char *)&EXT4_I(inode)->i_data;
}
@@ -3162,16 +3133,17 @@
if (handle)
ext4_journal_stop(handle);
- kfree(sd);
- return err;
+ goto out_free_encrypted_link;
+
err_drop_inode:
if (handle)
ext4_journal_stop(handle);
clear_nlink(inode);
unlock_new_inode(inode);
iput(inode);
-err_free_sd:
- kfree(sd);
+out_free_encrypted_link:
+ if (disk_link.name != (unsigned char *)symname)
+ kfree(disk_link.name);
return err;
}
diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c
index 2531cc1..c39a12d 100644
--- a/fs/ext4/readpage.c
+++ b/fs/ext4/readpage.c
@@ -91,7 +91,7 @@
if (bio->bi_error) {
fscrypt_release_ctx(bio->bi_private);
} else {
- fscrypt_decrypt_bio_pages(bio->bi_private, bio);
+ fscrypt_enqueue_decrypt_bio(bio->bi_private, bio);
return;
}
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 43ce5fc..e95b6e1 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1028,9 +1028,7 @@
jbd2_free_inode(EXT4_I(inode)->jinode);
EXT4_I(inode)->jinode = NULL;
}
-#ifdef CONFIG_EXT4_FS_ENCRYPTION
- fscrypt_put_encryption_info(inode, NULL);
-#endif
+ fscrypt_put_encryption_info(inode);
}
static struct inode *ext4_nfs_get_inode(struct super_block *sb,
@@ -2272,6 +2270,8 @@
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
"Block bitmap for group %u overlaps "
"superblock", 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: "
@@ -2284,6 +2284,8 @@
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
"Inode bitmap for group %u overlaps "
"superblock", 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: "
@@ -2296,6 +2298,8 @@
ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
"Inode table for group %u overlaps "
"superblock", i);
+ if (!(sb->s_flags & MS_RDONLY))
+ return 0;
}
if (inode_table < first_block ||
inode_table + sbi->s_itb_per_group - 1 > last_block) {
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index 557b3b0..d4ce3af 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -27,59 +27,28 @@
struct delayed_call *done)
{
struct page *cpage = NULL;
- char *caddr, *paddr = NULL;
- struct fscrypt_str cstr, pstr;
- struct fscrypt_symlink_data *sd;
- int res;
- u32 max_size = inode->i_sb->s_blocksize;
+ const void *caddr;
+ unsigned int max_size;
+ const char *paddr;
if (!dentry)
return ERR_PTR(-ECHILD);
- res = fscrypt_get_encryption_info(inode);
- if (res)
- return ERR_PTR(res);
-
if (ext4_inode_is_fast_symlink(inode)) {
- caddr = (char *) EXT4_I(inode)->i_data;
+ caddr = EXT4_I(inode)->i_data;
max_size = sizeof(EXT4_I(inode)->i_data);
} else {
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
if (IS_ERR(cpage))
return ERR_CAST(cpage);
caddr = page_address(cpage);
+ max_size = inode->i_sb->s_blocksize;
}
- /* Symlink is encrypted */
- sd = (struct fscrypt_symlink_data *)caddr;
- cstr.name = sd->encrypted_path;
- cstr.len = le16_to_cpu(sd->len);
- if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
- /* Symlink data on the disk is corrupted */
- res = -EFSCORRUPTED;
- goto errout;
- }
-
- res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
- if (res)
- goto errout;
- paddr = pstr.name;
-
- res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
- if (res)
- goto errout;
-
- /* Null-terminate the name */
- paddr[pstr.len] = '\0';
+ paddr = fscrypt_get_symlink(inode, caddr, max_size, done);
if (cpage)
put_page(cpage);
- set_delayed_call(done, kfree_link, paddr);
return paddr;
-errout:
- if (cpage)
- put_page(cpage);
- kfree(paddr);
- return ERR_PTR(res);
}
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 701781a..91b2d00 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -68,6 +68,7 @@
.old_blkaddr = index,
.new_blkaddr = index,
.encrypted_page = NULL,
+ .is_meta = is_meta,
};
if (unlikely(!is_meta))
@@ -162,6 +163,7 @@
.op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD,
.encrypted_page = NULL,
.in_list = false,
+ .is_meta = (type != META_POR),
};
struct blk_plug plug;
@@ -383,7 +385,7 @@
if (!PageUptodate(page))
SetPageUptodate(page);
if (!PageDirty(page)) {
- f2fs_set_page_dirty_nobuffers(page);
+ __set_page_dirty_nobuffers(page);
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META);
SetPagePrivate(page);
f2fs_trace_pid(page);
@@ -572,13 +574,8 @@
struct node_info ni;
int err = acquire_orphan_inode(sbi);
- if (err) {
- set_sbi_flag(sbi, SBI_NEED_FSCK);
- f2fs_msg(sbi->sb, KERN_WARNING,
- "%s: orphan failed (ino=%x), run fsck to fix.",
- __func__, ino);
- return err;
- }
+ if (err)
+ goto err_out;
__add_ino_entry(sbi, ino, 0, ORPHAN_INO);
@@ -592,6 +589,11 @@
return PTR_ERR(inode);
}
+ err = dquot_initialize(inode);
+ if (err)
+ goto err_out;
+
+ dquot_initialize(inode);
clear_nlink(inode);
/* truncate all the data during iput */
@@ -601,14 +603,18 @@
/* ENOMEM was fully retried in f2fs_evict_inode. */
if (ni.blk_addr != NULL_ADDR) {
- set_sbi_flag(sbi, SBI_NEED_FSCK);
- f2fs_msg(sbi->sb, KERN_WARNING,
- "%s: orphan failed (ino=%x) by kernel, retry mount.",
- __func__, ino);
- return -EIO;
+ err = -EIO;
+ goto err_out;
}
__remove_ino_entry(sbi, ino, ORPHAN_INO);
return 0;
+
+err_out:
+ set_sbi_flag(sbi, SBI_NEED_FSCK);
+ f2fs_msg(sbi->sb, KERN_WARNING,
+ "%s: orphan failed (ino=%x), run fsck to fix.",
+ __func__, ino);
+ return err;
}
int recover_orphan_inodes(struct f2fs_sb_info *sbi)
@@ -1139,6 +1145,8 @@
if (cpc->reason & CP_TRIMMED)
__set_ckpt_flags(ckpt, CP_TRIMMED_FLAG);
+ else
+ __clear_ckpt_flags(ckpt, CP_TRIMMED_FLAG);
if (cpc->reason & CP_UMOUNT)
__set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
@@ -1165,6 +1173,39 @@
spin_unlock_irqrestore(&sbi->cp_lock, flags);
}
+static void commit_checkpoint(struct f2fs_sb_info *sbi,
+ void *src, block_t blk_addr)
+{
+ struct writeback_control wbc = {
+ .for_reclaim = 0,
+ };
+
+ /*
+ * pagevec_lookup_tag and lock_page again will take
+ * some extra time. Therefore, update_meta_pages and
+ * sync_meta_pages are combined in this function.
+ */
+ struct page *page = grab_meta_page(sbi, blk_addr);
+ int err;
+
+ memcpy(page_address(page), src, PAGE_SIZE);
+ set_page_dirty(page);
+
+ f2fs_wait_on_page_writeback(page, META, true);
+ f2fs_bug_on(sbi, PageWriteback(page));
+ if (unlikely(!clear_page_dirty_for_io(page)))
+ f2fs_bug_on(sbi, 1);
+
+ /* writeout cp pack 2 page */
+ err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO);
+ f2fs_bug_on(sbi, err);
+
+ f2fs_put_page(page, 0);
+
+ /* submit checkpoint (with barrier if NOBARRIER is not set) */
+ f2fs_submit_merged_write(sbi, META_FLUSH);
+}
+
static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
{
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
@@ -1267,16 +1308,6 @@
}
}
- /* need to wait for end_io results */
- wait_on_all_pages_writeback(sbi);
- if (unlikely(f2fs_cp_error(sbi)))
- return -EIO;
-
- /* flush all device cache */
- err = f2fs_flush_device_cache(sbi);
- if (err)
- return err;
-
/* write out checkpoint buffer at block 0 */
update_meta_page(sbi, ckpt, start_blk++);
@@ -1304,26 +1335,26 @@
start_blk += NR_CURSEG_NODE_TYPE;
}
- /* writeout checkpoint block */
- update_meta_page(sbi, ckpt, start_blk);
+ /* update user_block_counts */
+ sbi->last_valid_block_count = sbi->total_valid_block_count;
+ percpu_counter_set(&sbi->alloc_valid_block_count, 0);
- /* wait for previous submitted node/meta pages writeback */
+ /* Here, we have one bio having CP pack except cp pack 2 page */
+ sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO);
+
+ /* wait for previous submitted meta pages writeback */
wait_on_all_pages_writeback(sbi);
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
- filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX);
- filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX);
+ /* flush all device cache */
+ err = f2fs_flush_device_cache(sbi);
+ if (err)
+ return err;
- /* update user_block_counts */
- sbi->last_valid_block_count = sbi->total_valid_block_count;
- percpu_counter_set(&sbi->alloc_valid_block_count, 0);
-
- /* Here, we only have one bio having CP pack */
- sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO);
-
- /* wait for previous submitted meta pages writeback */
+ /* barrier and flush checkpoint cp pack 2 page if it can */
+ commit_checkpoint(sbi, ckpt, start_blk);
wait_on_all_pages_writeback(sbi);
release_ino_entry(sbi, false);
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 6c13ee3..b1fd4e2 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -19,8 +19,6 @@
#include <linux/bio.h>
#include <linux/prefetch.h>
#include <linux/uio.h>
-#include <linux/mm.h>
-#include <linux/memcontrol.h>
#include <linux/cleancache.h>
#include "f2fs.h"
@@ -30,6 +28,11 @@
#include <trace/events/f2fs.h>
#include <trace/events/android_fs.h>
+#define NUM_PREALLOC_POST_READ_CTXS 128
+
+static struct kmem_cache *bio_post_read_ctx_cache;
+static mempool_t *bio_post_read_ctx_pool;
+
static bool __is_cp_guaranteed(struct page *page)
{
struct address_space *mapping = page->mapping;
@@ -50,11 +53,77 @@
return false;
}
-static void f2fs_read_end_io(struct bio *bio)
+/* postprocessing steps for read bios */
+enum bio_post_read_step {
+ STEP_INITIAL = 0,
+ STEP_DECRYPT,
+};
+
+struct bio_post_read_ctx {
+ struct bio *bio;
+ struct work_struct work;
+ unsigned int cur_step;
+ unsigned int enabled_steps;
+};
+
+static void __read_end_io(struct bio *bio)
{
- struct bio_vec *bvec;
+ struct page *page;
+ struct bio_vec *bv;
int i;
+ bio_for_each_segment_all(bv, bio, i) {
+ page = bv->bv_page;
+
+ /* PG_error was set if any post_read step failed */
+ if (bio->bi_error || PageError(page)) {
+ ClearPageUptodate(page);
+ SetPageError(page);
+ } else {
+ SetPageUptodate(page);
+ }
+ unlock_page(page);
+ }
+ if (bio->bi_private)
+ mempool_free(bio->bi_private, bio_post_read_ctx_pool);
+ bio_put(bio);
+}
+
+static void bio_post_read_processing(struct bio_post_read_ctx *ctx);
+
+static void decrypt_work(struct work_struct *work)
+{
+ struct bio_post_read_ctx *ctx =
+ container_of(work, struct bio_post_read_ctx, work);
+
+ fscrypt_decrypt_bio(ctx->bio);
+
+ bio_post_read_processing(ctx);
+}
+
+static void bio_post_read_processing(struct bio_post_read_ctx *ctx)
+{
+ switch (++ctx->cur_step) {
+ case STEP_DECRYPT:
+ if (ctx->enabled_steps & (1 << STEP_DECRYPT)) {
+ INIT_WORK(&ctx->work, decrypt_work);
+ fscrypt_enqueue_decrypt_work(&ctx->work);
+ return;
+ }
+ ctx->cur_step++;
+ /* fall-through */
+ default:
+ __read_end_io(ctx->bio);
+ }
+}
+
+static bool f2fs_bio_post_read_required(struct bio *bio)
+{
+ return bio->bi_private && !bio->bi_error;
+}
+
+static void f2fs_read_end_io(struct bio *bio)
+{
#ifdef CONFIG_F2FS_FAULT_INJECTION
if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) {
f2fs_show_injection_info(FAULT_IO);
@@ -62,28 +131,15 @@
}
#endif
- if (f2fs_bio_encrypted(bio)) {
- if (bio->bi_error) {
- fscrypt_release_ctx(bio->bi_private);
- } else {
- fscrypt_decrypt_bio_pages(bio->bi_private, bio);
- return;
- }
+ if (f2fs_bio_post_read_required(bio)) {
+ struct bio_post_read_ctx *ctx = bio->bi_private;
+
+ ctx->cur_step = STEP_INITIAL;
+ bio_post_read_processing(ctx);
+ return;
}
- bio_for_each_segment_all(bvec, bio, i) {
- struct page *page = bvec->bv_page;
-
- if (!bio->bi_error) {
- if (!PageUptodate(page))
- SetPageUptodate(page);
- } else {
- ClearPageUptodate(page);
- SetPageError(page);
- }
- unlock_page(page);
- }
- bio_put(bio);
+ __read_end_io(bio);
}
static void f2fs_write_end_io(struct bio *bio)
@@ -174,15 +230,22 @@
*/
static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
struct writeback_control *wbc,
- int npages, bool is_read)
+ int npages, bool is_read,
+ enum page_type type, enum temp_type temp)
{
struct bio *bio;
bio = f2fs_bio_alloc(sbi, npages, true);
f2fs_target_device(sbi, blk_addr, bio);
- bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
- bio->bi_private = is_read ? NULL : sbi;
+ if (is_read) {
+ bio->bi_end_io = f2fs_read_end_io;
+ bio->bi_private = NULL;
+ } else {
+ bio->bi_end_io = f2fs_write_end_io;
+ bio->bi_private = sbi;
+ bio->bi_write_hint = io_type_to_rw_hint(sbi, type, temp);
+ }
if (wbc)
wbc_init_bio(wbc, bio);
@@ -195,13 +258,12 @@
if (!is_read_io(bio_op(bio))) {
unsigned int start;
- if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
- current->plug && (type == DATA || type == NODE))
- blk_finish_plug(current->plug);
-
if (type != DATA && type != NODE)
goto submit_io;
+ if (f2fs_sb_has_blkzoned(sbi->sb) && current->plug)
+ blk_finish_plug(current->plug);
+
start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS;
start %= F2FS_IO_SIZE(sbi);
@@ -376,12 +438,13 @@
struct page *page = fio->encrypted_page ?
fio->encrypted_page : fio->page;
+ verify_block_addr(fio, fio->new_blkaddr);
trace_f2fs_submit_page_bio(page, fio);
f2fs_trace_ios(fio, 0);
/* Allocate a new bio */
bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc,
- 1, is_read_io(fio->op));
+ 1, is_read_io(fio->op), fio->type, fio->temp);
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
bio_put(bio);
@@ -421,8 +484,8 @@
}
if (fio->old_blkaddr != NEW_ADDR)
- verify_block_addr(sbi, fio->old_blkaddr);
- verify_block_addr(sbi, fio->new_blkaddr);
+ verify_block_addr(fio, fio->old_blkaddr);
+ verify_block_addr(fio, fio->new_blkaddr);
bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
@@ -444,7 +507,8 @@
goto out_fail;
}
io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc,
- BIO_MAX_PAGES, false);
+ BIO_MAX_PAGES, false,
+ fio->type, fio->temp);
io->fio = *fio;
}
@@ -472,29 +536,33 @@
unsigned nr_pages)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct fscrypt_ctx *ctx = NULL;
struct bio *bio;
+ struct bio_post_read_ctx *ctx;
+ unsigned int post_read_steps = 0;
- if (f2fs_encrypted_file(inode)) {
- ctx = fscrypt_get_ctx(inode, GFP_NOFS);
- if (IS_ERR(ctx))
- return ERR_CAST(ctx);
+ bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
+ if (!bio)
+ return ERR_PTR(-ENOMEM);
+ f2fs_target_device(sbi, blkaddr, bio);
+ bio->bi_end_io = f2fs_read_end_io;
+ bio_set_op_attrs(bio, REQ_OP_READ, 0);
+
+ if (f2fs_encrypted_file(inode))
+ post_read_steps |= 1 << STEP_DECRYPT;
+ if (post_read_steps) {
+ ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS);
+ if (!ctx) {
+ bio_put(bio);
+ return ERR_PTR(-ENOMEM);
+ }
+ ctx->bio = bio;
+ ctx->enabled_steps = post_read_steps;
+ bio->bi_private = ctx;
/* wait the page to be moved by cleaning */
f2fs_wait_on_block_writeback(sbi, blkaddr);
}
- bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
- if (!bio) {
- if (ctx)
- fscrypt_release_ctx(ctx);
- return ERR_PTR(-ENOMEM);
- }
- f2fs_target_device(sbi, blkaddr, bio);
- bio->bi_end_io = f2fs_read_end_io;
- bio->bi_private = ctx;
- bio_set_op_attrs(bio, REQ_OP_READ, 0);
-
return bio;
}
@@ -831,13 +899,6 @@
return 0;
}
-static inline bool __force_buffered_io(struct inode *inode, int rw)
-{
- return (f2fs_encrypted_file(inode) ||
- (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
- F2FS_I_SB(inode)->s_ndevs);
-}
-
int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from)
{
struct inode *inode = file_inode(iocb->ki_filp);
@@ -868,9 +929,8 @@
map.m_seg_type = NO_CHECK_TYPE;
if (direct_io) {
- /* map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); */
- map.m_seg_type = rw_hint_to_seg_type(WRITE_LIFE_NOT_SET);
- flag = __force_buffered_io(inode, WRITE) ?
+ map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint);
+ flag = f2fs_force_buffered_io(inode, WRITE) ?
F2FS_GET_BLOCK_PRE_AIO :
F2FS_GET_BLOCK_PRE_DIO;
goto map_blocks;
@@ -1114,6 +1174,31 @@
return err;
}
+bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len)
+{
+ struct f2fs_map_blocks map;
+ block_t last_lblk;
+ int err;
+
+ if (pos + len > i_size_read(inode))
+ return false;
+
+ map.m_lblk = F2FS_BYTES_TO_BLK(pos);
+ map.m_next_pgofs = NULL;
+ map.m_next_extent = NULL;
+ map.m_seg_type = NO_CHECK_TYPE;
+ last_lblk = F2FS_BLK_ALIGN(pos + len);
+
+ while (map.m_lblk < last_lblk) {
+ map.m_len = last_lblk - map.m_lblk;
+ err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT);
+ if (err || map.m_len == 0)
+ return false;
+ map.m_lblk += map.m_len;
+ }
+ return true;
+}
+
static int __get_data_block(struct inode *inode, sector_t iblock,
struct buffer_head *bh, int create, int flag,
pgoff_t *next_pgofs, int seg_type)
@@ -1151,8 +1236,7 @@
return __get_data_block(inode, iblock, bh_result, create,
F2FS_GET_BLOCK_DEFAULT, NULL,
rw_hint_to_seg_type(
- WRITE_LIFE_NOT_SET));
- /* inode->i_write_hint)); */
+ inode->i_write_hint));
}
static int get_data_block_bmap(struct inode *inode, sector_t iblock,
@@ -1500,7 +1584,7 @@
if (!f2fs_encrypted_file(inode))
return 0;
- /* wait for GCed encrypted page writeback */
+ /* wait for GCed page writeback via META_MAPPING */
f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr);
retry_encrypt:
@@ -1650,6 +1734,7 @@
goto out_writepage;
set_page_writeback(page);
+ ClearPageError(page);
f2fs_put_dnode(&dn);
if (fio->need_lock == LOCK_REQ)
f2fs_unlock_op(fio->sbi);
@@ -1672,6 +1757,7 @@
goto out_writepage;
set_page_writeback(page);
+ ClearPageError(page);
/* LFS mode write path */
write_data_page(&dn, fio);
@@ -2212,8 +2298,8 @@
f2fs_wait_on_page_writeback(page, DATA, false);
- /* wait for GCed encrypted page writeback */
- if (f2fs_encrypted_file(inode))
+ /* wait for GCed page writeback via META_MAPPING */
+ if (f2fs_post_read_required(inode))
f2fs_wait_on_block_writeback(sbi, blkaddr);
if (len == PAGE_SIZE || PageUptodate(page))
@@ -2304,16 +2390,19 @@
{
struct address_space *mapping = iocb->ki_filp->f_mapping;
struct inode *inode = mapping->host;
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
size_t count = iov_iter_count(iter);
loff_t offset = iocb->ki_pos;
int rw = iov_iter_rw(iter);
int err;
+ enum rw_hint hint = iocb->ki_hint;
+ int whint_mode = F2FS_OPTION(sbi).whint_mode;
err = check_direct_IO(inode, iter, offset);
if (err)
return err;
- if (__force_buffered_io(inode, rw))
+ if (f2fs_force_buffered_io(inode, rw))
return 0;
trace_f2fs_direct_IO_enter(inode, offset, count, rw);
@@ -2340,12 +2429,24 @@
current->pid, path,
current->comm);
}
+ if (rw == WRITE && whint_mode == WHINT_MODE_OFF)
+ iocb->ki_hint = WRITE_LIFE_NOT_SET;
- down_read(&F2FS_I(inode)->dio_rwsem[rw]);
+ if (!down_read_trylock(&F2FS_I(inode)->dio_rwsem[rw])) {
+ if (iocb->ki_flags & IOCB_NOWAIT) {
+ iocb->ki_hint = hint;
+ err = -EAGAIN;
+ goto out;
+ }
+ down_read(&F2FS_I(inode)->dio_rwsem[rw]);
+ }
+
err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio);
up_read(&F2FS_I(inode)->dio_rwsem[rw]);
if (rw == WRITE) {
+ if (whint_mode == WHINT_MODE_OFF)
+ iocb->ki_hint = hint;
if (err > 0) {
f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO,
err);
@@ -2354,7 +2455,7 @@
f2fs_write_failed(mapping, offset + count);
}
}
-
+out:
if (trace_android_fs_dataread_start_enabled() &&
(rw == READ))
trace_android_fs_dataread_end(inode, offset, count);
@@ -2411,35 +2512,6 @@
return 1;
}
-/*
- * This was copied from __set_page_dirty_buffers which gives higher performance
- * in very high speed storages. (e.g., pmem)
- */
-void f2fs_set_page_dirty_nobuffers(struct page *page)
-{
- struct address_space *mapping = page->mapping;
- unsigned long flags;
-
- if (unlikely(!mapping))
- return;
-
- spin_lock(&mapping->private_lock);
- lock_page_memcg(page);
- SetPageDirty(page);
- spin_unlock(&mapping->private_lock);
-
- spin_lock_irqsave(&mapping->tree_lock, flags);
- WARN_ON_ONCE(!PageUptodate(page));
- account_page_dirtied(page, mapping);
- radix_tree_tag_set(&mapping->page_tree,
- page_index(page), PAGECACHE_TAG_DIRTY);
- spin_unlock_irqrestore(&mapping->tree_lock, flags);
- unlock_page_memcg(page);
-
- __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
- return;
-}
-
static int f2fs_set_data_page_dirty(struct page *page)
{
struct address_space *mapping = page->mapping;
@@ -2463,7 +2535,7 @@
}
if (!PageDirty(page)) {
- f2fs_set_page_dirty_nobuffers(page);
+ __set_page_dirty_nobuffers(page);
update_dirty_page(inode, page);
return 1;
}
@@ -2556,3 +2628,27 @@
.migratepage = f2fs_migrate_page,
#endif
};
+
+int __init f2fs_init_post_read_processing(void)
+{
+ bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0);
+ if (!bio_post_read_ctx_cache)
+ goto fail;
+ bio_post_read_ctx_pool =
+ mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS,
+ bio_post_read_ctx_cache);
+ if (!bio_post_read_ctx_pool)
+ goto fail_free_cache;
+ return 0;
+
+fail_free_cache:
+ kmem_cache_destroy(bio_post_read_ctx_cache);
+fail:
+ return -ENOMEM;
+}
+
+void __exit f2fs_destroy_post_read_processing(void)
+{
+ mempool_destroy(bio_post_read_ctx_pool);
+ kmem_cache_destroy(bio_post_read_ctx_cache);
+}
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index a352ace5..f9a1e18 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -361,6 +361,7 @@
struct page *dpage)
{
struct page *page;
+ int dummy_encrypt = DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(dir));
int err;
if (is_inode_flag_set(inode, FI_NEW_INODE)) {
@@ -387,7 +388,8 @@
if (err)
goto put_error;
- if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) {
+ if ((f2fs_encrypted_inode(dir) || dummy_encrypt) &&
+ f2fs_may_encrypt(inode)) {
err = fscrypt_inherit_context(dir, inode, page, false);
if (err)
goto put_error;
@@ -396,8 +398,6 @@
page = get_node_page(F2FS_I_SB(dir), inode->i_ino);
if (IS_ERR(page))
return page;
-
- set_cold_node(inode, page);
}
if (new_name) {
@@ -704,7 +704,8 @@
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
- add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
+ if (F2FS_OPTION(F2FS_I_SB(dir)).fsync_mode == FSYNC_MODE_STRICT)
+ add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
if (f2fs_has_inline_dentry(dir))
return f2fs_delete_inline_entry(dentry, page, dir, inode);
diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c
index ff2352a..d5a861b 100644
--- a/fs/f2fs/extent_cache.c
+++ b/fs/f2fs/extent_cache.c
@@ -460,7 +460,7 @@
struct rb_node *insert_parent)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct rb_node **p = &et->root.rb_node;
+ struct rb_node **p;
struct rb_node *parent = NULL;
struct extent_node *en = NULL;
@@ -706,6 +706,9 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct extent_tree *et = F2FS_I(inode)->extent_tree;
+ if (!f2fs_may_extent_tree(inode))
+ return;
+
set_inode_flag(inode, FI_NO_EXTENT);
write_lock(&et->lock);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index e5d3e22..84be1e7 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -99,9 +99,10 @@
#define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000
#define F2FS_MOUNT_RESERVE_ROOT 0x01000000
-#define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
-#define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option)
-#define test_opt(sbi, option) ((sbi)->mount_opt.opt & F2FS_MOUNT_##option)
+#define F2FS_OPTION(sbi) ((sbi)->mount_opt)
+#define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option)
+#define set_opt(sbi, option) (F2FS_OPTION(sbi).opt |= F2FS_MOUNT_##option)
+#define test_opt(sbi, option) (F2FS_OPTION(sbi).opt & F2FS_MOUNT_##option)
#define ver_after(a, b) (typecheck(unsigned long long, a) && \
typecheck(unsigned long long, b) && \
@@ -114,7 +115,26 @@
typedef u32 nid_t;
struct f2fs_mount_info {
- unsigned int opt;
+ unsigned int opt;
+ int write_io_size_bits; /* Write IO size bits */
+ block_t root_reserved_blocks; /* root reserved blocks */
+ kuid_t s_resuid; /* reserved blocks for uid */
+ kgid_t s_resgid; /* reserved blocks for gid */
+ int active_logs; /* # of active logs */
+ int inline_xattr_size; /* inline xattr size */
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+ struct f2fs_fault_info fault_info; /* For fault injection */
+#endif
+#ifdef CONFIG_QUOTA
+ /* Names of quota files with journalled quota */
+ char *s_qf_names[MAXQUOTAS];
+ int s_jquota_fmt; /* Format of quota to use */
+#endif
+ /* For which write hints are passed down to block layer */
+ int whint_mode;
+ int alloc_mode; /* segment allocation policy */
+ int fsync_mode; /* fsync policy */
+ bool test_dummy_encryption; /* test dummy encryption */
};
#define F2FS_FEATURE_ENCRYPT 0x0001
@@ -126,6 +146,8 @@
#define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040
#define F2FS_FEATURE_QUOTA_INO 0x0080
#define F2FS_FEATURE_INODE_CRTIME 0x0100
+#define F2FS_FEATURE_LOST_FOUND 0x0200
+#define F2FS_FEATURE_VERITY 0x0400 /* reserved */
#define F2FS_HAS_FEATURE(sb, mask) \
((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0)
@@ -448,7 +470,7 @@
d->inode = inode;
d->max = NR_DENTRY_IN_BLOCK;
d->nr_bitmap = SIZE_OF_DENTRY_BITMAP;
- d->bitmap = &t->dentry_bitmap;
+ d->bitmap = t->dentry_bitmap;
d->dentry = t->dentry;
d->filename = t->filename;
}
@@ -574,6 +596,8 @@
#define FADVISE_ENCRYPT_BIT 0x04
#define FADVISE_ENC_NAME_BIT 0x08
#define FADVISE_KEEP_SIZE_BIT 0x10
+#define FADVISE_HOT_BIT 0x20
+#define FADVISE_VERITY_BIT 0x40 /* reserved */
#define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT)
#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
@@ -588,6 +612,9 @@
#define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT)
#define file_keep_isize(inode) is_file(inode, FADVISE_KEEP_SIZE_BIT)
#define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT)
+#define file_is_hot(inode) is_file(inode, FADVISE_HOT_BIT)
+#define file_set_hot(inode) set_file(inode, FADVISE_HOT_BIT)
+#define file_clear_hot(inode) clear_file(inode, FADVISE_HOT_BIT)
#define DEF_DIR_LEVEL 0
@@ -635,6 +662,7 @@
kprojid_t i_projid; /* id for project quota */
int i_inline_xattr_size; /* inline xattr size */
struct timespec i_crtime; /* inode creation time */
+ struct timespec i_disk_time[4]; /* inode disk times */
};
static inline void get_extent_info(struct extent_info *ext,
@@ -741,7 +769,7 @@
unsigned int nid_cnt[MAX_NID_STATE]; /* the number of free node id */
spinlock_t nid_list_lock; /* protect nid lists ops */
struct mutex build_lock; /* lock for build free nids */
- unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE];
+ unsigned char **free_nid_bitmap;
unsigned char *nat_block_bitmap;
unsigned short *free_nid_count; /* free nid count of NAT block */
@@ -974,6 +1002,7 @@
bool submitted; /* indicate IO submission */
int need_lock; /* indicate we need to lock cp_rwsem */
bool in_list; /* indicate fio is in io_list */
+ bool is_meta; /* indicate borrow meta inode mapping or not */
enum iostat_type io_type; /* io type */
struct writeback_control *io_wbc; /* writeback control */
};
@@ -1035,10 +1064,34 @@
MAX_TIME,
};
+enum {
+ WHINT_MODE_OFF, /* not pass down write hints */
+ WHINT_MODE_USER, /* try to pass down hints given by users */
+ WHINT_MODE_FS, /* pass down hints with F2FS policy */
+};
+
+enum {
+ ALLOC_MODE_DEFAULT, /* stay default */
+ ALLOC_MODE_REUSE, /* reuse segments as much as possible */
+};
+
+enum fsync_mode {
+ FSYNC_MODE_POSIX, /* fsync follows posix semantics */
+ FSYNC_MODE_STRICT, /* fsync behaves in line with ext4 */
+};
+
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+#define DUMMY_ENCRYPTION_ENABLED(sbi) \
+ (unlikely(F2FS_OPTION(sbi).test_dummy_encryption))
+#else
+#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
+#endif
+
struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */
struct f2fs_super_block *raw_super; /* raw super block pointer */
+ struct rw_semaphore sb_lock; /* lock for raw super block */
int valid_super_block; /* valid super block no */
unsigned long s_flag; /* flags for sbi */
@@ -1058,7 +1111,6 @@
struct f2fs_bio_info *write_io[NR_PAGE_TYPE]; /* for write bios */
struct mutex wio_mutex[NR_PAGE_TYPE - 1][NR_TEMP_TYPE];
/* bio ordering for NODE/DATA */
- int write_io_size_bits; /* Write IO size bits */
mempool_t *write_io_dummy; /* Dummy pages */
/* for checkpoint */
@@ -1108,9 +1160,7 @@
unsigned int total_node_count; /* total node block count */
unsigned int total_valid_node_count; /* valid node block count */
loff_t max_file_blocks; /* max block index of file */
- int active_logs; /* # of active logs */
int dir_level; /* directory level */
- int inline_xattr_size; /* inline xattr size */
unsigned int trigger_ssr_threshold; /* threshold to trigger ssr */
int readdir_ra; /* readahead inode in readdir */
@@ -1120,9 +1170,6 @@
block_t last_valid_block_count; /* for recovery */
block_t reserved_blocks; /* configurable reserved blocks */
block_t current_reserved_blocks; /* current reserved blocks */
- block_t root_reserved_blocks; /* root reserved blocks */
- kuid_t s_resuid; /* reserved blocks for uid */
- kgid_t s_resgid; /* reserved blocks for gid */
unsigned int nquota_files; /* # of quota sysfile */
@@ -1207,17 +1254,6 @@
/* Precomputed FS UUID checksum for seeding other checksums */
__u32 s_chksum_seed;
-
- /* For fault injection */
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- struct f2fs_fault_info fault_info;
-#endif
-
-#ifdef CONFIG_QUOTA
- /* Names of quota files with journalled quota */
- char *s_qf_names[MAXQUOTAS];
- int s_jquota_fmt; /* Format of quota to use */
-#endif
};
#ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -1227,7 +1263,7 @@
__func__, __builtin_return_address(0))
static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type)
{
- struct f2fs_fault_info *ffi = &sbi->fault_info;
+ struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
if (!ffi->inject_rate)
return false;
@@ -1576,7 +1612,7 @@
}
static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi,
- struct inode *inode)
+ struct inode *inode, bool cap)
{
if (!inode)
return true;
@@ -1584,12 +1620,12 @@
return false;
if (IS_NOQUOTA(inode))
return true;
- if (capable(CAP_SYS_RESOURCE))
+ if (uid_eq(F2FS_OPTION(sbi).s_resuid, current_fsuid()))
return true;
- if (uid_eq(sbi->s_resuid, current_fsuid()))
+ if (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) &&
+ in_group_p(F2FS_OPTION(sbi).s_resgid))
return true;
- if (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) &&
- in_group_p(sbi->s_resgid))
+ if (cap && capable(CAP_SYS_RESOURCE))
return true;
return false;
}
@@ -1624,8 +1660,8 @@
avail_user_block_count = sbi->user_block_count -
sbi->current_reserved_blocks;
- if (!__allow_reserved_blocks(sbi, inode))
- avail_user_block_count -= sbi->root_reserved_blocks;
+ if (!__allow_reserved_blocks(sbi, inode, true))
+ avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks;
if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) {
diff = sbi->total_valid_block_count - avail_user_block_count;
@@ -1760,6 +1796,12 @@
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
int offset;
+ if (is_set_ckpt_flags(sbi, CP_LARGE_NAT_BITMAP_FLAG)) {
+ offset = (flag == SIT_BITMAP) ?
+ le32_to_cpu(ckpt->nat_ver_bitmap_bytesize) : 0;
+ return &ckpt->sit_nat_version_bitmap + offset;
+ }
+
if (__cp_payload(sbi) > 0) {
if (flag == NAT_BITMAP)
return &ckpt->sit_nat_version_bitmap;
@@ -1825,8 +1867,8 @@
valid_block_count = sbi->total_valid_block_count +
sbi->current_reserved_blocks + 1;
- if (!__allow_reserved_blocks(sbi, inode))
- valid_block_count += sbi->root_reserved_blocks;
+ if (!__allow_reserved_blocks(sbi, inode, false))
+ valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks;
if (unlikely(valid_block_count > sbi->user_block_count)) {
spin_unlock(&sbi->stat_lock);
@@ -2428,7 +2470,17 @@
}
if (!is_inode_flag_set(inode, FI_AUTO_RECOVER) ||
file_keep_isize(inode) ||
- i_size_read(inode) & PAGE_MASK)
+ i_size_read(inode) & ~PAGE_MASK)
+ return false;
+
+ if (!timespec_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime))
+ return false;
+ if (!timespec_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime))
+ return false;
+ if (!timespec_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime))
+ return false;
+ if (!timespec_equal(F2FS_I(inode)->i_disk_time + 3,
+ &F2FS_I(inode)->i_crtime))
return false;
down_read(&F2FS_I(inode)->i_sem);
@@ -2438,8 +2490,7 @@
return ret;
}
-#define sb_rdonly f2fs_readonly
-static inline int f2fs_readonly(struct super_block *sb)
+static inline bool f2fs_readonly(struct super_block *sb)
{
return sb->s_flags & MS_RDONLY;
}
@@ -2501,15 +2552,6 @@
return ret;
}
-enum rw_hint {
- WRITE_LIFE_NOT_SET = 0,
- WRITE_LIFE_NONE = 1, /* RWH_WRITE_LIFE_NONE */
- WRITE_LIFE_SHORT = 2, /* RWH_WRITE_LIFE_SHORT */
- WRITE_LIFE_MEDIUM = 3, /* RWH_WRITE_LIFE_MEDIUM */
- WRITE_LIFE_LONG = 4, /* RWH_WRITE_LIFE_LONG */
- WRITE_LIFE_EXTREME = 5, /* RWH_WRITE_LIFE_EXTREME */
-};
-
static inline int wbc_to_write_flags(struct writeback_control *wbc)
{
if (wbc->sync_mode == WB_SYNC_ALL)
@@ -2628,6 +2670,8 @@
/*
* namei.c
*/
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+ bool hot, bool set);
struct dentry *f2fs_get_parent(struct dentry *child);
/*
@@ -2800,6 +2844,8 @@
int __init create_segment_manager_caches(void);
void destroy_segment_manager_caches(void);
int rw_hint_to_seg_type(enum rw_hint hint);
+enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, enum page_type type,
+ enum temp_type temp);
/*
* checkpoint.c
@@ -2840,6 +2886,8 @@
/*
* data.c
*/
+int f2fs_init_post_read_processing(void);
+void f2fs_destroy_post_read_processing(void);
void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type);
void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi,
struct inode *inode, nid_t ino, pgoff_t idx,
@@ -2871,7 +2919,6 @@
u64 start, u64 len);
bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio);
bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio);
-void f2fs_set_page_dirty_nobuffers(struct page *page);
int __f2fs_write_data_pages(struct address_space *mapping,
struct writeback_control *wbc,
enum iostat_type io_type);
@@ -2882,6 +2929,7 @@
int f2fs_migrate_page(struct address_space *mapping, struct page *newpage,
struct page *page, enum migrate_mode mode);
#endif
+bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len);
/*
* gc.c
@@ -3199,50 +3247,30 @@
#endif
}
-static inline bool f2fs_bio_encrypted(struct bio *bio)
+/*
+ * Returns true if the reads of the inode's data need to undergo some
+ * postprocessing step, like decryption or authenticity verification.
+ */
+static inline bool f2fs_post_read_required(struct inode *inode)
{
- return bio->bi_private != NULL;
+ return f2fs_encrypted_file(inode);
}
-static inline int f2fs_sb_has_crypto(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT);
+#define F2FS_FEATURE_FUNCS(name, flagname) \
+static inline int f2fs_sb_has_##name(struct super_block *sb) \
+{ \
+ return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_##flagname); \
}
-static inline int f2fs_sb_mounted_blkzoned(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_BLKZONED);
-}
-
-static inline int f2fs_sb_has_extra_attr(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR);
-}
-
-static inline int f2fs_sb_has_project_quota(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA);
-}
-
-static inline int f2fs_sb_has_inode_chksum(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM);
-}
-
-static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR);
-}
-
-static inline int f2fs_sb_has_quota_ino(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO);
-}
-
-static inline int f2fs_sb_has_inode_crtime(struct super_block *sb)
-{
- return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CRTIME);
-}
+F2FS_FEATURE_FUNCS(encrypt, ENCRYPT);
+F2FS_FEATURE_FUNCS(blkzoned, BLKZONED);
+F2FS_FEATURE_FUNCS(extra_attr, EXTRA_ATTR);
+F2FS_FEATURE_FUNCS(project_quota, PRJQUOTA);
+F2FS_FEATURE_FUNCS(inode_chksum, INODE_CHKSUM);
+F2FS_FEATURE_FUNCS(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR);
+F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO);
+F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME);
+F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND);
#ifdef CONFIG_BLK_DEV_ZONED
static inline int get_blkz_type(struct f2fs_sb_info *sbi,
@@ -3262,7 +3290,7 @@
{
struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev);
- return blk_queue_discard(q) || f2fs_sb_mounted_blkzoned(sbi->sb);
+ return blk_queue_discard(q) || f2fs_sb_has_blkzoned(sbi->sb);
}
static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt)
@@ -3291,4 +3319,11 @@
#endif
}
+static inline bool f2fs_force_buffered_io(struct inode *inode, int rw)
+{
+ return (f2fs_post_read_required(inode) ||
+ (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) ||
+ F2FS_I_SB(inode)->s_ndevs);
+}
+
#endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index b926df7..0e39c77 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -112,8 +112,8 @@
/* fill the page */
f2fs_wait_on_page_writeback(page, DATA, false);
- /* wait for GCed encrypted page writeback */
- if (f2fs_encrypted_file(inode))
+ /* wait for GCed page writeback via META_MAPPING */
+ if (f2fs_post_read_required(inode))
f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr);
out_sem:
@@ -165,9 +165,10 @@
cp_reason = CP_NODE_NEED_CP;
else if (test_opt(sbi, FASTBOOT))
cp_reason = CP_FASTBOOT_MODE;
- else if (sbi->active_logs == 2)
+ else if (F2FS_OPTION(sbi).active_logs == 2)
cp_reason = CP_SPEC_LOG_NUM;
- else if (need_dentry_mark(sbi, inode->i_ino) &&
+ else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT &&
+ need_dentry_mark(sbi, inode->i_ino) &&
exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
cp_reason = CP_RECOVER_DIR;
@@ -480,6 +481,9 @@
if (err)
return err;
+
+ filp->f_mode |= FMODE_NOWAIT;
+
return dquot_file_open(inode, filp);
}
@@ -570,7 +574,6 @@
int truncate_blocks(struct inode *inode, u64 from, bool lock)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- unsigned int blocksize = inode->i_sb->s_blocksize;
struct dnode_of_data dn;
pgoff_t free_from;
int count = 0, err = 0;
@@ -579,7 +582,7 @@
trace_f2fs_truncate_blocks_enter(inode, from);
- free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1);
+ free_from = (pgoff_t)F2FS_BLK_ALIGN(from);
if (free_from >= sbi->max_file_blocks)
goto free_partial;
@@ -1350,8 +1353,12 @@
}
out:
- if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size)
- f2fs_i_size_write(inode, new_size);
+ if (new_size > i_size_read(inode)) {
+ if (mode & FALLOC_FL_KEEP_SIZE)
+ file_set_keep_isize(inode);
+ else
+ f2fs_i_size_write(inode, new_size);
+ }
out_sem:
up_write(&F2FS_I(inode)->i_mmap_sem);
@@ -1705,6 +1712,8 @@
inode_lock(inode);
+ down_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
+
if (f2fs_is_volatile_file(inode))
goto err_out;
@@ -1723,6 +1732,7 @@
ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false);
}
err_out:
+ up_write(&F2FS_I(inode)->dio_rwsem[WRITE]);
inode_unlock(inode);
mnt_drop_write_file(filp);
return ret;
@@ -1932,7 +1942,7 @@
{
struct inode *inode = file_inode(filp);
- if (!f2fs_sb_has_crypto(inode->i_sb))
+ if (!f2fs_sb_has_encrypt(inode->i_sb))
return -EOPNOTSUPP;
f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
@@ -1942,7 +1952,7 @@
static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg)
{
- if (!f2fs_sb_has_crypto(file_inode(filp)->i_sb))
+ if (!f2fs_sb_has_encrypt(file_inode(filp)->i_sb))
return -EOPNOTSUPP;
return fscrypt_ioctl_get_policy(filp, (void __user *)arg);
}
@@ -1953,16 +1963,18 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
int err;
- if (!f2fs_sb_has_crypto(inode->i_sb))
+ if (!f2fs_sb_has_encrypt(inode->i_sb))
return -EOPNOTSUPP;
- if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
- goto got_it;
-
err = mnt_want_write_file(filp);
if (err)
return err;
+ down_write(&sbi->sb_lock);
+
+ if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt))
+ goto got_it;
+
/* update superblock with uuid */
generate_random_uuid(sbi->raw_super->encrypt_pw_salt);
@@ -1970,15 +1982,16 @@
if (err) {
/* undo new data */
memset(sbi->raw_super->encrypt_pw_salt, 0, 16);
- mnt_drop_write_file(filp);
- return err;
+ goto out_err;
}
- mnt_drop_write_file(filp);
got_it:
if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt,
16))
- return -EFAULT;
- return 0;
+ err = -EFAULT;
+out_err:
+ up_write(&sbi->sb_lock);
+ mnt_drop_write_file(filp);
+ return err;
}
static int f2fs_ioc_gc(struct file *filp, unsigned long arg)
@@ -2039,8 +2052,10 @@
return ret;
end = range.start + range.len;
- if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi))
- return -EINVAL;
+ if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) {
+ ret = -EINVAL;
+ goto out;
+ }
do_more:
if (!range.sync) {
if (!mutex_trylock(&sbi->gc_mutex)) {
@@ -2681,25 +2696,54 @@
if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
return -EIO;
- inode_lock(inode);
+ if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT))
+ return -EINVAL;
+
+ if (!inode_trylock(inode)) {
+ if (iocb->ki_flags & IOCB_NOWAIT)
+ return -EAGAIN;
+ inode_lock(inode);
+ }
+
ret = generic_write_checks(iocb, from);
if (ret > 0) {
+ bool preallocated = false;
+ size_t target_size = 0;
int err;
if (iov_iter_fault_in_readable(from, iov_iter_count(from)))
set_inode_flag(inode, FI_NO_PREALLOC);
- err = f2fs_preallocate_blocks(iocb, from);
- if (err) {
- clear_inode_flag(inode, FI_NO_PREALLOC);
- inode_unlock(inode);
- return err;
+ if ((iocb->ki_flags & IOCB_NOWAIT) &&
+ (iocb->ki_flags & IOCB_DIRECT)) {
+ if (!f2fs_overwrite_io(inode, iocb->ki_pos,
+ iov_iter_count(from)) ||
+ f2fs_has_inline_data(inode) ||
+ f2fs_force_buffered_io(inode, WRITE)) {
+ inode_unlock(inode);
+ return -EAGAIN;
+ }
+
+ } else {
+ preallocated = true;
+ target_size = iocb->ki_pos + iov_iter_count(from);
+
+ err = f2fs_preallocate_blocks(iocb, from);
+ if (err) {
+ clear_inode_flag(inode, FI_NO_PREALLOC);
+ inode_unlock(inode);
+ return err;
+ }
}
blk_start_plug(&plug);
ret = __generic_file_write_iter(iocb, from);
blk_finish_plug(&plug);
clear_inode_flag(inode, FI_NO_PREALLOC);
+ /* if we couldn't write data, we should deallocate blocks. */
+ if (preallocated && i_size_read(inode) < target_size)
+ f2fs_truncate(inode);
+
if (ret > 0)
f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret);
}
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 3b26aa1..604d3fc 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -76,14 +76,15 @@
* invalidated soon after by user update or deletion.
* So, I'd like to wait some time to collect dirty segments.
*/
- if (!mutex_trylock(&sbi->gc_mutex))
- goto next;
-
if (gc_th->gc_urgent) {
wait_ms = gc_th->urgent_sleep_time;
+ mutex_lock(&sbi->gc_mutex);
goto do_gc;
}
+ if (!mutex_trylock(&sbi->gc_mutex))
+ goto next;
+
if (!is_idle(sbi)) {
increase_sleep_time(gc_th, &wait_ms);
mutex_unlock(&sbi->gc_mutex);
@@ -161,12 +162,17 @@
{
int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY;
- if (gc_th && gc_th->gc_idle) {
+ if (!gc_th)
+ return gc_mode;
+
+ if (gc_th->gc_idle) {
if (gc_th->gc_idle == 1)
gc_mode = GC_CB;
else if (gc_th->gc_idle == 2)
gc_mode = GC_GREEDY;
}
+ if (gc_th->gc_urgent)
+ gc_mode = GC_GREEDY;
return gc_mode;
}
@@ -188,11 +194,14 @@
}
/* we need to check every dirty segments in the FG_GC case */
- if (gc_type != FG_GC && p->max_search > sbi->max_victim_search)
+ if (gc_type != FG_GC &&
+ (sbi->gc_thread && !sbi->gc_thread->gc_urgent) &&
+ p->max_search > sbi->max_victim_search)
p->max_search = sbi->max_victim_search;
- /* let's select beginning hot/small space first */
- if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+ /* let's select beginning hot/small space first in no_heap mode*/
+ if (test_opt(sbi, NOHEAP) &&
+ (type == CURSEG_HOT_DATA || IS_NODESEG(type)))
p->offset = 0;
else
p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
@@ -841,8 +850,8 @@
if (IS_ERR(inode) || is_bad_inode(inode))
continue;
- /* if encrypted inode, let's go phase 3 */
- if (f2fs_encrypted_file(inode)) {
+ /* if inode uses special I/O path, let's go phase 3 */
+ if (f2fs_post_read_required(inode)) {
add_gc_inode(gc_list, inode);
continue;
}
@@ -890,7 +899,7 @@
start_bidx = start_bidx_of_node(nofs, inode)
+ ofs_in_node;
- if (f2fs_encrypted_file(inode))
+ if (f2fs_post_read_required(inode))
move_data_block(inode, start_bidx, segno, off);
else
move_data_page(inode, start_bidx, gc_type,
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 1925814..26832e7 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -26,7 +26,7 @@
if (i_size_read(inode) > MAX_INLINE_DATA(inode))
return false;
- if (f2fs_encrypted_file(inode))
+ if (f2fs_post_read_required(inode))
return false;
return true;
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 10be247..e0d9e8f 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -284,6 +284,10 @@
fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec);
}
+ F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
+ F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
+ F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
+ F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
f2fs_put_page(node_page, 1);
stat_inc_inline_xattr(inode);
@@ -439,12 +443,15 @@
}
__set_inode_rdev(inode, ri);
- set_cold_node(inode, node_page);
/* deleted inode */
if (inode->i_nlink == 0)
clear_inline_node(node_page);
+ F2FS_I(inode)->i_disk_time[0] = inode->i_atime;
+ F2FS_I(inode)->i_disk_time[1] = inode->i_ctime;
+ F2FS_I(inode)->i_disk_time[2] = inode->i_mtime;
+ F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime;
}
void update_inode_page(struct inode *inode)
@@ -585,7 +592,7 @@
!exist_written_data(sbi, inode->i_ino, ORPHAN_INO));
}
out_clear:
- fscrypt_put_encryption_info(inode, NULL);
+ fscrypt_put_encryption_info(inode);
clear_inode(inode);
}
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 59e8dca..392d1ed 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -78,7 +78,8 @@
set_inode_flag(inode, FI_NEW_INODE);
/* If the directory encrypted, then we should encrypt the inode. */
- if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode))
+ if ((f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) &&
+ f2fs_may_encrypt(inode))
f2fs_set_encrypted_inode(inode);
if (f2fs_sb_has_extra_attr(sbi->sb)) {
@@ -97,7 +98,7 @@
if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) {
f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode));
if (f2fs_has_inline_xattr(inode))
- xattr_size = sbi->inline_xattr_size;
+ xattr_size = F2FS_OPTION(sbi).inline_xattr_size;
/* Otherwise, will be 0 */
} else if (f2fs_has_inline_xattr(inode) ||
f2fs_has_inline_dentry(inode)) {
@@ -142,7 +143,7 @@
return ERR_PTR(err);
}
-static int is_multimedia_file(const unsigned char *s, const char *sub)
+static int is_extension_exist(const unsigned char *s, const char *sub)
{
size_t slen = strlen(s);
size_t sublen = strlen(sub);
@@ -168,19 +169,94 @@
/*
* Set multimedia files as cold files for hot/cold data separation
*/
-static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
+static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode,
const unsigned char *name)
{
- int i;
- __u8 (*extlist)[8] = sbi->raw_super->extension_list;
+ __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+ int i, cold_count, hot_count;
- int count = le32_to_cpu(sbi->raw_super->extension_count);
- for (i = 0; i < count; i++) {
- if (is_multimedia_file(name, extlist[i])) {
+ down_read(&sbi->sb_lock);
+
+ cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+ hot_count = sbi->raw_super->hot_ext_count;
+
+ for (i = 0; i < cold_count + hot_count; i++) {
+ if (!is_extension_exist(name, extlist[i]))
+ continue;
+ if (i < cold_count)
file_set_cold(inode);
- break;
- }
+ else
+ file_set_hot(inode);
+ break;
}
+
+ up_read(&sbi->sb_lock);
+}
+
+int update_extension_list(struct f2fs_sb_info *sbi, const char *name,
+ bool hot, bool set)
+{
+ __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list;
+ int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+ int hot_count = sbi->raw_super->hot_ext_count;
+ int total_count = cold_count + hot_count;
+ int start, count;
+ int i;
+
+ if (set) {
+ if (total_count == F2FS_MAX_EXTENSION)
+ return -EINVAL;
+ } else {
+ if (!hot && !cold_count)
+ return -EINVAL;
+ if (hot && !hot_count)
+ return -EINVAL;
+ }
+
+ if (hot) {
+ start = cold_count;
+ count = total_count;
+ } else {
+ start = 0;
+ count = cold_count;
+ }
+
+ for (i = start; i < count; i++) {
+ if (strcmp(name, extlist[i]))
+ continue;
+
+ if (set)
+ return -EINVAL;
+
+ memcpy(extlist[i], extlist[i + 1],
+ F2FS_EXTENSION_LEN * (total_count - i - 1));
+ memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN);
+ if (hot)
+ sbi->raw_super->hot_ext_count = hot_count - 1;
+ else
+ sbi->raw_super->extension_count =
+ cpu_to_le32(cold_count - 1);
+ return 0;
+ }
+
+ if (!set)
+ return -EINVAL;
+
+ if (hot) {
+ strncpy(extlist[count], name, strlen(name));
+ sbi->raw_super->hot_ext_count = hot_count + 1;
+ } else {
+ char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];
+
+ memcpy(buf, &extlist[cold_count],
+ F2FS_EXTENSION_LEN * hot_count);
+ memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN);
+ strncpy(extlist[cold_count], name, strlen(name));
+ memcpy(&extlist[cold_count + 1], buf,
+ F2FS_EXTENSION_LEN * hot_count);
+ sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1);
+ }
+ return 0;
}
static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
@@ -203,7 +279,7 @@
return PTR_ERR(inode);
if (!test_opt(sbi, DISABLE_EXT_IDENTIFY))
- set_cold_files(sbi, inode, dentry->d_name.name);
+ set_file_temperature(sbi, inode, dentry->d_name.name);
inode->i_op = &f2fs_file_inode_operations;
inode->i_fop = &f2fs_file_operations;
@@ -218,8 +294,8 @@
alloc_nid_done(sbi, ino);
- d_instantiate(dentry, inode);
unlock_new_inode(inode);
+ d_instantiate(dentry, inode);
if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
@@ -481,27 +557,16 @@
struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
struct inode *inode;
size_t len = strlen(symname);
- struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1);
- struct fscrypt_symlink_data *sd = NULL;
+ struct fscrypt_str disk_link;
int err;
if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
- if (f2fs_encrypted_inode(dir)) {
- err = fscrypt_get_encryption_info(dir);
- if (err)
- return err;
-
- if (!fscrypt_has_encryption_key(dir))
- return -ENOKEY;
-
- disk_link.len = (fscrypt_fname_encrypted_size(dir, len) +
- sizeof(struct fscrypt_symlink_data));
- }
-
- if (disk_link.len > dir->i_sb->s_blocksize)
- return -ENAMETOOLONG;
+ err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
+ &disk_link);
+ if (err)
+ return err;
err = dquot_initialize(dir);
if (err)
@@ -511,7 +576,7 @@
if (IS_ERR(inode))
return PTR_ERR(inode);
- if (f2fs_encrypted_inode(inode))
+ if (IS_ENCRYPTED(inode))
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
else
inode->i_op = &f2fs_symlink_inode_operations;
@@ -521,44 +586,19 @@
f2fs_lock_op(sbi);
err = f2fs_add_link(dentry, inode);
if (err)
- goto out;
+ goto out_handle_failed_inode;
f2fs_unlock_op(sbi);
alloc_nid_done(sbi, inode->i_ino);
- if (f2fs_encrypted_inode(inode)) {
- struct qstr istr = QSTR_INIT(symname, len);
- struct fscrypt_str ostr;
-
- sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS);
- if (!sd) {
- err = -ENOMEM;
- goto err_out;
- }
-
- err = fscrypt_get_encryption_info(inode);
- if (err)
- goto err_out;
-
- if (!fscrypt_has_encryption_key(inode)) {
- err = -ENOKEY;
- goto err_out;
- }
-
- ostr.name = sd->encrypted_path;
- ostr.len = disk_link.len;
- err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr);
- if (err)
- goto err_out;
-
- sd->len = cpu_to_le16(ostr.len);
- disk_link.name = (char *)sd;
- }
+ err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link);
+ if (err)
+ goto err_out;
err = page_symlink(inode, disk_link.name, disk_link.len);
err_out:
- d_instantiate(dentry, inode);
unlock_new_inode(inode);
+ d_instantiate(dentry, inode);
/*
* Let's flush symlink data in order to avoid broken symlink as much as
@@ -579,12 +619,14 @@
f2fs_unlink(dir, dentry);
}
- kfree(sd);
-
f2fs_balance_fs(sbi, true);
- return err;
-out:
+ goto out_free_encrypted_link;
+
+out_handle_failed_inode:
handle_failed_inode(inode);
+out_free_encrypted_link:
+ if (disk_link.name != (unsigned char *)symname)
+ kfree(disk_link.name);
return err;
}
@@ -619,8 +661,8 @@
alloc_nid_done(sbi, inode->i_ino);
- d_instantiate(dentry, inode);
unlock_new_inode(inode);
+ d_instantiate(dentry, inode);
if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
@@ -671,8 +713,8 @@
alloc_nid_done(sbi, inode->i_ino);
- d_instantiate(dentry, inode);
unlock_new_inode(inode);
+ d_instantiate(dentry, inode);
if (IS_DIRSYNC(dir))
f2fs_sync_fs(sbi->sb, 1);
@@ -746,10 +788,12 @@
static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
{
- if (unlikely(f2fs_cp_error(F2FS_I_SB(dir))))
+ struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+
+ if (unlikely(f2fs_cp_error(sbi)))
return -EIO;
- if (f2fs_encrypted_inode(dir)) {
+ if (f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) {
int err = fscrypt_get_encryption_info(dir);
if (err)
return err;
@@ -929,7 +973,8 @@
f2fs_put_page(old_dir_page, 0);
f2fs_i_links_write(old_dir, false);
}
- add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+ if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
+ add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
f2fs_unlock_op(sbi);
@@ -1079,8 +1124,10 @@
}
f2fs_mark_inode_dirty_sync(new_dir, false);
- add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
- add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+ if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
+ add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
+ add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+ }
f2fs_unlock_op(sbi);
@@ -1132,68 +1179,20 @@
struct inode *inode,
struct delayed_call *done)
{
- struct page *cpage = NULL;
- char *caddr, *paddr = NULL;
- struct fscrypt_str cstr = FSTR_INIT(NULL, 0);
- struct fscrypt_str pstr = FSTR_INIT(NULL, 0);
- struct fscrypt_symlink_data *sd;
- u32 max_size = inode->i_sb->s_blocksize;
- int res;
+ struct page *page;
+ const char *target;
if (!dentry)
return ERR_PTR(-ECHILD);
- res = fscrypt_get_encryption_info(inode);
- if (res)
- return ERR_PTR(res);
+ page = read_mapping_page(inode->i_mapping, 0, NULL);
+ if (IS_ERR(page))
+ return ERR_CAST(page);
- cpage = read_mapping_page(inode->i_mapping, 0, NULL);
- if (IS_ERR(cpage))
- return ERR_CAST(cpage);
- caddr = page_address(cpage);
-
- /* Symlink is encrypted */
- sd = (struct fscrypt_symlink_data *)caddr;
- cstr.name = sd->encrypted_path;
- cstr.len = le16_to_cpu(sd->len);
-
- /* this is broken symlink case */
- if (unlikely(cstr.len == 0)) {
- res = -ENOENT;
- goto errout;
- }
-
- if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) {
- /* Symlink data on the disk is corrupted */
- res = -EIO;
- goto errout;
- }
- res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr);
- if (res)
- goto errout;
-
- res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr);
- if (res)
- goto errout;
-
- /* this is broken symlink case */
- if (unlikely(pstr.name[0] == 0)) {
- res = -ENOENT;
- goto errout;
- }
-
- paddr = pstr.name;
-
- /* Null-terminate the name */
- paddr[pstr.len] = '\0';
-
- put_page(cpage);
- set_delayed_call(done, kfree_link, paddr);
- return paddr;
-errout:
- fscrypt_fname_free_buffer(&pstr);
- put_page(cpage);
- return ERR_PTR(res);
+ target = fscrypt_get_symlink(inode, page_address(page),
+ inode->i_sb->s_blocksize, done);
+ put_page(page);
+ return target;
}
const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 7cded84..ccf410a 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -193,8 +193,8 @@
__free_nat_entry(e);
}
-static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
- struct nat_entry *ne)
+static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i,
+ struct nat_entry *ne)
{
nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
struct nat_entry_set *head;
@@ -209,15 +209,36 @@
head->entry_cnt = 0;
f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head);
}
+ return head;
+}
+
+static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
+ struct nat_entry *ne)
+{
+ struct nat_entry_set *head;
+ bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR;
+
+ if (!new_ne)
+ head = __grab_nat_entry_set(nm_i, ne);
+
+ /*
+ * update entry_cnt in below condition:
+ * 1. update NEW_ADDR to valid block address;
+ * 2. update old block address to new one;
+ */
+ if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) ||
+ !get_nat_flag(ne, IS_DIRTY)))
+ head->entry_cnt++;
+
+ set_nat_flag(ne, IS_PREALLOC, new_ne);
if (get_nat_flag(ne, IS_DIRTY))
goto refresh_list;
nm_i->dirty_nat_cnt++;
- head->entry_cnt++;
set_nat_flag(ne, IS_DIRTY, true);
refresh_list:
- if (nat_get_blkaddr(ne) == NEW_ADDR)
+ if (new_ne)
list_del_init(&ne->list);
else
list_move_tail(&ne->list, &head->entry_list);
@@ -1076,7 +1097,7 @@
f2fs_wait_on_page_writeback(page, NODE, true);
fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
- set_cold_node(dn->inode, page);
+ set_cold_node(page, S_ISDIR(dn->inode->i_mode));
if (!PageUptodate(page))
SetPageUptodate(page);
if (set_page_dirty(page))
@@ -1751,7 +1772,7 @@
if (!PageUptodate(page))
SetPageUptodate(page);
if (!PageDirty(page)) {
- f2fs_set_page_dirty_nobuffers(page);
+ __set_page_dirty_nobuffers(page);
inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES);
SetPagePrivate(page);
f2fs_trace_pid(page);
@@ -2310,6 +2331,7 @@
if (!PageUptodate(ipage))
SetPageUptodate(ipage);
fill_node_footer(ipage, ino, ino, 0, true);
+ set_cold_node(page, false);
src = F2FS_INODE(page);
dst = F2FS_INODE(ipage);
@@ -2599,8 +2621,7 @@
if (!enabled_nat_bits(sbi, NULL))
return 0;
- nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 +
- F2FS_BLKSIZE - 1);
+ nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8);
nm_i->nat_bits = f2fs_kzalloc(sbi,
nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL);
if (!nm_i->nat_bits)
@@ -2726,12 +2747,20 @@
static int init_free_nid_cache(struct f2fs_sb_info *sbi)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
+ int i;
- nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks *
- NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL);
+ nm_i->free_nid_bitmap = f2fs_kzalloc(sbi, nm_i->nat_blocks *
+ sizeof(unsigned char *), GFP_KERNEL);
if (!nm_i->free_nid_bitmap)
return -ENOMEM;
+ for (i = 0; i < nm_i->nat_blocks; i++) {
+ nm_i->free_nid_bitmap[i] = f2fs_kvzalloc(sbi,
+ NAT_ENTRY_BITMAP_SIZE_ALIGNED, GFP_KERNEL);
+ if (!nm_i->free_nid_bitmap)
+ return -ENOMEM;
+ }
+
nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8,
GFP_KERNEL);
if (!nm_i->nat_block_bitmap)
@@ -2822,7 +2851,13 @@
up_write(&nm_i->nat_tree_lock);
kvfree(nm_i->nat_block_bitmap);
- kvfree(nm_i->free_nid_bitmap);
+ if (nm_i->free_nid_bitmap) {
+ int i;
+
+ for (i = 0; i < nm_i->nat_blocks; i++)
+ kvfree(nm_i->free_nid_bitmap[i]);
+ kfree(nm_i->free_nid_bitmap);
+ }
kvfree(nm_i->free_nid_count);
kfree(nm_i->nat_bitmap);
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 081ef0d..b95e49e 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -44,6 +44,7 @@
HAS_FSYNCED_INODE, /* is the inode fsynced before? */
HAS_LAST_FSYNC, /* has the latest node fsync mark? */
IS_DIRTY, /* this nat entry is dirty? */
+ IS_PREALLOC, /* nat entry is preallocated */
};
/*
@@ -422,12 +423,12 @@
ClearPageChecked(page);
}
-static inline void set_cold_node(struct inode *inode, struct page *page)
+static inline void set_cold_node(struct page *page, bool is_dir)
{
struct f2fs_node *rn = F2FS_NODE(page);
unsigned int flag = le32_to_cpu(rn->footer.flag);
- if (S_ISDIR(inode->i_mode))
+ if (is_dir)
flag &= ~(0x1 << COLD_BIT_SHIFT);
else
flag |= (0x1 << COLD_BIT_SHIFT);
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index 210de28..4ddc226 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -242,6 +242,9 @@
struct curseg_info *curseg;
struct page *page = NULL;
block_t blkaddr;
+ unsigned int loop_cnt = 0;
+ unsigned int free_blocks = sbi->user_block_count -
+ valid_user_blocks(sbi);
int err = 0;
/* get node pages in the current segment */
@@ -294,6 +297,17 @@
if (IS_INODE(page) && is_dent_dnode(page))
entry->last_dentry = blkaddr;
next:
+ /* sanity check in order to detect looped node chain */
+ if (++loop_cnt >= free_blocks ||
+ blkaddr == next_blkaddr_of_node(page)) {
+ f2fs_msg(sbi->sb, KERN_NOTICE,
+ "%s: detect looped node chain, "
+ "blkaddr:%u, next:%u",
+ __func__, blkaddr, next_blkaddr_of_node(page));
+ err = -EINVAL;
+ break;
+ }
+
/* check next segment */
blkaddr = next_blkaddr_of_node(page);
f2fs_put_page(page, 1);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index cc34d88..fc4ee38 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -1411,12 +1411,11 @@
if (kthread_should_stop())
return 0;
- if (dcc->discard_wake) {
+ if (dcc->discard_wake)
dcc->discard_wake = 0;
- if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
- init_discard_policy(&dpolicy,
- DPOLICY_FORCE, 1);
- }
+
+ if (sbi->gc_thread && sbi->gc_thread->gc_urgent)
+ init_discard_policy(&dpolicy, DPOLICY_FORCE, 1);
sb_start_intwrite(sbi->sb);
@@ -1485,7 +1484,7 @@
struct block_device *bdev, block_t blkstart, block_t blklen)
{
#ifdef CONFIG_BLK_DEV_ZONED
- if (f2fs_sb_mounted_blkzoned(sbi->sb) &&
+ if (f2fs_sb_has_blkzoned(sbi->sb) &&
bdev_zoned_model(bdev) != BLK_ZONED_NONE)
return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen);
#endif
@@ -1683,7 +1682,7 @@
sbi->blocks_per_seg, cur_pos);
len = next_pos - cur_pos;
- if (f2fs_sb_mounted_blkzoned(sbi->sb) ||
+ if (f2fs_sb_has_blkzoned(sbi->sb) ||
(force && len < cpc->trim_minlen))
goto skip;
@@ -1727,7 +1726,7 @@
} else if (discard_type == DPOLICY_FORCE) {
dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME;
dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME;
- dpolicy->io_aware = true;
+ dpolicy->io_aware = false;
} else if (discard_type == DPOLICY_FSTRIM) {
dpolicy->io_aware = false;
} else if (discard_type == DPOLICY_UMOUNT) {
@@ -1863,7 +1862,7 @@
sbi->discard_blks--;
/* don't overwrite by SSR to keep node chain */
- if (se->type == CURSEG_WARM_NODE) {
+ if (IS_NODESEG(se->type)) {
if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
se->ckpt_valid_blocks++;
}
@@ -2164,11 +2163,17 @@
if (sbi->segs_per_sec != 1)
return CURSEG_I(sbi, type)->segno;
- if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+ if (test_opt(sbi, NOHEAP) &&
+ (type == CURSEG_HOT_DATA || IS_NODESEG(type)))
return 0;
if (SIT_I(sbi)->last_victim[ALLOC_NEXT])
return SIT_I(sbi)->last_victim[ALLOC_NEXT];
+
+ /* find segments from 0 to reuse freed segments */
+ if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
+ return 0;
+
return CURSEG_I(sbi, type)->segno;
}
@@ -2455,6 +2460,101 @@
}
}
+/* This returns write hints for each segment type. This hints will be
+ * passed down to block layer. There are mapping tables which depend on
+ * the mount option 'whint_mode'.
+ *
+ * 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET.
+ *
+ * 2) whint_mode=user-based. F2FS tries to pass down hints given by users.
+ *
+ * User F2FS Block
+ * ---- ---- -----
+ * META WRITE_LIFE_NOT_SET
+ * HOT_NODE "
+ * WARM_NODE "
+ * COLD_NODE "
+ * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
+ * extension list " "
+ *
+ * -- buffered io
+ * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
+ * WRITE_LIFE_NONE " "
+ * WRITE_LIFE_MEDIUM " "
+ * WRITE_LIFE_LONG " "
+ *
+ * -- direct io
+ * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
+ * WRITE_LIFE_NONE " WRITE_LIFE_NONE
+ * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
+ * WRITE_LIFE_LONG " WRITE_LIFE_LONG
+ *
+ * 3) whint_mode=fs-based. F2FS passes down hints with its policy.
+ *
+ * User F2FS Block
+ * ---- ---- -----
+ * META WRITE_LIFE_MEDIUM;
+ * HOT_NODE WRITE_LIFE_NOT_SET
+ * WARM_NODE "
+ * COLD_NODE WRITE_LIFE_NONE
+ * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME
+ * extension list " "
+ *
+ * -- buffered io
+ * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG
+ * WRITE_LIFE_NONE " "
+ * WRITE_LIFE_MEDIUM " "
+ * WRITE_LIFE_LONG " "
+ *
+ * -- direct io
+ * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME
+ * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT
+ * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET
+ * WRITE_LIFE_NONE " WRITE_LIFE_NONE
+ * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM
+ * WRITE_LIFE_LONG " WRITE_LIFE_LONG
+ */
+
+enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi,
+ enum page_type type, enum temp_type temp)
+{
+ if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) {
+ if (type == DATA) {
+ if (temp == WARM)
+ return WRITE_LIFE_NOT_SET;
+ else if (temp == HOT)
+ return WRITE_LIFE_SHORT;
+ else if (temp == COLD)
+ return WRITE_LIFE_EXTREME;
+ } else {
+ return WRITE_LIFE_NOT_SET;
+ }
+ } else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) {
+ if (type == DATA) {
+ if (temp == WARM)
+ return WRITE_LIFE_LONG;
+ else if (temp == HOT)
+ return WRITE_LIFE_SHORT;
+ else if (temp == COLD)
+ return WRITE_LIFE_EXTREME;
+ } else if (type == NODE) {
+ if (temp == WARM || temp == HOT)
+ return WRITE_LIFE_NOT_SET;
+ else if (temp == COLD)
+ return WRITE_LIFE_NONE;
+ } else if (type == META) {
+ return WRITE_LIFE_MEDIUM;
+ }
+ }
+ return WRITE_LIFE_NOT_SET;
+}
+
static int __get_segment_type_2(struct f2fs_io_info *fio)
{
if (fio->type == DATA)
@@ -2487,7 +2587,8 @@
if (is_cold_data(fio->page) || file_is_cold(inode))
return CURSEG_COLD_DATA;
- if (is_inode_flag_set(inode, FI_HOT_DATA))
+ if (file_is_hot(inode) ||
+ is_inode_flag_set(inode, FI_HOT_DATA))
return CURSEG_HOT_DATA;
/* rw_hint_to_seg_type(inode->i_write_hint); */
return CURSEG_WARM_DATA;
@@ -2503,7 +2604,7 @@
{
int type = 0;
- switch (fio->sbi->active_logs) {
+ switch (F2FS_OPTION(fio->sbi).active_logs) {
case 2:
type = __get_segment_type_2(fio);
break;
@@ -2643,6 +2744,7 @@
struct f2fs_io_info fio = {
.sbi = sbi,
.type = META,
+ .temp = HOT,
.op = REQ_OP_WRITE,
.op_flags = REQ_SYNC | REQ_META | REQ_PRIO,
.old_blkaddr = page->index,
@@ -2689,8 +2791,15 @@
int rewrite_data_page(struct f2fs_io_info *fio)
{
int err;
+ struct f2fs_sb_info *sbi = fio->sbi;
fio->new_blkaddr = fio->old_blkaddr;
+ /* i/o temperature is needed for passing down write hints */
+ __get_segment_type(fio);
+
+ f2fs_bug_on(sbi, !IS_DATASEG(get_seg_entry(sbi,
+ GET_SEGNO(sbi, fio->new_blkaddr))->type));
+
stat_inc_inplace_blocks(fio->sbi);
err = f2fs_submit_page_bio(fio);
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index f11c4bc..3325d07 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -53,13 +53,19 @@
((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \
(sbi)->segs_per_sec)) \
-#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr)
-#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr)
+#define MAIN_BLKADDR(sbi) \
+ (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \
+ le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr))
+#define SEG0_BLKADDR(sbi) \
+ (SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : \
+ le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr))
#define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments)
#define MAIN_SECS(sbi) ((sbi)->total_sections)
-#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count)
+#define TOTAL_SEGS(sbi) \
+ (SM_I(sbi) ? SM_I(sbi)->segment_count : \
+ le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count))
#define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg)
#define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi))
@@ -596,6 +602,8 @@
#define DEF_MIN_FSYNC_BLOCKS 8
#define DEF_MIN_HOT_BLOCKS 16
+#define SMALL_VOLUME_SEGMENTS (16 * 512) /* 16GB */
+
enum {
F2FS_IPU_FORCE,
F2FS_IPU_SSR,
@@ -630,10 +638,17 @@
f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
}
-static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr)
+static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
{
- BUG_ON(blk_addr < SEG0_BLKADDR(sbi)
- || blk_addr >= MAX_BLKADDR(sbi));
+ struct f2fs_sb_info *sbi = fio->sbi;
+
+ if (PAGE_TYPE_OF_BIO(fio->type) == META &&
+ (!is_read_io(fio->op) || fio->is_meta))
+ BUG_ON(blk_addr < SEG0_BLKADDR(sbi) ||
+ blk_addr >= MAIN_BLKADDR(sbi));
+ else
+ BUG_ON(blk_addr < MAIN_BLKADDR(sbi) ||
+ blk_addr >= MAX_BLKADDR(sbi));
}
/*
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 78b763c..7d4621a 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -60,7 +60,7 @@
static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
unsigned int rate)
{
- struct f2fs_fault_info *ffi = &sbi->fault_info;
+ struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info;
if (rate) {
atomic_set(&ffi->inject_ops, 0);
@@ -129,6 +129,10 @@
Opt_jqfmt_vfsold,
Opt_jqfmt_vfsv0,
Opt_jqfmt_vfsv1,
+ Opt_whint,
+ Opt_alloc,
+ Opt_fsync,
+ Opt_test_dummy_encryption,
Opt_err,
};
@@ -182,6 +186,10 @@
{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
{Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
+ {Opt_whint, "whint_mode=%s"},
+ {Opt_alloc, "alloc_mode=%s"},
+ {Opt_fsync, "fsync_mode=%s"},
+ {Opt_test_dummy_encryption, "test_dummy_encryption"},
{Opt_err, NULL},
};
@@ -202,21 +210,24 @@
block_t limit = (sbi->user_block_count << 1) / 1000;
/* limit is 0.2% */
- if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) {
- sbi->root_reserved_blocks = limit;
+ if (test_opt(sbi, RESERVE_ROOT) &&
+ F2FS_OPTION(sbi).root_reserved_blocks > limit) {
+ F2FS_OPTION(sbi).root_reserved_blocks = limit;
f2fs_msg(sbi->sb, KERN_INFO,
"Reduce reserved blocks for root = %u",
- sbi->root_reserved_blocks);
+ F2FS_OPTION(sbi).root_reserved_blocks);
}
if (!test_opt(sbi, RESERVE_ROOT) &&
- (!uid_eq(sbi->s_resuid,
+ (!uid_eq(F2FS_OPTION(sbi).s_resuid,
make_kuid(&init_user_ns, F2FS_DEF_RESUID)) ||
- !gid_eq(sbi->s_resgid,
+ !gid_eq(F2FS_OPTION(sbi).s_resgid,
make_kgid(&init_user_ns, F2FS_DEF_RESGID))))
f2fs_msg(sbi->sb, KERN_INFO,
"Ignore s_resuid=%u, s_resgid=%u w/o reserve_root",
- from_kuid_munged(&init_user_ns, sbi->s_resuid),
- from_kgid_munged(&init_user_ns, sbi->s_resgid));
+ from_kuid_munged(&init_user_ns,
+ F2FS_OPTION(sbi).s_resuid),
+ from_kgid_munged(&init_user_ns,
+ F2FS_OPTION(sbi).s_resgid));
}
static void init_once(void *foo)
@@ -236,7 +247,7 @@
char *qname;
int ret = -EINVAL;
- if (sb_any_quota_loaded(sb) && !sbi->s_qf_names[qtype]) {
+ if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) {
f2fs_msg(sb, KERN_ERR,
"Cannot change journaled "
"quota options when quota turned on");
@@ -254,8 +265,8 @@
"Not enough memory for storing quotafile name");
return -EINVAL;
}
- if (sbi->s_qf_names[qtype]) {
- if (strcmp(sbi->s_qf_names[qtype], qname) == 0)
+ if (F2FS_OPTION(sbi).s_qf_names[qtype]) {
+ if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0)
ret = 0;
else
f2fs_msg(sb, KERN_ERR,
@@ -268,7 +279,7 @@
"quotafile must be on filesystem root");
goto errout;
}
- sbi->s_qf_names[qtype] = qname;
+ F2FS_OPTION(sbi).s_qf_names[qtype] = qname;
set_opt(sbi, QUOTA);
return 0;
errout:
@@ -280,13 +291,13 @@
{
struct f2fs_sb_info *sbi = F2FS_SB(sb);
- if (sb_any_quota_loaded(sb) && sbi->s_qf_names[qtype]) {
+ if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) {
f2fs_msg(sb, KERN_ERR, "Cannot change journaled quota options"
" when quota turned on");
return -EINVAL;
}
- kfree(sbi->s_qf_names[qtype]);
- sbi->s_qf_names[qtype] = NULL;
+ kfree(F2FS_OPTION(sbi).s_qf_names[qtype]);
+ F2FS_OPTION(sbi).s_qf_names[qtype] = NULL;
return 0;
}
@@ -302,15 +313,19 @@
"Cannot enable project quota enforcement.");
return -1;
}
- if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] ||
- sbi->s_qf_names[PRJQUOTA]) {
- if (test_opt(sbi, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
+ if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] ||
+ F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] ||
+ F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) {
+ if (test_opt(sbi, USRQUOTA) &&
+ F2FS_OPTION(sbi).s_qf_names[USRQUOTA])
clear_opt(sbi, USRQUOTA);
- if (test_opt(sbi, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
+ if (test_opt(sbi, GRPQUOTA) &&
+ F2FS_OPTION(sbi).s_qf_names[GRPQUOTA])
clear_opt(sbi, GRPQUOTA);
- if (test_opt(sbi, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA])
+ if (test_opt(sbi, PRJQUOTA) &&
+ F2FS_OPTION(sbi).s_qf_names[PRJQUOTA])
clear_opt(sbi, PRJQUOTA);
if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) ||
@@ -320,19 +335,19 @@
return -1;
}
- if (!sbi->s_jquota_fmt) {
+ if (!F2FS_OPTION(sbi).s_jquota_fmt) {
f2fs_msg(sbi->sb, KERN_ERR, "journaled quota format "
"not specified");
return -1;
}
}
- if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) {
+ if (f2fs_sb_has_quota_ino(sbi->sb) && F2FS_OPTION(sbi).s_jquota_fmt) {
f2fs_msg(sbi->sb, KERN_INFO,
"QUOTA feature is enabled, so ignore jquota_fmt");
- sbi->s_jquota_fmt = 0;
+ F2FS_OPTION(sbi).s_jquota_fmt = 0;
}
- if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) {
+ if (f2fs_sb_has_quota_ino(sbi->sb) && f2fs_readonly(sbi->sb)) {
f2fs_msg(sbi->sb, KERN_INFO,
"Filesystem with quota feature cannot be mounted RDWR "
"without CONFIG_QUOTA");
@@ -403,14 +418,14 @@
q = bdev_get_queue(sb->s_bdev);
if (blk_queue_discard(q)) {
set_opt(sbi, DISCARD);
- } else if (!f2fs_sb_mounted_blkzoned(sb)) {
+ } else if (!f2fs_sb_has_blkzoned(sb)) {
f2fs_msg(sb, KERN_WARNING,
"mounting with \"discard\" option, but "
"the device does not support discard");
}
break;
case Opt_nodiscard:
- if (f2fs_sb_mounted_blkzoned(sb)) {
+ if (f2fs_sb_has_blkzoned(sb)) {
f2fs_msg(sb, KERN_WARNING,
"discard is required for zoned block devices");
return -EINVAL;
@@ -440,7 +455,7 @@
if (args->from && match_int(args, &arg))
return -EINVAL;
set_opt(sbi, INLINE_XATTR_SIZE);
- sbi->inline_xattr_size = arg;
+ F2FS_OPTION(sbi).inline_xattr_size = arg;
break;
#else
case Opt_user_xattr:
@@ -480,7 +495,7 @@
return -EINVAL;
if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE)
return -EINVAL;
- sbi->active_logs = arg;
+ F2FS_OPTION(sbi).active_logs = arg;
break;
case Opt_disable_ext_identify:
set_opt(sbi, DISABLE_EXT_IDENTIFY);
@@ -524,9 +539,9 @@
if (test_opt(sbi, RESERVE_ROOT)) {
f2fs_msg(sb, KERN_INFO,
"Preserve previous reserve_root=%u",
- sbi->root_reserved_blocks);
+ F2FS_OPTION(sbi).root_reserved_blocks);
} else {
- sbi->root_reserved_blocks = arg;
+ F2FS_OPTION(sbi).root_reserved_blocks = arg;
set_opt(sbi, RESERVE_ROOT);
}
break;
@@ -539,7 +554,7 @@
"Invalid uid value %d", arg);
return -EINVAL;
}
- sbi->s_resuid = uid;
+ F2FS_OPTION(sbi).s_resuid = uid;
break;
case Opt_resgid:
if (args->from && match_int(args, &arg))
@@ -550,7 +565,7 @@
"Invalid gid value %d", arg);
return -EINVAL;
}
- sbi->s_resgid = gid;
+ F2FS_OPTION(sbi).s_resgid = gid;
break;
case Opt_mode:
name = match_strdup(&args[0]);
@@ -559,7 +574,7 @@
return -ENOMEM;
if (strlen(name) == 8 &&
!strncmp(name, "adaptive", 8)) {
- if (f2fs_sb_mounted_blkzoned(sb)) {
+ if (f2fs_sb_has_blkzoned(sb)) {
f2fs_msg(sb, KERN_WARNING,
"adaptive mode is not allowed with "
"zoned block device feature");
@@ -585,7 +600,7 @@
1 << arg, BIO_MAX_PAGES);
return -EINVAL;
}
- sbi->write_io_size_bits = arg;
+ F2FS_OPTION(sbi).write_io_size_bits = arg;
break;
case Opt_fault_injection:
if (args->from && match_int(args, &arg))
@@ -646,13 +661,13 @@
return ret;
break;
case Opt_jqfmt_vfsold:
- sbi->s_jquota_fmt = QFMT_VFS_OLD;
+ F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD;
break;
case Opt_jqfmt_vfsv0:
- sbi->s_jquota_fmt = QFMT_VFS_V0;
+ F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0;
break;
case Opt_jqfmt_vfsv1:
- sbi->s_jquota_fmt = QFMT_VFS_V1;
+ F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1;
break;
case Opt_noquota:
clear_opt(sbi, QUOTA);
@@ -679,6 +694,73 @@
"quota operations not supported");
break;
#endif
+ case Opt_whint:
+ name = match_strdup(&args[0]);
+ if (!name)
+ return -ENOMEM;
+ if (strlen(name) == 10 &&
+ !strncmp(name, "user-based", 10)) {
+ F2FS_OPTION(sbi).whint_mode = WHINT_MODE_USER;
+ } else if (strlen(name) == 3 &&
+ !strncmp(name, "off", 3)) {
+ F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
+ } else if (strlen(name) == 8 &&
+ !strncmp(name, "fs-based", 8)) {
+ F2FS_OPTION(sbi).whint_mode = WHINT_MODE_FS;
+ } else {
+ kfree(name);
+ return -EINVAL;
+ }
+ kfree(name);
+ break;
+ case Opt_alloc:
+ name = match_strdup(&args[0]);
+ if (!name)
+ return -ENOMEM;
+
+ if (strlen(name) == 7 &&
+ !strncmp(name, "default", 7)) {
+ F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
+ } else if (strlen(name) == 5 &&
+ !strncmp(name, "reuse", 5)) {
+ F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
+ } else {
+ kfree(name);
+ return -EINVAL;
+ }
+ kfree(name);
+ break;
+ case Opt_fsync:
+ name = match_strdup(&args[0]);
+ if (!name)
+ return -ENOMEM;
+ if (strlen(name) == 5 &&
+ !strncmp(name, "posix", 5)) {
+ F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
+ } else if (strlen(name) == 6 &&
+ !strncmp(name, "strict", 6)) {
+ F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT;
+ } else {
+ kfree(name);
+ return -EINVAL;
+ }
+ kfree(name);
+ break;
+ case Opt_test_dummy_encryption:
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+ if (!f2fs_sb_has_encrypt(sb)) {
+ f2fs_msg(sb, KERN_ERR, "Encrypt feature is off");
+ return -EINVAL;
+ }
+
+ F2FS_OPTION(sbi).test_dummy_encryption = true;
+ f2fs_msg(sb, KERN_INFO,
+ "Test dummy encryption mode enabled");
+#else
+ f2fs_msg(sb, KERN_INFO,
+ "Test dummy encryption mount option ignored");
+#endif
+ break;
default:
f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing value",
@@ -699,14 +781,22 @@
}
if (test_opt(sbi, INLINE_XATTR_SIZE)) {
+ if (!f2fs_sb_has_extra_attr(sb) ||
+ !f2fs_sb_has_flexible_inline_xattr(sb)) {
+ f2fs_msg(sb, KERN_ERR,
+ "extra_attr or flexible_inline_xattr "
+ "feature is off");
+ return -EINVAL;
+ }
if (!test_opt(sbi, INLINE_XATTR)) {
f2fs_msg(sb, KERN_ERR,
"inline_xattr_size option should be "
"set with inline_xattr option");
return -EINVAL;
}
- if (!sbi->inline_xattr_size ||
- sbi->inline_xattr_size >= DEF_ADDRS_PER_INODE -
+ if (!F2FS_OPTION(sbi).inline_xattr_size ||
+ F2FS_OPTION(sbi).inline_xattr_size >=
+ DEF_ADDRS_PER_INODE -
F2FS_TOTAL_EXTRA_ATTR_SIZE -
DEF_INLINE_RESERVED_SIZE -
DEF_MIN_INLINE_SIZE) {
@@ -715,6 +805,12 @@
return -EINVAL;
}
}
+
+ /* Not pass down write hints if the number of active logs is lesser
+ * than NR_CURSEG_TYPE.
+ */
+ if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE)
+ F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
return 0;
}
@@ -731,7 +827,6 @@
/* Initialize f2fs-specific inode info */
atomic_set(&fi->dirty_pages, 0);
fi->i_current_depth = 1;
- fi->i_advise = 0;
init_rwsem(&fi->i_sem);
INIT_LIST_HEAD(&fi->dirty_list);
INIT_LIST_HEAD(&fi->gdirty_list);
@@ -743,10 +838,6 @@
init_rwsem(&fi->i_mmap_sem);
init_rwsem(&fi->i_xattr_sem);
-#ifdef CONFIG_QUOTA
- memset(&fi->i_dquot, 0, sizeof(fi->i_dquot));
- fi->i_reserved_quota = 0;
-#endif
/* Will be used by directory only */
fi->i_dir_level = F2FS_SB(sb)->dir_level;
@@ -956,7 +1047,7 @@
mempool_destroy(sbi->write_io_dummy);
#ifdef CONFIG_QUOTA
for (i = 0; i < MAXQUOTAS; i++)
- kfree(sbi->s_qf_names[i]);
+ kfree(F2FS_OPTION(sbi).s_qf_names[i]);
#endif
destroy_percpu_info(sbi);
for (i = 0; i < NR_PAGE_TYPE; i++)
@@ -1070,8 +1161,9 @@
buf->f_blocks = total_count - start_count;
buf->f_bfree = user_block_count - valid_user_blocks(sbi) -
sbi->current_reserved_blocks;
- if (buf->f_bfree > sbi->root_reserved_blocks)
- buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks;
+ if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks)
+ buf->f_bavail = buf->f_bfree -
+ F2FS_OPTION(sbi).root_reserved_blocks;
else
buf->f_bavail = 0;
@@ -1106,10 +1198,10 @@
#ifdef CONFIG_QUOTA
struct f2fs_sb_info *sbi = F2FS_SB(sb);
- if (sbi->s_jquota_fmt) {
+ if (F2FS_OPTION(sbi).s_jquota_fmt) {
char *fmtname = "";
- switch (sbi->s_jquota_fmt) {
+ switch (F2FS_OPTION(sbi).s_jquota_fmt) {
case QFMT_VFS_OLD:
fmtname = "vfsold";
break;
@@ -1123,14 +1215,17 @@
seq_printf(seq, ",jqfmt=%s", fmtname);
}
- if (sbi->s_qf_names[USRQUOTA])
- seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]);
+ if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA])
+ seq_show_option(seq, "usrjquota",
+ F2FS_OPTION(sbi).s_qf_names[USRQUOTA]);
- if (sbi->s_qf_names[GRPQUOTA])
- seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]);
+ if (F2FS_OPTION(sbi).s_qf_names[GRPQUOTA])
+ seq_show_option(seq, "grpjquota",
+ F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]);
- if (sbi->s_qf_names[PRJQUOTA])
- seq_show_option(seq, "prjjquota", sbi->s_qf_names[PRJQUOTA]);
+ if (F2FS_OPTION(sbi).s_qf_names[PRJQUOTA])
+ seq_show_option(seq, "prjjquota",
+ F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]);
#endif
}
@@ -1165,7 +1260,7 @@
seq_puts(seq, ",noinline_xattr");
if (test_opt(sbi, INLINE_XATTR_SIZE))
seq_printf(seq, ",inline_xattr_size=%u",
- sbi->inline_xattr_size);
+ F2FS_OPTION(sbi).inline_xattr_size);
#endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL
if (test_opt(sbi, POSIX_ACL))
@@ -1201,18 +1296,20 @@
seq_puts(seq, "adaptive");
else if (test_opt(sbi, LFS))
seq_puts(seq, "lfs");
- seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+ seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs);
if (test_opt(sbi, RESERVE_ROOT))
seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u",
- sbi->root_reserved_blocks,
- from_kuid_munged(&init_user_ns, sbi->s_resuid),
- from_kgid_munged(&init_user_ns, sbi->s_resgid));
+ F2FS_OPTION(sbi).root_reserved_blocks,
+ from_kuid_munged(&init_user_ns,
+ F2FS_OPTION(sbi).s_resuid),
+ from_kgid_munged(&init_user_ns,
+ F2FS_OPTION(sbi).s_resgid));
if (F2FS_IO_SIZE_BITS(sbi))
seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
#ifdef CONFIG_F2FS_FAULT_INJECTION
if (test_opt(sbi, FAULT_INJECTION))
seq_printf(seq, ",fault_injection=%u",
- sbi->fault_info.inject_rate);
+ F2FS_OPTION(sbi).fault_info.inject_rate);
#endif
#ifdef CONFIG_QUOTA
if (test_opt(sbi, QUOTA))
@@ -1225,15 +1322,37 @@
seq_puts(seq, ",prjquota");
#endif
f2fs_show_quota_options(seq, sbi->sb);
+ if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER)
+ seq_printf(seq, ",whint_mode=%s", "user-based");
+ else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS)
+ seq_printf(seq, ",whint_mode=%s", "fs-based");
+#ifdef CONFIG_F2FS_FS_ENCRYPTION
+ if (F2FS_OPTION(sbi).test_dummy_encryption)
+ seq_puts(seq, ",test_dummy_encryption");
+#endif
+ if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT)
+ seq_printf(seq, ",alloc_mode=%s", "default");
+ else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE)
+ seq_printf(seq, ",alloc_mode=%s", "reuse");
+
+ if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX)
+ seq_printf(seq, ",fsync_mode=%s", "posix");
+ else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT)
+ seq_printf(seq, ",fsync_mode=%s", "strict");
return 0;
}
static void default_options(struct f2fs_sb_info *sbi)
{
/* init some FS parameters */
- sbi->active_logs = NR_CURSEG_TYPE;
- sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
+ F2FS_OPTION(sbi).active_logs = NR_CURSEG_TYPE;
+ F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
+ F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
+ F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
+ F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX;
+ F2FS_OPTION(sbi).test_dummy_encryption = false;
+ sbi->readdir_ra = 1;
set_opt(sbi, BG_GC);
set_opt(sbi, INLINE_XATTR);
@@ -1243,7 +1362,7 @@
set_opt(sbi, NOHEAP);
sbi->sb->s_flags |= MS_LAZYTIME;
set_opt(sbi, FLUSH_MERGE);
- if (f2fs_sb_mounted_blkzoned(sbi->sb)) {
+ if (f2fs_sb_has_blkzoned(sbi->sb)) {
set_opt_mode(sbi, F2FS_MOUNT_LFS);
set_opt(sbi, DISCARD);
} else {
@@ -1270,16 +1389,11 @@
struct f2fs_sb_info *sbi = F2FS_SB(sb);
struct f2fs_mount_info org_mount_opt;
unsigned long old_sb_flags;
- int err, active_logs;
+ int err;
bool need_restart_gc = false;
bool need_stop_gc = false;
bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE);
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- struct f2fs_fault_info ffi = sbi->fault_info;
-#endif
#ifdef CONFIG_QUOTA
- int s_jquota_fmt;
- char *s_qf_names[MAXQUOTAS];
int i, j;
#endif
@@ -1289,21 +1403,21 @@
*/
org_mount_opt = sbi->mount_opt;
old_sb_flags = sb->s_flags;
- active_logs = sbi->active_logs;
#ifdef CONFIG_QUOTA
- s_jquota_fmt = sbi->s_jquota_fmt;
+ org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++) {
- if (sbi->s_qf_names[i]) {
- s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
- GFP_KERNEL);
- if (!s_qf_names[i]) {
+ if (F2FS_OPTION(sbi).s_qf_names[i]) {
+ org_mount_opt.s_qf_names[i] =
+ kstrdup(F2FS_OPTION(sbi).s_qf_names[i],
+ GFP_KERNEL);
+ if (!org_mount_opt.s_qf_names[i]) {
for (j = 0; j < i; j++)
- kfree(s_qf_names[j]);
+ kfree(org_mount_opt.s_qf_names[j]);
return -ENOMEM;
}
} else {
- s_qf_names[i] = NULL;
+ org_mount_opt.s_qf_names[i] = NULL;
}
}
#endif
@@ -1373,7 +1487,8 @@
need_stop_gc = true;
}
- if (*flags & MS_RDONLY) {
+ if (*flags & MS_RDONLY ||
+ F2FS_OPTION(sbi).whint_mode != org_mount_opt.whint_mode) {
writeback_inodes_sb(sb, WB_REASON_SYNC);
sync_inodes_sb(sb);
@@ -1399,7 +1514,7 @@
#ifdef CONFIG_QUOTA
/* Release old quota file names */
for (i = 0; i < MAXQUOTAS; i++)
- kfree(s_qf_names[i]);
+ kfree(org_mount_opt.s_qf_names[i]);
#endif
/* Update the POSIXACL Flag */
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
@@ -1417,18 +1532,14 @@
}
restore_opts:
#ifdef CONFIG_QUOTA
- sbi->s_jquota_fmt = s_jquota_fmt;
+ F2FS_OPTION(sbi).s_jquota_fmt = org_mount_opt.s_jquota_fmt;
for (i = 0; i < MAXQUOTAS; i++) {
- kfree(sbi->s_qf_names[i]);
- sbi->s_qf_names[i] = s_qf_names[i];
+ kfree(F2FS_OPTION(sbi).s_qf_names[i]);
+ F2FS_OPTION(sbi).s_qf_names[i] = org_mount_opt.s_qf_names[i];
}
#endif
sbi->mount_opt = org_mount_opt;
- sbi->active_logs = active_logs;
sb->s_flags = old_sb_flags;
-#ifdef CONFIG_F2FS_FAULT_INJECTION
- sbi->fault_info = ffi;
-#endif
return err;
}
@@ -1550,8 +1661,8 @@
static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type)
{
- return dquot_quota_on_mount(sbi->sb, sbi->s_qf_names[type],
- sbi->s_jquota_fmt, type);
+ return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type],
+ F2FS_OPTION(sbi).s_jquota_fmt, type);
}
int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly)
@@ -1570,7 +1681,7 @@
}
for (i = 0; i < MAXQUOTAS; i++) {
- if (sbi->s_qf_names[i]) {
+ if (F2FS_OPTION(sbi).s_qf_names[i]) {
err = f2fs_quota_on_mount(sbi, i);
if (!err) {
enabled = 1;
@@ -1797,11 +1908,28 @@
static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len,
void *fs_data)
{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+ /*
+ * Encrypting the root directory is not allowed because fsck
+ * expects lost+found directory to exist and remain unencrypted
+ * if LOST_FOUND feature is enabled.
+ *
+ */
+ if (f2fs_sb_has_lost_found(sbi->sb) &&
+ inode->i_ino == F2FS_ROOT_INO(sbi))
+ return -EPERM;
+
return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION,
F2FS_XATTR_NAME_ENCRYPTION_CONTEXT,
ctx, len, fs_data, XATTR_CREATE);
}
+static bool f2fs_dummy_context(struct inode *inode)
+{
+ return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode));
+}
+
static unsigned f2fs_max_namelen(struct inode *inode)
{
return S_ISLNK(inode->i_mode) ?
@@ -1812,6 +1940,7 @@
.key_prefix = "f2fs:",
.get_context = f2fs_get_context,
.set_context = f2fs_set_context,
+ .dummy_context = f2fs_dummy_context,
.empty_dir = f2fs_empty_dir,
.max_namelen = f2fs_max_namelen,
};
@@ -1894,7 +2023,6 @@
lock_buffer(bh);
if (super)
memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
- set_buffer_uptodate(bh);
set_buffer_dirty(bh);
unlock_buffer(bh);
@@ -2181,6 +2309,8 @@
sbi->dirty_device = 0;
spin_lock_init(&sbi->dev_lock);
+
+ init_rwsem(&sbi->sb_lock);
}
static int init_percpu_info(struct f2fs_sb_info *sbi)
@@ -2206,7 +2336,7 @@
unsigned int n = 0;
int err = -EIO;
- if (!f2fs_sb_mounted_blkzoned(sbi->sb))
+ if (!f2fs_sb_has_blkzoned(sbi->sb))
return 0;
if (sbi->blocks_per_blkz && sbi->blocks_per_blkz !=
@@ -2334,7 +2464,7 @@
}
/* write back-up superblock first */
- bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1);
+ bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1);
if (!bh)
return -EIO;
err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
@@ -2345,7 +2475,7 @@
return err;
/* write current valid superblock */
- bh = sb_getblk(sbi->sb, sbi->valid_super_block);
+ bh = sb_bread(sbi->sb, sbi->valid_super_block);
if (!bh)
return -EIO;
err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi));
@@ -2417,7 +2547,7 @@
#ifdef CONFIG_BLK_DEV_ZONED
if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
- !f2fs_sb_mounted_blkzoned(sbi->sb)) {
+ !f2fs_sb_has_blkzoned(sbi->sb)) {
f2fs_msg(sbi->sb, KERN_ERR,
"Zoned block device feature not enabled\n");
return -EINVAL;
@@ -2451,6 +2581,18 @@
return 0;
}
+static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi)
+{
+ struct f2fs_sm_info *sm_i = SM_I(sbi);
+
+ /* adjust parameters according to the volume size */
+ if (sm_i->main_segments <= SMALL_VOLUME_SEGMENTS) {
+ F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE;
+ sm_i->dcc_info->discard_granularity = 1;
+ sm_i->ipu_policy = 1 << F2FS_IPU_FORCE;
+ }
+}
+
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
{
struct f2fs_sb_info *sbi;
@@ -2498,8 +2640,8 @@
sb->s_fs_info = sbi;
sbi->raw_super = raw_super;
- sbi->s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
- sbi->s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
+ F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID);
+ F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID);
/* precompute checksum seed for metadata */
if (f2fs_sb_has_inode_chksum(sb))
@@ -2512,7 +2654,7 @@
* devices, but mandatory for host-managed zoned block devices.
*/
#ifndef CONFIG_BLK_DEV_ZONED
- if (f2fs_sb_mounted_blkzoned(sb)) {
+ if (f2fs_sb_has_blkzoned(sb)) {
f2fs_msg(sb, KERN_ERR,
"Zoned block device support is not enabled\n");
err = -EOPNOTSUPP;
@@ -2728,7 +2870,7 @@
* Turn on quotas which were not enabled for read-only mounts if
* filesystem has quota feature, so that they are updated correctly.
*/
- if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) {
+ if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) {
err = f2fs_enable_quotas(sb);
if (err) {
f2fs_msg(sb, KERN_ERR,
@@ -2803,6 +2945,8 @@
f2fs_join_shrinker(sbi);
+ f2fs_tuning_parameters(sbi);
+
f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
cur_cp_version(F2FS_CKPT(sbi)));
f2fs_update_time(sbi, CP_TIME);
@@ -2811,7 +2955,7 @@
free_meta:
#ifdef CONFIG_QUOTA
- if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb))
+ if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb))
f2fs_quota_off_umount(sbi->sb);
#endif
f2fs_sync_inode_meta(sbi);
@@ -2855,7 +2999,7 @@
free_options:
#ifdef CONFIG_QUOTA
for (i = 0; i < MAXQUOTAS; i++)
- kfree(sbi->s_qf_names[i]);
+ kfree(F2FS_OPTION(sbi).s_qf_names[i]);
#endif
kfree(options);
free_sb_buf:
@@ -2952,8 +3096,13 @@
err = f2fs_create_root_stats();
if (err)
goto free_filesystem;
+ err = f2fs_init_post_read_processing();
+ if (err)
+ goto free_root_stats;
return 0;
+free_root_stats:
+ f2fs_destroy_root_stats();
free_filesystem:
unregister_filesystem(&f2fs_fs_type);
free_shrinker:
@@ -2976,6 +3125,7 @@
static void __exit exit_f2fs_fs(void)
{
+ f2fs_destroy_post_read_processing();
f2fs_destroy_root_stats();
unregister_filesystem(&f2fs_fs_type);
unregister_shrinker(&f2fs_shrinker_info);
diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c
index d978c7b..f33a56d 100644
--- a/fs/f2fs/sysfs.c
+++ b/fs/f2fs/sysfs.c
@@ -58,7 +58,7 @@
#ifdef CONFIG_F2FS_FAULT_INJECTION
else if (struct_type == FAULT_INFO_RATE ||
struct_type == FAULT_INFO_TYPE)
- return (unsigned char *)&sbi->fault_info;
+ return (unsigned char *)&F2FS_OPTION(sbi).fault_info;
#endif
return NULL;
}
@@ -92,10 +92,10 @@
if (!sb->s_bdev->bd_part)
return snprintf(buf, PAGE_SIZE, "0\n");
- if (f2fs_sb_has_crypto(sb))
+ if (f2fs_sb_has_encrypt(sb))
len += snprintf(buf, PAGE_SIZE - len, "%s",
"encryption");
- if (f2fs_sb_mounted_blkzoned(sb))
+ if (f2fs_sb_has_blkzoned(sb))
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
len ? ", " : "", "blkzoned");
if (f2fs_sb_has_extra_attr(sb))
@@ -116,6 +116,9 @@
if (f2fs_sb_has_inode_crtime(sb))
len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
len ? ", " : "", "inode_crtime");
+ if (f2fs_sb_has_lost_found(sb))
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s%s",
+ len ? ", " : "", "lost_found");
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return len;
}
@@ -136,6 +139,27 @@
if (!ptr)
return -EINVAL;
+ if (!strcmp(a->attr.name, "extension_list")) {
+ __u8 (*extlist)[F2FS_EXTENSION_LEN] =
+ sbi->raw_super->extension_list;
+ int cold_count = le32_to_cpu(sbi->raw_super->extension_count);
+ int hot_count = sbi->raw_super->hot_ext_count;
+ int len = 0, i;
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "cold file extenstion:\n");
+ for (i = 0; i < cold_count; i++)
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+ extlist[i]);
+
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "hot file extenstion:\n");
+ for (i = cold_count; i < cold_count + hot_count; i++)
+ len += snprintf(buf + len, PAGE_SIZE - len, "%s\n",
+ extlist[i]);
+ return len;
+ }
+
ui = (unsigned int *)(ptr + a->offset);
return snprintf(buf, PAGE_SIZE, "%u\n", *ui);
@@ -154,6 +178,41 @@
if (!ptr)
return -EINVAL;
+ if (!strcmp(a->attr.name, "extension_list")) {
+ const char *name = strim((char *)buf);
+ bool set = true, hot;
+
+ if (!strncmp(name, "[h]", 3))
+ hot = true;
+ else if (!strncmp(name, "[c]", 3))
+ hot = false;
+ else
+ return -EINVAL;
+
+ name += 3;
+
+ if (*name == '!') {
+ name++;
+ set = false;
+ }
+
+ if (strlen(name) >= F2FS_EXTENSION_LEN)
+ return -EINVAL;
+
+ down_write(&sbi->sb_lock);
+
+ ret = update_extension_list(sbi, name, hot, set);
+ if (ret)
+ goto out;
+
+ ret = f2fs_commit_super(sbi, false);
+ if (ret)
+ update_extension_list(sbi, name, hot, !set);
+out:
+ up_write(&sbi->sb_lock);
+ return ret ? ret : count;
+ }
+
ui = (unsigned int *)(ptr + a->offset);
ret = kstrtoul(skip_spaces(buf), 0, &t);
@@ -166,7 +225,7 @@
if (a->struct_type == RESERVED_BLOCKS) {
spin_lock(&sbi->stat_lock);
if (t > (unsigned long)(sbi->user_block_count -
- sbi->root_reserved_blocks)) {
+ F2FS_OPTION(sbi).root_reserved_blocks)) {
spin_unlock(&sbi->stat_lock);
return -EINVAL;
}
@@ -236,6 +295,7 @@
FEAT_FLEXIBLE_INLINE_XATTR,
FEAT_QUOTA_INO,
FEAT_INODE_CRTIME,
+ FEAT_LOST_FOUND,
};
static ssize_t f2fs_feature_show(struct f2fs_attr *a,
@@ -251,6 +311,7 @@
case FEAT_FLEXIBLE_INLINE_XATTR:
case FEAT_QUOTA_INO:
case FEAT_INODE_CRTIME:
+ case FEAT_LOST_FOUND:
return snprintf(buf, PAGE_SIZE, "supported\n");
}
return 0;
@@ -307,6 +368,7 @@
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra);
F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list);
#ifdef CONFIG_F2FS_FAULT_INJECTION
F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate);
F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type);
@@ -329,6 +391,7 @@
F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR);
F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO);
F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME);
+F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND);
#define ATTR_LIST(name) (&f2fs_attr_##name.attr)
static struct attribute *f2fs_attrs[] = {
@@ -357,6 +420,7 @@
ATTR_LIST(iostat_enable),
ATTR_LIST(readdir_ra),
ATTR_LIST(gc_pin_file_thresh),
+ ATTR_LIST(extension_list),
#ifdef CONFIG_F2FS_FAULT_INJECTION
ATTR_LIST(inject_rate),
ATTR_LIST(inject_type),
@@ -383,6 +447,7 @@
ATTR_LIST(flexible_inline_xattr),
ATTR_LIST(quota_ino),
ATTR_LIST(inode_crtime),
+ ATTR_LIST(lost_found),
NULL,
};
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index ad2e55d..5af226f 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -745,11 +745,12 @@
*/
if (inode && inode_to_wb_is_valid(inode)) {
struct bdi_writeback *wb;
- bool locked, congested;
+ struct wb_lock_cookie lock_cookie = {};
+ bool congested;
- wb = unlocked_inode_to_wb_begin(inode, &locked);
+ wb = unlocked_inode_to_wb_begin(inode, &lock_cookie);
congested = wb_congested(wb, cong_bits);
- unlocked_inode_to_wb_end(inode, locked);
+ unlocked_inode_to_wb_end(inode, &lock_cookie);
return congested;
}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 658fa9e..a0b0683 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -1891,8 +1891,10 @@
err = copy_out_args(cs, &req->out, nbytes);
if (req->in.h.opcode == FUSE_CANONICAL_PATH) {
- req->out.h.error = kern_path((char *)req->out.args[0].value, 0,
- req->canonical_path);
+ char *path = (char *)req->out.args[0].value;
+
+ path[req->out.args[0].size - 1] = 0;
+ req->out.h.error = kern_path(path, 0, req->canonical_path);
}
fuse_copy_finish(cs);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index f06c39c..d10bb2c 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -951,7 +951,7 @@
}
/*
- * This is a variaon of __jbd2_update_log_tail which checks for validity of
+ * This is a variation of __jbd2_update_log_tail which checks for validity of
* provided log tail and locks j_checkpoint_mutex. So it is safe against races
* with other threads updating log tail.
*/
@@ -1394,6 +1394,9 @@
journal_superblock_t *sb = journal->j_superblock;
int ret;
+ if (is_journal_aborted(journal))
+ return -EIO;
+
BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n",
tail_block, tail_tid);
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 5ef21f4..59c019a 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -342,7 +342,7 @@
static void jffs2_kill_sb(struct super_block *sb)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
- if (!(sb->s_flags & MS_RDONLY))
+ if (c && !(sb->s_flags & MS_RDONLY))
jffs2_stop_garbage_collect_thread(c);
kill_mtd_super(sb);
kfree(c);
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index a770da3..4d51259 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -132,6 +132,8 @@
{
int err = 0;
struct svc_rqst *rqstp = vrqstp;
+ struct net *net = &init_net;
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
/* try_to_freeze() is called from svc_recv() */
set_freezable();
@@ -176,6 +178,8 @@
if (nlmsvc_ops)
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
+ cancel_delayed_work_sync(&ln->grace_period_end);
+ locks_end_grace(&ln->lockd_manager);
return 0;
}
@@ -270,8 +274,6 @@
if (ln->nlmsvc_users) {
if (--ln->nlmsvc_users == 0) {
nlm_shutdown_hosts_net(net);
- cancel_delayed_work_sync(&ln->grace_period_end);
- locks_end_grace(&ln->lockd_manager);
svc_shutdown_net(serv, net);
dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
}
diff --git a/fs/namei.c b/fs/namei.c
index 02fc285..a5a05d3 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -221,9 +221,10 @@
if (len <= EMBEDDED_NAME_MAX) {
result->name = (char *)result->iname;
} else if (len <= PATH_MAX) {
+ const size_t size = offsetof(struct filename, iname[1]);
struct filename *tmp;
- tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
+ tmp = kmalloc(size, GFP_KERNEL);
if (unlikely(!tmp)) {
__putname(result);
return ERR_PTR(-ENOMEM);
diff --git a/fs/namespace.c b/fs/namespace.c
index 2160bb9..4628d08c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1051,7 +1051,8 @@
goto out_free;
}
- mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED);
+ mnt->mnt.mnt_flags = old->mnt.mnt_flags;
+ mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);
/* Don't allow unprivileged users to change mount flags */
if (flag & CL_UNPRIVILEGED) {
mnt->mnt.mnt_flags |= MNT_LOCK_ATIME;
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 13abd60..4539008 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -475,6 +475,7 @@
goto out_err_free;
/* fh */
+ rc = -EIO;
p = xdr_inline_decode(&stream, 4);
if (!p)
goto out_err_free;
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 4638654..1b1b616 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3300,6 +3300,7 @@
.rpc_resp = &res,
};
int status;
+ int i;
bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS |
FATTR4_WORD0_FH_EXPIRE_TYPE |
@@ -3365,8 +3366,13 @@
server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
server->cache_consistency_bitmask[2] = 0;
+
+ /* Avoid a regression due to buggy server */
+ for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++)
+ res.exclcreat_bitmask[i] &= res.attr_bitmask[i];
memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask,
sizeof(server->exclcreat_bitmask));
+
server->acl_bitmask = res.acl_bitmask;
server->fh_expire_type = res.fh_expire_type;
}
@@ -8173,6 +8179,12 @@
/* fall through */
case -NFS4ERR_RETRY_UNCACHED_REP:
return -EAGAIN;
+ case -NFS4ERR_BADSESSION:
+ case -NFS4ERR_DEADSESSION:
+ case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
+ nfs4_schedule_session_recovery(clp->cl_session,
+ task->tk_status);
+ break;
default:
nfs4_schedule_lease_recovery(clp);
}
@@ -8251,7 +8263,6 @@
if (status == 0)
status = task->tk_status;
rpc_put_task(task);
- return 0;
out:
dprintk("<-- %s status=%d\n", __func__, status);
return status;
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 71deeae..0bb0e62 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -1637,13 +1637,14 @@
nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
}
-static void nfs4_reclaim_complete(struct nfs_client *clp,
+static int nfs4_reclaim_complete(struct nfs_client *clp,
const struct nfs4_state_recovery_ops *ops,
struct rpc_cred *cred)
{
/* Notify the server we're done reclaiming our state */
if (ops->reclaim_complete)
- (void)ops->reclaim_complete(clp, cred);
+ return ops->reclaim_complete(clp, cred);
+ return 0;
}
static void nfs4_clear_reclaim_server(struct nfs_server *server)
@@ -1690,13 +1691,16 @@
{
const struct nfs4_state_recovery_ops *ops;
struct rpc_cred *cred;
+ int err;
if (!nfs4_state_clear_reclaim_reboot(clp))
return;
ops = clp->cl_mvops->reboot_recovery_ops;
cred = nfs4_get_clid_cred(clp);
- nfs4_reclaim_complete(clp, ops, cred);
+ err = nfs4_reclaim_complete(clp, ops, cred);
put_rpccred(cred);
+ if (err == -NFS4ERR_CONN_NOT_BOUND_TO_SESSION)
+ set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
}
static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
index e0e5f7c..8a459b1 100644
--- a/fs/notify/fanotify/fanotify.c
+++ b/fs/notify/fanotify/fanotify.c
@@ -92,7 +92,7 @@
u32 event_mask,
void *data, int data_type)
{
- __u32 marks_mask, marks_ignored_mask;
+ __u32 marks_mask = 0, marks_ignored_mask = 0;
struct path *path = data;
pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
@@ -108,24 +108,20 @@
!d_can_lookup(path->dentry))
return false;
- if (inode_mark && vfsmnt_mark) {
- marks_mask = (vfsmnt_mark->mask | inode_mark->mask);
- marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask);
- } else if (inode_mark) {
- /*
- * if the event is for a child and this inode doesn't care about
- * events on the child, don't send it!
- */
- if ((event_mask & FS_EVENT_ON_CHILD) &&
- !(inode_mark->mask & FS_EVENT_ON_CHILD))
- return false;
- marks_mask = inode_mark->mask;
- marks_ignored_mask = inode_mark->ignored_mask;
- } else if (vfsmnt_mark) {
- marks_mask = vfsmnt_mark->mask;
- marks_ignored_mask = vfsmnt_mark->ignored_mask;
- } else {
- BUG();
+ /*
+ * if the event is for a child and this inode doesn't care about
+ * events on the child, don't send it!
+ */
+ if (inode_mark &&
+ (!(event_mask & FS_EVENT_ON_CHILD) ||
+ (inode_mark->mask & FS_EVENT_ON_CHILD))) {
+ marks_mask |= inode_mark->mask;
+ marks_ignored_mask |= inode_mark->ignored_mask;
+ }
+
+ if (vfsmnt_mark) {
+ marks_mask |= vfsmnt_mark->mask;
+ marks_ignored_mask |= vfsmnt_mark->ignored_mask;
}
if (d_is_dir(path->dentry) &&
diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c
index 629d8c9..6e35ef6 100644
--- a/fs/orangefs/super.c
+++ b/fs/orangefs/super.c
@@ -559,6 +559,11 @@
/* provided sb cleanup */
kill_anon_super(sb);
+ if (!ORANGEFS_SB(sb)) {
+ mutex_lock(&orangefs_request_mutex);
+ mutex_unlock(&orangefs_request_mutex);
+ return;
+ }
/*
* issue the unmount to userspace to tell it to remove the
* dynamic mount info it has for this superblock
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index 306b6c1..8546384 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -180,6 +180,9 @@
inc_nlink(inode);
}
d_instantiate(dentry, inode);
+ /* Force lookup of new upper hardlink to find its lower */
+ if (hardlink)
+ d_drop(dentry);
}
static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 7fb53d0..16f6db8 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -227,6 +227,16 @@
return res;
}
+static bool ovl_can_list(const char *s)
+{
+ /* List all non-trusted xatts */
+ if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
+ return true;
+
+ /* Never list trusted.overlay, list other trusted for superuser only */
+ return !ovl_is_private_xattr(s) && capable(CAP_SYS_ADMIN);
+}
+
ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
{
struct dentry *realdentry = ovl_dentry_real(dentry);
@@ -250,7 +260,7 @@
return -EIO;
len -= slen;
- if (ovl_is_private_xattr(s)) {
+ if (!ovl_can_list(s)) {
res -= slen;
memmove(s, s + slen, len);
} else {
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 1ade120..08dce22 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -81,3 +81,10 @@
Say Y if you are running any user-space software which takes benefit from
this interface. For example, rkt is such a piece of software.
+
+config PROC_UID
+ bool "Include /proc/uid/ files"
+ default y
+ depends on PROC_FS && RT_MUTEXES
+ help
+ Provides aggregated per-uid information under /proc/uid.
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 12c6922..dea53ba 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -25,6 +25,7 @@
proc-y += namespaces.o
proc-y += self.o
proc-y += thread_self.o
+proc-$(CONFIG_PROC_UID) += uid.o
proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o
proc-$(CONFIG_NET) += proc_net.o
proc-$(CONFIG_PROC_KCORE) += kcore.o
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1370a4e..abe157a5 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -87,6 +87,7 @@
#include <linux/slab.h>
#include <linux/flex_array.h>
#include <linux/posix-timers.h>
+#include <linux/cpufreq_times.h>
#ifdef CONFIG_HARDWALL
#include <asm/hardwall.h>
#endif
@@ -3166,8 +3167,8 @@
ONE("cgroup", S_IRUGO, proc_cgroup_show),
#endif
ONE("oom_score", S_IRUGO, proc_oom_score),
- REG("oom_adj", S_IRUSR, proc_oom_adj_operations),
- REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
+ REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
+ REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUGO, proc_sessionid_operations),
@@ -3198,6 +3199,9 @@
REG("timers", S_IRUGO, proc_timers_operations),
#endif
REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations),
+#ifdef CONFIG_CPU_FREQ_TIMES
+ ONE("time_in_state", 0444, proc_time_in_state_show),
+#endif
};
static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
@@ -3561,8 +3565,8 @@
ONE("cgroup", S_IRUGO, proc_cgroup_show),
#endif
ONE("oom_score", S_IRUGO, proc_oom_score),
- REG("oom_adj", S_IRUSR, proc_oom_adj_operations),
- REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
+ REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
+ REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
#ifdef CONFIG_AUDITSYSCALL
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUGO, proc_sessionid_operations),
@@ -3586,6 +3590,9 @@
REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations),
#endif
+#ifdef CONFIG_CPU_FREQ_TIMES
+ ONE("time_in_state", 0444, proc_time_in_state_show),
+#endif
};
static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 6dfb414..d8105cd 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -257,6 +257,15 @@
#endif
/*
+ * uid.c
+ */
+#ifdef CONFIG_PROC_UID
+extern int proc_uid_init(void);
+#else
+static inline void proc_uid_init(void) { }
+#endif
+
+/*
* proc_tty.c
*/
#ifdef CONFIG_TTY
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 8d3e484..c2f5014 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -131,7 +131,7 @@
proc_symlink("mounts", NULL, "self/mounts");
proc_net_init();
-
+ proc_uid_init();
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
diff --git a/fs/proc/uid.c b/fs/proc/uid.c
new file mode 100644
index 0000000..3fd7b9f
--- /dev/null
+++ b/fs/proc/uid.c
@@ -0,0 +1,295 @@
+/*
+ * /proc/uid support
+ */
+
+#include <linux/cpufreq_times.h>
+#include <linux/fs.h>
+#include <linux/hashtable.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/rtmutex.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include "internal.h"
+
+static struct proc_dir_entry *proc_uid;
+
+#define UID_HASH_BITS 10
+
+static DECLARE_HASHTABLE(proc_uid_hash_table, UID_HASH_BITS);
+
+/*
+ * use rt_mutex here to avoid priority inversion between high-priority readers
+ * of these files and tasks calling proc_register_uid().
+ */
+static DEFINE_RT_MUTEX(proc_uid_lock); /* proc_uid_hash_table */
+
+struct uid_hash_entry {
+ uid_t uid;
+ struct hlist_node hash;
+};
+
+/* Caller must hold proc_uid_lock */
+static bool uid_hash_entry_exists_locked(uid_t uid)
+{
+ struct uid_hash_entry *entry;
+
+ hash_for_each_possible(proc_uid_hash_table, entry, hash, uid) {
+ if (entry->uid == uid)
+ return true;
+ }
+ return false;
+}
+
+void proc_register_uid(kuid_t kuid)
+{
+ struct uid_hash_entry *entry;
+ bool exists;
+ uid_t uid = from_kuid_munged(current_user_ns(), kuid);
+
+ rt_mutex_lock(&proc_uid_lock);
+ exists = uid_hash_entry_exists_locked(uid);
+ rt_mutex_unlock(&proc_uid_lock);
+ if (exists)
+ return;
+
+ entry = kzalloc(sizeof(struct uid_hash_entry), GFP_KERNEL);
+ if (!entry)
+ return;
+ entry->uid = uid;
+
+ rt_mutex_lock(&proc_uid_lock);
+ if (uid_hash_entry_exists_locked(uid))
+ kfree(entry);
+ else
+ hash_add(proc_uid_hash_table, &entry->hash, uid);
+ rt_mutex_unlock(&proc_uid_lock);
+}
+
+struct uid_entry {
+ const char *name;
+ int len;
+ umode_t mode;
+ const struct inode_operations *iop;
+ const struct file_operations *fop;
+};
+
+#define NOD(NAME, MODE, IOP, FOP) { \
+ .name = (NAME), \
+ .len = sizeof(NAME) - 1, \
+ .mode = MODE, \
+ .iop = IOP, \
+ .fop = FOP, \
+}
+
+#ifdef CONFIG_CPU_FREQ_TIMES
+static const struct file_operations proc_uid_time_in_state_operations = {
+ .open = single_uid_time_in_state_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+static const struct uid_entry uid_base_stuff[] = {
+#ifdef CONFIG_CPU_FREQ_TIMES
+ NOD("time_in_state", 0444, NULL, &proc_uid_time_in_state_operations),
+#endif
+};
+
+static const struct inode_operations proc_uid_def_inode_operations = {
+ .setattr = proc_setattr,
+};
+
+static struct inode *proc_uid_make_inode(struct super_block *sb, kuid_t kuid)
+{
+ struct inode *inode;
+
+ inode = new_inode(sb);
+ if (!inode)
+ return NULL;
+
+ inode->i_ino = get_next_ino();
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+ inode->i_op = &proc_uid_def_inode_operations;
+ inode->i_uid = kuid;
+
+ return inode;
+}
+
+static int proc_uident_instantiate(struct inode *dir, struct dentry *dentry,
+ struct task_struct *unused, const void *ptr)
+{
+ const struct uid_entry *u = ptr;
+ struct inode *inode;
+
+ inode = proc_uid_make_inode(dir->i_sb, dir->i_uid);
+ if (!inode)
+ return -ENOENT;
+
+ inode->i_mode = u->mode;
+ if (S_ISDIR(inode->i_mode))
+ set_nlink(inode, 2);
+ if (u->iop)
+ inode->i_op = u->iop;
+ if (u->fop)
+ inode->i_fop = u->fop;
+ d_add(dentry, inode);
+ return 0;
+}
+
+static struct dentry *proc_uid_base_lookup(struct inode *dir,
+ struct dentry *dentry,
+ unsigned int flags)
+{
+ const struct uid_entry *u, *last;
+ unsigned int nents = ARRAY_SIZE(uid_base_stuff);
+
+ if (nents == 0)
+ return ERR_PTR(-ENOENT);
+
+ last = &uid_base_stuff[nents - 1];
+ for (u = uid_base_stuff; u <= last; u++) {
+ if (u->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, u->name, u->len))
+ break;
+ }
+ if (u > last)
+ return ERR_PTR(-ENOENT);
+
+ return ERR_PTR(proc_uident_instantiate(dir, dentry, NULL, u));
+}
+
+static int proc_uid_base_readdir(struct file *file, struct dir_context *ctx)
+{
+ unsigned int nents = ARRAY_SIZE(uid_base_stuff);
+ const struct uid_entry *u;
+
+ if (!dir_emit_dots(file, ctx))
+ return 0;
+
+ if (ctx->pos >= nents + 2)
+ return 0;
+
+ for (u = uid_base_stuff + (ctx->pos - 2);
+ u <= uid_base_stuff + nents - 1; u++) {
+ if (!proc_fill_cache(file, ctx, u->name, u->len,
+ proc_uident_instantiate, NULL, u))
+ break;
+ ctx->pos++;
+ }
+
+ return 0;
+}
+
+static const struct inode_operations proc_uid_base_inode_operations = {
+ .lookup = proc_uid_base_lookup,
+ .setattr = proc_setattr,
+};
+
+static const struct file_operations proc_uid_base_operations = {
+ .read = generic_read_dir,
+ .iterate = proc_uid_base_readdir,
+ .llseek = default_llseek,
+};
+
+static int proc_uid_instantiate(struct inode *dir, struct dentry *dentry,
+ struct task_struct *unused, const void *ptr)
+{
+ unsigned int i, len;
+ nlink_t nlinks;
+ kuid_t *kuid = (kuid_t *)ptr;
+ struct inode *inode = proc_uid_make_inode(dir->i_sb, *kuid);
+
+ if (!inode)
+ return -ENOENT;
+
+ inode->i_mode = S_IFDIR | 0555;
+ inode->i_op = &proc_uid_base_inode_operations;
+ inode->i_fop = &proc_uid_base_operations;
+ inode->i_flags |= S_IMMUTABLE;
+
+ nlinks = 2;
+ len = ARRAY_SIZE(uid_base_stuff);
+ for (i = 0; i < len; ++i) {
+ if (S_ISDIR(uid_base_stuff[i].mode))
+ ++nlinks;
+ }
+ set_nlink(inode, nlinks);
+
+ d_add(dentry, inode);
+
+ return 0;
+}
+
+static int proc_uid_readdir(struct file *file, struct dir_context *ctx)
+{
+ int last_shown, i;
+ unsigned long bkt;
+ struct uid_hash_entry *entry;
+
+ if (!dir_emit_dots(file, ctx))
+ return 0;
+
+ i = 0;
+ last_shown = ctx->pos - 2;
+ rt_mutex_lock(&proc_uid_lock);
+ hash_for_each(proc_uid_hash_table, bkt, entry, hash) {
+ int len;
+ char buf[PROC_NUMBUF];
+
+ if (i < last_shown)
+ continue;
+ len = snprintf(buf, sizeof(buf), "%u", entry->uid);
+ if (!proc_fill_cache(file, ctx, buf, len,
+ proc_uid_instantiate, NULL, &entry->uid))
+ break;
+ i++;
+ ctx->pos++;
+ }
+ rt_mutex_unlock(&proc_uid_lock);
+ return 0;
+}
+
+static struct dentry *proc_uid_lookup(struct inode *dir, struct dentry *dentry,
+ unsigned int flags)
+{
+ int result = -ENOENT;
+
+ uid_t uid = name_to_int(&dentry->d_name);
+ bool uid_exists;
+
+ rt_mutex_lock(&proc_uid_lock);
+ uid_exists = uid_hash_entry_exists_locked(uid);
+ rt_mutex_unlock(&proc_uid_lock);
+ if (uid_exists) {
+ kuid_t kuid = make_kuid(current_user_ns(), uid);
+
+ result = proc_uid_instantiate(dir, dentry, NULL, &kuid);
+ }
+ return ERR_PTR(result);
+}
+
+static const struct file_operations proc_uid_operations = {
+ .read = generic_read_dir,
+ .iterate = proc_uid_readdir,
+ .llseek = default_llseek,
+};
+
+static const struct inode_operations proc_uid_inode_operations = {
+ .lookup = proc_uid_lookup,
+ .setattr = proc_setattr,
+};
+
+int __init proc_uid_init(void)
+{
+ proc_uid = proc_mkdir("uid", NULL);
+ if (!proc_uid)
+ return -ENOMEM;
+ proc_uid->proc_iops = &proc_uid_inode_operations;
+ proc_uid->proc_fops = &proc_uid_operations;
+
+ return 0;
+}
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 7610818..2a5c481 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2640,7 +2640,7 @@
if (IS_ERR(journal->j_dev_bd)) {
result = PTR_ERR(journal->j_dev_bd);
journal->j_dev_bd = NULL;
- reiserfs_warning(super,
+ reiserfs_warning(super, "sh-457",
"journal_init_dev: Cannot open '%s': %i",
jdev_name, result);
return result;
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 4ec05108..03dda1c 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -1728,8 +1728,11 @@
dbg_save_space_info(c);
- for (i = 0; i < c->jhead_cnt; i++)
- ubifs_wbuf_sync(&c->jheads[i].wbuf);
+ for (i = 0; i < c->jhead_cnt; i++) {
+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+ if (err)
+ ubifs_ro_mode(c, err);
+ }
c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
@@ -1795,8 +1798,11 @@
int err;
/* Synchronize write-buffers */
- for (i = 0; i < c->jhead_cnt; i++)
- ubifs_wbuf_sync(&c->jheads[i].wbuf);
+ for (i = 0; i < c->jhead_cnt; i++) {
+ err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
+ if (err)
+ ubifs_ro_mode(c, err);
+ }
/*
* We are being cleanly unmounted which means the
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c
index 695389a..3a3be23 100644
--- a/fs/udf/unicode.c
+++ b/fs/udf/unicode.c
@@ -28,6 +28,9 @@
#include "udf_sb.h"
+#define SURROGATE_MASK 0xfffff800
+#define SURROGATE_PAIR 0x0000d800
+
static int udf_uni2char_utf8(wchar_t uni,
unsigned char *out,
int boundlen)
@@ -37,6 +40,9 @@
if (boundlen <= 0)
return -ENAMETOOLONG;
+ if ((uni & SURROGATE_MASK) == SURROGATE_PAIR)
+ return -EINVAL;
+
if (uni < 0x80) {
out[u_len++] = (unsigned char)uni;
} else if (uni < 0x800) {
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 8f66aaa..9e3f761 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -48,7 +48,17 @@
* Use compiler specific <stdarg.h> is a good practice for even when
* -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
*/
+#ifndef va_arg
+#ifdef ACPI_USE_BUILTIN_STDARG
+typedef __builtin_va_list va_list;
+#define va_start(v, l) __builtin_va_start(v, l)
+#define va_end(v) __builtin_va_end(v)
+#define va_arg(v, l) __builtin_va_arg(v, l)
+#define va_copy(d, s) __builtin_va_copy(d, s)
+#else
#include <stdarg.h>
+#endif
+#endif
#define ACPI_INLINE __inline__
diff --git a/include/acpi/platform/acintel.h b/include/acpi/platform/acintel.h
index 17bd3b7..bdb6858 100644
--- a/include/acpi/platform/acintel.h
+++ b/include/acpi/platform/acintel.h
@@ -48,7 +48,9 @@
* Use compiler specific <stdarg.h> is a good practice for even when
* -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined.
*/
+#ifndef va_arg
#include <stdarg.h>
+#endif
/* Configuration specific to Intel 64-bit C compiler */
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
index 3c2024d..328f232 100644
--- a/include/drm/drm_mipi_dsi.h
+++ b/include/drm/drm_mipi_dsi.h
@@ -32,6 +32,7 @@
* @type: payload data type
* @flags: flags controlling this message transmission
* @ctrl: ctrl index to transmit on
+ * @wait_ms: duration in ms to wait after message transmission
* @tx_len: length of @tx_buf
* @tx_buf: data to be written
* @rx_len: length of @rx_buf
@@ -42,6 +43,7 @@
u8 type;
u16 flags;
u32 ctrl;
+ u32 wait_ms;
size_t tx_len;
const void *tx_buf;
diff --git a/include/dt-bindings/clock/msm-clocks-8952.h b/include/dt-bindings/clock/msm-clocks-8952.h
index 3190d4f..e66c5ed 100644
--- a/include/dt-bindings/clock/msm-clocks-8952.h
+++ b/include/dt-bindings/clock/msm-clocks-8952.h
@@ -237,8 +237,10 @@
#define clk_dsi0pll_byte_clk_src 0xbbaa30be
#define clk_dsi0pll_pixel_clk_src 0x45b3260f
+#define clk_dsi0pll_vco_clk 0x15940d40
#define clk_dsi1pll_byte_clk_src 0x63930a8f
#define clk_dsi1pll_pixel_clk_src 0x0e4c9b56
+#define clk_dsi1pll_vco_clk 0x99797b50
#define clk_dsi_pll0_byte_clk_src 0x44539836
#define clk_dsi_pll0_pixel_clk_src 0x5767c287
diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h
index 2062c67..a72db8d 100644
--- a/include/dt-bindings/clock/mt2701-clk.h
+++ b/include/dt-bindings/clock/mt2701-clk.h
@@ -176,7 +176,8 @@
#define CLK_TOP_AUD_EXT1 156
#define CLK_TOP_AUD_EXT2 157
#define CLK_TOP_NFI1X_PAD 158
-#define CLK_TOP_NR 159
+#define CLK_TOP_AXISEL_D4 159
+#define CLK_TOP_NR 160
/* APMIXEDSYS */
diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h
new file mode 100644
index 0000000..e518e4e
--- /dev/null
+++ b/include/kvm/arm_psci.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012,2013 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __KVM_ARM_PSCI_H__
+#define __KVM_ARM_PSCI_H__
+
+#include <linux/kvm_host.h>
+#include <uapi/linux/psci.h>
+
+#define KVM_ARM_PSCI_0_1 PSCI_VERSION(0, 1)
+#define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2)
+#define KVM_ARM_PSCI_1_0 PSCI_VERSION(1, 0)
+
+#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_0
+
+/*
+ * We need the KVM pointer independently from the vcpu as we can call
+ * this from HYP, and need to apply kern_hyp_va on it...
+ */
+static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm)
+{
+ /*
+ * Our PSCI implementation stays the same across versions from
+ * v0.2 onward, only adding the few mandatory functions (such
+ * as FEATURES with 1.0) that are required by newer
+ * revisions. It is thus safe to return the latest.
+ */
+ if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features))
+ return KVM_ARM_PSCI_LATEST;
+
+ return KVM_ARM_PSCI_0_1;
+}
+
+
+int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
+
+#endif /* __KVM_ARM_PSCI_H__ */
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
index 4c5bca38..43690f5 100644
--- a/include/linux/arm-smccc.h
+++ b/include/linux/arm-smccc.h
@@ -14,14 +14,16 @@
#ifndef __LINUX_ARM_SMCCC_H
#define __LINUX_ARM_SMCCC_H
+#include <uapi/linux/const.h>
+
/*
* This file provides common defines for ARM SMC Calling Convention as
* specified in
* http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
*/
-#define ARM_SMCCC_STD_CALL 0
-#define ARM_SMCCC_FAST_CALL 1
+#define ARM_SMCCC_STD_CALL _AC(0,U)
+#define ARM_SMCCC_FAST_CALL _AC(1,U)
#define ARM_SMCCC_TYPE_SHIFT 31
#define ARM_SMCCC_SMC_32 0
@@ -60,6 +62,24 @@
#define ARM_SMCCC_QUIRK_NONE 0
#define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */
+#define ARM_SMCCC_VERSION_1_0 0x10000
+#define ARM_SMCCC_VERSION_1_1 0x10001
+
+#define ARM_SMCCC_VERSION_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ 0, 0)
+
+#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ 0, 1)
+
+#define ARM_SMCCC_ARCH_WORKAROUND_1 \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
+ ARM_SMCCC_SMC_32, \
+ 0, 0x8000)
+
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
@@ -130,5 +150,148 @@
#define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__)
+/* SMCCC v1.1 implementation madness follows */
+#ifdef CONFIG_ARM64
+
+#define SMCCC_SMC_INST "smc #0"
+#define SMCCC_HVC_INST "hvc #0"
+#define SMCCC_REG(n) asm("x" # n)
+
+#elif defined(CONFIG_ARM)
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+
+#define SMCCC_SMC_INST __SMC(0)
+#define SMCCC_HVC_INST __HVC(0)
+#define SMCCC_REG(n) asm("r" # n)
+
+#endif
+
+#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x
+
+#define __count_args(...) \
+ ___count_args(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
+
+#define __constraint_write_0 \
+ "+r" (r0), "=&r" (r1), "=&r" (r2), "=&r" (r3)
+#define __constraint_write_1 \
+ "+r" (r0), "+r" (r1), "=&r" (r2), "=&r" (r3)
+#define __constraint_write_2 \
+ "+r" (r0), "+r" (r1), "+r" (r2), "=&r" (r3)
+#define __constraint_write_3 \
+ "+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3)
+#define __constraint_write_4 __constraint_write_3
+#define __constraint_write_5 __constraint_write_4
+#define __constraint_write_6 __constraint_write_5
+#define __constraint_write_7 __constraint_write_6
+
+#define __constraint_read_0
+#define __constraint_read_1
+#define __constraint_read_2
+#define __constraint_read_3
+#define __constraint_read_4 "r" (r4)
+#define __constraint_read_5 __constraint_read_4, "r" (r5)
+#define __constraint_read_6 __constraint_read_5, "r" (r6)
+#define __constraint_read_7 __constraint_read_6, "r" (r7)
+
+#define __declare_arg_0(a0, res) \
+ struct arm_smccc_res *___res = res; \
+ register u32 r0 SMCCC_REG(0) = a0; \
+ register unsigned long r1 SMCCC_REG(1); \
+ register unsigned long r2 SMCCC_REG(2); \
+ register unsigned long r3 SMCCC_REG(3)
+
+#define __declare_arg_1(a0, a1, res) \
+ struct arm_smccc_res *___res = res; \
+ register u32 r0 SMCCC_REG(0) = a0; \
+ register typeof(a1) r1 SMCCC_REG(1) = a1; \
+ register unsigned long r2 SMCCC_REG(2); \
+ register unsigned long r3 SMCCC_REG(3)
+
+#define __declare_arg_2(a0, a1, a2, res) \
+ struct arm_smccc_res *___res = res; \
+ register u32 r0 SMCCC_REG(0) = a0; \
+ register typeof(a1) r1 SMCCC_REG(1) = a1; \
+ register typeof(a2) r2 SMCCC_REG(2) = a2; \
+ register unsigned long r3 SMCCC_REG(3)
+
+#define __declare_arg_3(a0, a1, a2, a3, res) \
+ struct arm_smccc_res *___res = res; \
+ register u32 r0 SMCCC_REG(0) = a0; \
+ register typeof(a1) r1 SMCCC_REG(1) = a1; \
+ register typeof(a2) r2 SMCCC_REG(2) = a2; \
+ register typeof(a3) r3 SMCCC_REG(3) = a3
+
+#define __declare_arg_4(a0, a1, a2, a3, a4, res) \
+ __declare_arg_3(a0, a1, a2, a3, res); \
+ register typeof(a4) r4 SMCCC_REG(4) = a4
+
+#define __declare_arg_5(a0, a1, a2, a3, a4, a5, res) \
+ __declare_arg_4(a0, a1, a2, a3, a4, res); \
+ register typeof(a5) r5 SMCCC_REG(5) = a5
+
+#define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res) \
+ __declare_arg_5(a0, a1, a2, a3, a4, a5, res); \
+ register typeof(a6) r6 SMCCC_REG(6) = a6
+
+#define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res) \
+ __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res); \
+ register typeof(a7) r7 SMCCC_REG(7) = a7
+
+#define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__)
+#define __declare_args(count, ...) ___declare_args(count, __VA_ARGS__)
+
+#define ___constraints(count) \
+ : __constraint_write_ ## count \
+ : __constraint_read_ ## count \
+ : "memory"
+#define __constraints(count) ___constraints(count)
+
+/*
+ * We have an output list that is not necessarily used, and GCC feels
+ * entitled to optimise the whole sequence away. "volatile" is what
+ * makes it stick.
+ */
+#define __arm_smccc_1_1(inst, ...) \
+ do { \
+ __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \
+ asm volatile(inst "\n" \
+ __constraints(__count_args(__VA_ARGS__))); \
+ if (___res) \
+ *___res = (typeof(*___res)){r0, r1, r2, r3}; \
+ } while (0)
+
+/*
+ * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call
+ *
+ * This is a variadic macro taking one to eight source arguments, and
+ * an optional return structure.
+ *
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This macro is used to make SMC calls following SMC Calling Convention v1.1.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction if not NULL.
+ */
+#define arm_smccc_1_1_smc(...) __arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__)
+
+/*
+ * arm_smccc_1_1_hvc() - make an SMCCC v1.1 compliant HVC call
+ *
+ * This is a variadic macro taking one to eight source arguments, and
+ * an optional return structure.
+ *
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This macro is used to make HVC calls following SMC Calling Convention v1.1.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the HVC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the HVC instruction if not NULL.
+ */
+#define arm_smccc_1_1_hvc(...) __arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__)
+
#endif /*__ASSEMBLY__*/
#endif /*__LINUX_ARM_SMCCC_H*/
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h
index 0691068..002f87c 100644
--- a/include/linux/backing-dev-defs.h
+++ b/include/linux/backing-dev-defs.h
@@ -195,6 +195,11 @@
set_wb_congested(bdi->wb.congested, sync);
}
+struct wb_lock_cookie {
+ bool locked;
+ unsigned long flags;
+};
+
#ifdef CONFIG_CGROUP_WRITEBACK
/**
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index c52a48c..8272fcf7 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -374,7 +374,7 @@
/**
* unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction
* @inode: target inode
- * @lockedp: temp bool output param, to be passed to the end function
+ * @cookie: output param, to be passed to the end function
*
* The caller wants to access the wb associated with @inode but isn't
* holding inode->i_lock, mapping->tree_lock or wb->list_lock. This
@@ -382,12 +382,12 @@
* association doesn't change until the transaction is finished with
* unlocked_inode_to_wb_end().
*
- * The caller must call unlocked_inode_to_wb_end() with *@lockdep
- * afterwards and can't sleep during transaction. IRQ may or may not be
- * disabled on return.
+ * The caller must call unlocked_inode_to_wb_end() with *@cookie afterwards and
+ * can't sleep during the transaction. IRQs may or may not be disabled on
+ * return.
*/
static inline struct bdi_writeback *
-unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
+unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
{
rcu_read_lock();
@@ -395,10 +395,10 @@
* Paired with store_release in inode_switch_wb_work_fn() and
* ensures that we see the new wb if we see cleared I_WB_SWITCH.
*/
- *lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
+ cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH;
- if (unlikely(*lockedp))
- spin_lock_irq(&inode->i_mapping->tree_lock);
+ if (unlikely(cookie->locked))
+ spin_lock_irqsave(&inode->i_mapping->tree_lock, cookie->flags);
/*
* Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock.
@@ -410,12 +410,13 @@
/**
* unlocked_inode_to_wb_end - end inode wb access transaction
* @inode: target inode
- * @locked: *@lockedp from unlocked_inode_to_wb_begin()
+ * @cookie: @cookie from unlocked_inode_to_wb_begin()
*/
-static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
+static inline void unlocked_inode_to_wb_end(struct inode *inode,
+ struct wb_lock_cookie *cookie)
{
- if (unlikely(locked))
- spin_unlock_irq(&inode->i_mapping->tree_lock);
+ if (unlikely(cookie->locked))
+ spin_unlock_irqrestore(&inode->i_mapping->tree_lock, cookie->flags);
rcu_read_unlock();
}
@@ -462,12 +463,13 @@
}
static inline struct bdi_writeback *
-unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp)
+unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie)
{
return inode_to_wb(inode);
}
-static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked)
+static inline void unlocked_inode_to_wb_end(struct inode *inode,
+ struct wb_lock_cookie *cookie)
{
}
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index 2b8b6e0..e4d84d3 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -25,6 +25,7 @@
struct bio {
struct bio *bi_next; /* request queue link */
struct block_device *bi_bdev;
+ unsigned short bi_write_hint;
int bi_error;
unsigned int bi_opf; /* bottom bits req flags,
* top bits REQ_OP. Use
diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h
new file mode 100644
index 0000000..3fb3875
--- /dev/null
+++ b/include/linux/cpufreq_times.h
@@ -0,0 +1,40 @@
+/* drivers/cpufreq/cpufreq_times.c
+ *
+ * Copyright (C) 2018 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_CPUFREQ_TIMES_H
+#define _LINUX_CPUFREQ_TIMES_H
+
+#include <linux/cpufreq.h>
+#include <linux/cputime.h>
+#include <linux/pid.h>
+
+#ifdef CONFIG_CPU_FREQ_TIMES
+void cpufreq_task_times_init(struct task_struct *p);
+void cpufreq_task_times_exit(struct task_struct *p);
+int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
+ struct pid *pid, struct task_struct *p);
+void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime);
+void cpufreq_times_create_policy(struct cpufreq_policy *policy);
+void cpufreq_times_record_transition(struct cpufreq_freqs *freq);
+void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end);
+int single_uid_time_in_state_open(struct inode *inode, struct file *file);
+#else
+static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {}
+static inline void cpufreq_times_record_transition(
+ struct cpufreq_freqs *freq) {}
+static inline void cpufreq_task_times_remove_uids(uid_t uid_start,
+ uid_t uid_end) {}
+#endif /* CONFIG_CPU_FREQ_TIMES */
+#endif /* _LINUX_CPUFREQ_TIMES_H */
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index b49f866..bd96bb2 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -695,6 +695,11 @@
void free_cpumask_var(cpumask_var_t mask);
void free_bootmem_cpumask_var(cpumask_var_t mask);
+static inline bool cpumask_available(cpumask_var_t mask)
+{
+ return mask != NULL;
+}
+
#else
typedef struct cpumask cpumask_var_t[1];
@@ -735,6 +740,11 @@
static inline void free_bootmem_cpumask_var(cpumask_var_t mask)
{
}
+
+static inline bool cpumask_available(cpumask_var_t mask)
+{
+ return true;
+}
#endif /* CONFIG_CPUMASK_OFFSTACK */
/* It's common to want to use cpu_all_mask in struct member initializers,
diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h
index a3d9563..d9912e0 100644
--- a/include/linux/diagchar.h
+++ b/include/linux/diagchar.h
@@ -896,7 +896,7 @@
/* LOG CODES */
static const uint32_t log_code_last_tbl[] = {
0x0, /* EQUIP ID 0 */
- 0x1C68, /* EQUIP ID 1 */
+ 0x1C6A, /* EQUIP ID 1 */
0x0, /* EQUIP ID 2 */
0x0, /* EQUIP ID 3 */
0x4910, /* EQUIP ID 4 */
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 393b880..aa5db8b 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -21,6 +21,7 @@
#define F2FS_BLKSIZE 4096 /* support only 4KB block */
#define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */
#define F2FS_MAX_EXTENSION 64 /* # of extension entries */
+#define F2FS_EXTENSION_LEN 8 /* max size of extension */
#define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS)
#define NULL_ADDR ((block_t)0) /* used as block_t addresses */
@@ -38,10 +39,10 @@
#define F2FS_MAX_QUOTAS 3
-#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */
-#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */
-#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */
-#define F2FS_IO_SIZE_BITS(sbi) ((sbi)->write_io_size_bits) /* power of 2 */
+#define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */
+#define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */
+#define F2FS_IO_SIZE_BYTES(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */
+#define F2FS_IO_SIZE_BITS(sbi) (F2FS_OPTION(sbi).write_io_size_bits) /* power of 2 */
#define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1)
/* This flag is used by node and meta inodes, and by recovery */
@@ -101,7 +102,7 @@
__u8 uuid[16]; /* 128-bit uuid for volume */
__le16 volume_name[MAX_VOLUME_NAME]; /* volume name */
__le32 extension_count; /* # of extensions below */
- __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */
+ __u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */
__le32 cp_payload;
__u8 version[VERSION_LEN]; /* the kernel version */
__u8 init_version[VERSION_LEN]; /* the initial kernel version */
@@ -110,12 +111,14 @@
__u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
struct f2fs_device devs[MAX_DEVICES]; /* device list */
__le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */
- __u8 reserved[315]; /* valid reserved region */
+ __u8 hot_ext_count; /* # of hot file extension */
+ __u8 reserved[314]; /* valid reserved region */
} __packed;
/*
* For checkpoint
*/
+#define CP_LARGE_NAT_BITMAP_FLAG 0x00000400
#define CP_NOCRC_RECOVERY_FLAG 0x00000200
#define CP_TRIMMED_FLAG 0x00000100
#define CP_NAT_BITS_FLAG 0x00000080
@@ -302,6 +305,10 @@
*/
#define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry))
#define NAT_ENTRY_BITMAP_SIZE ((NAT_ENTRY_PER_BLOCK + 7) / 8)
+#define NAT_ENTRY_BITMAP_SIZE_ALIGNED \
+ ((NAT_ENTRY_BITMAP_SIZE + BITS_PER_LONG - 1) / \
+ BITS_PER_LONG * BITS_PER_LONG)
+
struct f2fs_nat_entry {
__u8 version; /* latest version of cached nat entry */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index db3bdb2..8a3bdad 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -21,6 +21,7 @@
#include <linux/mm_types.h>
#include <linux/capability.h>
#include <linux/semaphore.h>
+#include <linux/fcntl.h>
#include <linux/fiemap.h>
#include <linux/rculist_bl.h>
#include <linux/atomic.h>
@@ -144,6 +145,9 @@
/* File was opened by fanotify and shouldn't generate fanotify events */
#define FMODE_NONOTIFY ((__force fmode_t)0x4000000)
+/* File is capable of returning -EAGAIN if I/O will block */
+#define FMODE_NOWAIT ((__force fmode_t)0x8000000)
+
/*
* Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector
* that indicates that they should check the contents of the iovec are
@@ -316,6 +320,18 @@
struct address_space;
struct writeback_control;
+/*
+ * Write life time hint values.
+ */
+enum rw_hint {
+ WRITE_LIFE_NOT_SET = 0,
+ WRITE_LIFE_NONE = RWH_WRITE_LIFE_NONE,
+ WRITE_LIFE_SHORT = RWH_WRITE_LIFE_SHORT,
+ WRITE_LIFE_MEDIUM = RWH_WRITE_LIFE_MEDIUM,
+ WRITE_LIFE_LONG = RWH_WRITE_LIFE_LONG,
+ WRITE_LIFE_EXTREME = RWH_WRITE_LIFE_EXTREME,
+};
+
#define IOCB_EVENTFD (1 << 0)
#define IOCB_APPEND (1 << 1)
#define IOCB_DIRECT (1 << 2)
@@ -323,6 +339,7 @@
#define IOCB_DSYNC (1 << 4)
#define IOCB_SYNC (1 << 5)
#define IOCB_WRITE (1 << 6)
+#define IOCB_NOWAIT (1 << 7)
struct kiocb {
struct file *ki_filp;
@@ -330,6 +347,7 @@
void (*ki_complete)(struct kiocb *iocb, long ret, long ret2);
void *private;
int ki_flags;
+ enum rw_hint ki_hint;
};
static inline bool is_sync_kiocb(struct kiocb *kiocb)
@@ -644,6 +662,7 @@
spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */
unsigned short i_bytes;
unsigned int i_blkbits;
+ enum rw_hint i_write_hint;
blkcnt_t i_blocks;
#ifdef __NEED_I_SIZE_ORDERED
@@ -1071,8 +1090,6 @@
#define OFFT_OFFSET_MAX INT_LIMIT(off_t)
#endif
-#include <linux/fcntl.h>
-
extern void send_sigio(struct fown_struct *fown, int fd, int band);
/*
diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h
index 8641e56..9e535af 100644
--- a/include/linux/fscrypt.h
+++ b/include/linux/fscrypt.h
@@ -13,42 +13,13 @@
#ifndef _LINUX_FSCRYPT_H
#define _LINUX_FSCRYPT_H
-#include <linux/key.h>
#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/bio.h>
-#include <linux/dcache.h>
-#include <crypto/skcipher.h>
-#include <uapi/linux/fs.h>
#define FS_CRYPTO_BLOCK_SIZE 16
+struct fscrypt_ctx;
struct fscrypt_info;
-struct fscrypt_ctx {
- union {
- struct {
- struct page *bounce_page; /* Ciphertext page */
- struct page *control_page; /* Original page */
- } w;
- struct {
- struct bio *bio;
- struct work_struct work;
- } r;
- struct list_head free_list; /* Free list */
- };
- u8 flags; /* Flags */
-};
-
-/**
- * For encrypted symlinks, the ciphertext length is stored at the beginning
- * of the string in little-endian format.
- */
-struct fscrypt_symlink_data {
- __le16 len;
- char encrypted_path[1];
-} __packed;
-
struct fscrypt_str {
unsigned char *name;
u32 len;
@@ -67,86 +38,11 @@
#define fname_name(p) ((p)->disk_name.name)
#define fname_len(p) ((p)->disk_name.len)
-/*
- * fscrypt superblock flags
- */
-#define FS_CFLG_OWN_PAGES (1U << 1)
-
-/*
- * crypto opertions for filesystems
- */
-struct fscrypt_operations {
- unsigned int flags;
- const char *key_prefix;
- int (*get_context)(struct inode *, void *, size_t);
- int (*set_context)(struct inode *, const void *, size_t, void *);
- bool (*dummy_context)(struct inode *);
- bool (*empty_dir)(struct inode *);
- unsigned (*max_namelen)(struct inode *);
-};
-
-static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
-{
- if (inode->i_sb->s_cop->dummy_context &&
- inode->i_sb->s_cop->dummy_context(inode))
- return true;
- return false;
-}
-
-static inline bool fscrypt_valid_enc_modes(u32 contents_mode,
- u32 filenames_mode)
-{
- if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC &&
- filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS)
- return true;
-
- if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS &&
- filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS)
- return true;
-
- return false;
-}
-
-static inline bool fscrypt_is_dot_dotdot(const struct qstr *str)
-{
- if (str->len == 1 && str->name[0] == '.')
- return true;
-
- if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.')
- return true;
-
- return false;
-}
-
#if __FS_HAS_ENCRYPTION
-
-static inline struct page *fscrypt_control_page(struct page *page)
-{
- return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
-}
-
-static inline bool fscrypt_has_encryption_key(const struct inode *inode)
-{
- return (inode->i_crypt_info != NULL);
-}
-
#include <linux/fscrypt_supp.h>
-
-#else /* !__FS_HAS_ENCRYPTION */
-
-static inline struct page *fscrypt_control_page(struct page *page)
-{
- WARN_ON_ONCE(1);
- return ERR_PTR(-EINVAL);
-}
-
-static inline bool fscrypt_has_encryption_key(const struct inode *inode)
-{
- return 0;
-}
-
+#else
#include <linux/fscrypt_notsupp.h>
-#endif /* __FS_HAS_ENCRYPTION */
+#endif
/**
* fscrypt_require_key - require an inode's encryption key
@@ -287,4 +183,68 @@
return 0;
}
+/**
+ * fscrypt_prepare_symlink - prepare to create a possibly-encrypted symlink
+ * @dir: directory in which the symlink is being created
+ * @target: plaintext symlink target
+ * @len: length of @target excluding null terminator
+ * @max_len: space the filesystem has available to store the symlink target
+ * @disk_link: (out) the on-disk symlink target being prepared
+ *
+ * This function computes the size the symlink target will require on-disk,
+ * stores it in @disk_link->len, and validates it against @max_len. An
+ * encrypted symlink may be longer than the original.
+ *
+ * Additionally, @disk_link->name is set to @target if the symlink will be
+ * unencrypted, but left NULL if the symlink will be encrypted. For encrypted
+ * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the
+ * on-disk target later. (The reason for the two-step process is that some
+ * filesystems need to know the size of the symlink target before creating the
+ * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.)
+ *
+ * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long,
+ * -ENOKEY if the encryption key is missing, or another -errno code if a problem
+ * occurred while setting up the encryption key.
+ */
+static inline int fscrypt_prepare_symlink(struct inode *dir,
+ const char *target,
+ unsigned int len,
+ unsigned int max_len,
+ struct fscrypt_str *disk_link)
+{
+ if (IS_ENCRYPTED(dir) || fscrypt_dummy_context_enabled(dir))
+ return __fscrypt_prepare_symlink(dir, len, max_len, disk_link);
+
+ disk_link->name = (unsigned char *)target;
+ disk_link->len = len + 1;
+ if (disk_link->len > max_len)
+ return -ENAMETOOLONG;
+ return 0;
+}
+
+/**
+ * fscrypt_encrypt_symlink - encrypt the symlink target if needed
+ * @inode: symlink inode
+ * @target: plaintext symlink target
+ * @len: length of @target excluding null terminator
+ * @disk_link: (in/out) the on-disk symlink target being prepared
+ *
+ * If the symlink target needs to be encrypted, then this function encrypts it
+ * into @disk_link->name. fscrypt_prepare_symlink() must have been called
+ * previously to compute @disk_link->len. If the filesystem did not allocate a
+ * buffer for @disk_link->name after calling fscrypt_prepare_link(), then one
+ * will be kmalloc()'ed and the filesystem will be responsible for freeing it.
+ *
+ * Return: 0 on success, -errno on failure
+ */
+static inline int fscrypt_encrypt_symlink(struct inode *inode,
+ const char *target,
+ unsigned int len,
+ struct fscrypt_str *disk_link)
+{
+ if (IS_ENCRYPTED(inode))
+ return __fscrypt_encrypt_symlink(inode, target, len, disk_link);
+ return 0;
+}
+
#endif /* _LINUX_FSCRYPT_H */
diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h
index c4c6bf2..6f97714 100644
--- a/include/linux/fscrypt_notsupp.h
+++ b/include/linux/fscrypt_notsupp.h
@@ -13,7 +13,21 @@
#ifndef _LINUX_FSCRYPT_NOTSUPP_H
#define _LINUX_FSCRYPT_NOTSUPP_H
+static inline bool fscrypt_has_encryption_key(const struct inode *inode)
+{
+ return false;
+}
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+ return false;
+}
+
/* crypto.c */
+static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work)
+{
+}
+
static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode,
gfp_t gfp_flags)
{
@@ -42,6 +56,11 @@
return -EOPNOTSUPP;
}
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+ WARN_ON_ONCE(1);
+ return ERR_PTR(-EINVAL);
+}
static inline void fscrypt_restore_control_page(struct page *page)
{
@@ -89,8 +108,7 @@
return -EOPNOTSUPP;
}
-static inline void fscrypt_put_encryption_info(struct inode *inode,
- struct fscrypt_info *ci)
+static inline void fscrypt_put_encryption_info(struct inode *inode)
{
return;
}
@@ -115,16 +133,8 @@
return;
}
-static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode,
- u32 ilen)
-{
- /* never happens */
- WARN_ON(1);
- return 0;
-}
-
static inline int fscrypt_fname_alloc_buffer(const struct inode *inode,
- u32 ilen,
+ u32 max_encrypted_len,
struct fscrypt_str *crypto_str)
{
return -EOPNOTSUPP;
@@ -143,13 +153,6 @@
return -EOPNOTSUPP;
}
-static inline int fscrypt_fname_usr_to_disk(struct inode *inode,
- const struct qstr *iname,
- struct fscrypt_str *oname)
-{
- return -EOPNOTSUPP;
-}
-
static inline bool fscrypt_match_name(const struct fscrypt_name *fname,
const u8 *de_name, u32 de_name_len)
{
@@ -160,10 +163,13 @@
}
/* bio.c */
-static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx,
- struct bio *bio)
+static inline void fscrypt_decrypt_bio(struct bio *bio)
{
- return;
+}
+
+static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx,
+ struct bio *bio)
+{
}
static inline void fscrypt_pullback_bio_page(struct page **page, bool restore)
@@ -207,4 +213,28 @@
return -EOPNOTSUPP;
}
+static inline int __fscrypt_prepare_symlink(struct inode *dir,
+ unsigned int len,
+ unsigned int max_len,
+ struct fscrypt_str *disk_link)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int __fscrypt_encrypt_symlink(struct inode *inode,
+ const char *target,
+ unsigned int len,
+ struct fscrypt_str *disk_link)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline const char *fscrypt_get_symlink(struct inode *inode,
+ const void *caddr,
+ unsigned int max_size,
+ struct delayed_call *done)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+
#endif /* _LINUX_FSCRYPT_NOTSUPP_H */
diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h
index 2db5e970..1ed79ee 100644
--- a/include/linux/fscrypt_supp.h
+++ b/include/linux/fscrypt_supp.h
@@ -10,8 +10,55 @@
#ifndef _LINUX_FSCRYPT_SUPP_H
#define _LINUX_FSCRYPT_SUPP_H
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+/*
+ * fscrypt superblock flags
+ */
+#define FS_CFLG_OWN_PAGES (1U << 1)
+
+/*
+ * crypto operations for filesystems
+ */
+struct fscrypt_operations {
+ unsigned int flags;
+ const char *key_prefix;
+ int (*get_context)(struct inode *, void *, size_t);
+ int (*set_context)(struct inode *, const void *, size_t, void *);
+ bool (*dummy_context)(struct inode *);
+ bool (*empty_dir)(struct inode *);
+ unsigned (*max_namelen)(struct inode *);
+};
+
+struct fscrypt_ctx {
+ union {
+ struct {
+ struct page *bounce_page; /* Ciphertext page */
+ struct page *control_page; /* Original page */
+ } w;
+ struct {
+ struct bio *bio;
+ struct work_struct work;
+ } r;
+ struct list_head free_list; /* Free list */
+ };
+ u8 flags; /* Flags */
+};
+
+static inline bool fscrypt_has_encryption_key(const struct inode *inode)
+{
+ return (inode->i_crypt_info != NULL);
+}
+
+static inline bool fscrypt_dummy_context_enabled(struct inode *inode)
+{
+ return inode->i_sb->s_cop->dummy_context &&
+ inode->i_sb->s_cop->dummy_context(inode);
+}
+
/* crypto.c */
-extern struct kmem_cache *fscrypt_info_cachep;
+extern void fscrypt_enqueue_decrypt_work(struct work_struct *);
extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t);
extern void fscrypt_release_ctx(struct fscrypt_ctx *);
extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *,
@@ -19,6 +66,12 @@
u64, gfp_t);
extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int,
unsigned int, u64);
+
+static inline struct page *fscrypt_control_page(struct page *page)
+{
+ return ((struct fscrypt_ctx *)page_private(page))->w.control_page;
+}
+
extern void fscrypt_restore_control_page(struct page *);
extern const struct dentry_operations fscrypt_d_ops;
@@ -43,7 +96,7 @@
void *, bool);
/* keyinfo.c */
extern int fscrypt_get_encryption_info(struct inode *);
-extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *);
+extern void fscrypt_put_encryption_info(struct inode *);
/* fname.c */
extern int fscrypt_setup_filename(struct inode *, const struct qstr *,
@@ -54,14 +107,11 @@
kfree(fname->crypto_buf.name);
}
-extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32);
extern int fscrypt_fname_alloc_buffer(const struct inode *, u32,
struct fscrypt_str *);
extern void fscrypt_fname_free_buffer(struct fscrypt_str *);
extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32,
const struct fscrypt_str *, struct fscrypt_str *);
-extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *,
- struct fscrypt_str *);
#define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32
@@ -138,7 +188,9 @@
}
/* bio.c */
-extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *);
+extern void fscrypt_decrypt_bio(struct bio *);
+extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx,
+ struct bio *bio);
extern void fscrypt_pullback_bio_page(struct page **, bool);
extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t,
unsigned int);
@@ -152,5 +204,14 @@
struct dentry *new_dentry,
unsigned int flags);
extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry);
+extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len,
+ unsigned int max_len,
+ struct fscrypt_str *disk_link);
+extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target,
+ unsigned int len,
+ struct fscrypt_str *disk_link);
+extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,
+ unsigned int max_size,
+ struct delayed_call *done);
#endif /* _LINUX_FSCRYPT_SUPP_H */
diff --git a/include/linux/hid.h b/include/linux/hid.h
index b2ec827..fab65b6 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -801,7 +801,7 @@
extern void hidinput_disconnect(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
-int hid_input_report(struct hid_device *, int type, u8 *, int, int);
+int hid_input_report(struct hid_device *, int type, u8 *, u32, int);
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid);
@@ -1106,13 +1106,13 @@
*
* @report: the report we want to know the length
*/
-static inline int hid_report_len(struct hid_report *report)
+static inline u32 hid_report_len(struct hid_report *report)
{
/* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
return ((report->size - 1) >> 3) + 1 + (report->id > 0);
}
-int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
int interrupt);
/* HID quirks API */
diff --git a/include/linux/init.h b/include/linux/init.h
index 906ec32..d4b13a4 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -133,6 +133,9 @@
void __init load_default_modules(void);
int __init init_rootfs(void);
+#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX)
+extern bool rodata_enabled;
+#endif
#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
#endif
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 589d14e..c2a0f00 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -1,6 +1,7 @@
#ifndef _LINUX_JIFFIES_H
#define _LINUX_JIFFIES_H
+#include <linux/cache.h>
#include <linux/math64.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -63,19 +64,17 @@
/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
-/* some arch's have a small-data section that can be accessed register-relative
- * but that can only take up to, say, 4-byte variables. jiffies being part of
- * an 8-byte variable may not be correctly accessed unless we force the issue
- */
-#define __jiffy_data __attribute__((section(".data")))
+#ifndef __jiffy_arch_data
+#define __jiffy_arch_data
+#endif
/*
* The 64-bit value is not atomic - you MUST NOT read it
* without sampling the sequence number in jiffies_lock.
* get_jiffies_64() will do this for you as appropriate.
*/
-extern u64 __jiffy_data jiffies_64;
-extern unsigned long volatile __jiffy_data jiffies;
+extern u64 __cacheline_aligned_in_smp jiffies_64;
+extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies;
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void);
diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h
index b4ee8f6..8e2828d 100644
--- a/include/linux/mlx4/qp.h
+++ b/include/linux/mlx4/qp.h
@@ -470,6 +470,7 @@
u16 rate_val;
};
+struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn);
int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn,
enum mlx4_update_qp_attr attr,
struct mlx4_update_qp_params *params);
diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h
index 5827614..5f3e622 100644
--- a/include/linux/mlx5/device.h
+++ b/include/linux/mlx5/device.h
@@ -750,8 +750,14 @@
};
enum {
- CQE_RSS_HTYPE_IP = 0x3 << 6,
- CQE_RSS_HTYPE_L4 = 0x3 << 2,
+ CQE_RSS_HTYPE_IP = 0x3 << 2,
+ /* cqe->rss_hash_type[3:2] - IP destination selected for hash
+ * (00 = none, 01 = IPv4, 10 = IPv6, 11 = Reserved)
+ */
+ CQE_RSS_HTYPE_L4 = 0x3 << 6,
+ /* cqe->rss_hash_type[7:6] - L4 destination selected for hash
+ * (00 = none, 01 = TCP. 10 = UDP, 11 = IPSEC.SPI
+ */
};
enum {
diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h
index 6e0b439..81e7e75 100644
--- a/include/linux/msm_gsi.h
+++ b/include/linux/msm_gsi.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
+/* 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
@@ -219,6 +219,11 @@
GSI_TWO_PREFETCH_SEG = 0x1
};
+enum gsi_prefetch_mode {
+ GSI_USE_PREFETCH_BUFS = 0x0,
+ GSI_ESCAPE_BUF_ONLY = 0x1
+};
+
enum gsi_chan_evt {
GSI_CHAN_EVT_INVALID = 0x0,
GSI_CHAN_EVT_SUCCESS = 0x1,
@@ -357,6 +362,7 @@
enum gsi_chan_use_db_eng use_db_eng;
enum gsi_max_prefetch max_prefetch;
uint8_t low_weight;
+ enum gsi_prefetch_mode prefetch_mode;
void (*xfer_cb)(struct gsi_chan_xfer_notify *notify);
void (*err_cb)(struct gsi_chan_err_notify *notify);
void *chan_user_data;
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index 9bfeb88..69111fa 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -254,6 +254,8 @@
bool xt_find_jump_offset(const unsigned int *offsets,
unsigned int target, unsigned int size);
+int xt_check_proc_name(const char *name, unsigned int size);
+
int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto,
bool inv_proto);
int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto,
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1b71179..3652290 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1348,9 +1348,9 @@
unsigned int min_vecs, unsigned int max_vecs,
unsigned int flags)
{
- if (min_vecs > 1)
- return -EINVAL;
- return 1;
+ if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1 && dev->irq)
+ return 1;
+ return -ENOSPC;
}
static inline void pci_free_irq_vectors(struct pci_dev *dev)
{
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 2fb9f03..78c2a9f 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -282,6 +282,10 @@
POWER_SUPPLY_PROP_ALLOW_HVDCP3,
POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED,
POWER_SUPPLY_PROP_MAX_PULSE_ALLOWED,
+ POWER_SUPPLY_PROP_IGNORE_FALSE_NEGATIVE_ISENSE,
+ POWER_SUPPLY_PROP_BATTERY_INFO,
+ POWER_SUPPLY_PROP_BATTERY_INFO_ID,
+ POWER_SUPPLY_PROP_ENABLE_JEITA_DETECTION,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index b97bf2e..b326d0a 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -74,6 +74,12 @@
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_PROC_UID
+extern void proc_register_uid(kuid_t uid);
+#else
+static inline void proc_register_uid(kuid_t uid) {}
+#endif
+
struct net;
static inline struct proc_dir_entry *proc_net_mkdir(
diff --git a/include/linux/psci.h b/include/linux/psci.h
index 6306ab1..347077c 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -25,6 +25,17 @@
int psci_cpu_init_idle(unsigned int cpu);
int psci_cpu_suspend_enter(unsigned long index);
+enum psci_conduit {
+ PSCI_CONDUIT_NONE,
+ PSCI_CONDUIT_SMC,
+ PSCI_CONDUIT_HVC,
+};
+
+enum smccc_version {
+ SMCCC_VERSION_1_0,
+ SMCCC_VERSION_1_1,
+};
+
struct psci_operations {
u32 (*get_version)(void);
int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -34,6 +45,8 @@
int (*affinity_info)(unsigned long target_affinity,
unsigned long lowest_affinity_level);
int (*migrate_info_type)(void);
+ enum psci_conduit conduit;
+ enum smccc_version smccc_version;
};
extern struct psci_operations psci_ops;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4b2a1bc..0748b7b 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1664,6 +1664,7 @@
u64 dl_deadline; /* relative deadline of each instance */
u64 dl_period; /* separation of two instances (period) */
u64 dl_bw; /* dl_runtime / dl_deadline */
+ u64 dl_density; /* dl_runtime / dl_deadline */
/*
* Actual scheduling parameters. Initialized with the values above,
@@ -1913,6 +1914,10 @@
cputime_t utime, stime, utimescaled, stimescaled;
cputime_t gtime;
+#ifdef CONFIG_CPU_FREQ_TIMES
+ u64 *time_in_state;
+ unsigned int max_state;
+#endif
struct prev_cputime prev_cputime;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
seqcount_t vtime_seqcount;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index c73bef9..3fbfe96 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -988,10 +988,10 @@
unsigned int headroom);
struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom,
int newtailroom, gfp_t priority);
-int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
- int offset, int len);
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset,
- int len);
+int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
+ int offset, int len);
+int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg,
+ int offset, int len);
int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
int skb_pad(struct sk_buff *skb, int pad);
#define dev_kfree_skb(a) consume_skb(a)
diff --git a/include/linux/tty.h b/include/linux/tty.h
index a41244f..6f1ee85 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -355,6 +355,7 @@
#define TTY_PTY_LOCK 16 /* pty private */
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
#define TTY_HUPPED 18 /* Post driver->hangup() */
+#define TTY_HUPPING 19 /* Hangup in progress */
#define TTY_LDISC_HALTED 22 /* Line discipline is halted */
/* Values for tty->flow_change */
diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h
index b37f8df..05fb7b5 100644
--- a/include/linux/wcnss_wlan.h
+++ b/include/linux/wcnss_wlan.h
@@ -63,6 +63,13 @@
WCNSS_WLAN_MAX_GPIO,
};
+enum wcnss_log_type {
+ ERR,
+ WARN,
+ INFO,
+ DBG,
+};
+
#define WCNSS_VBATT_THRESHOLD 3500000
#define WCNSS_VBATT_GUARD 20000
#define WCNSS_VBATT_HIGH 3700000
@@ -145,6 +152,7 @@
void wcnss_snoc_vote(bool clk_chk_en);
int wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config,
struct device *dev);
+void wcnss_log(enum wcnss_log_type type, const char *_fmt, ...);
#ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE
void wcnss_log_debug_regs_on_bite(void);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 554671c..4931787 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -893,7 +893,7 @@
u16 conn_timeout);
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
- u8 role);
+ u8 role, bdaddr_t *direct_rpa);
struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 520c4c3..f656728 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -64,6 +64,9 @@
/* Indicate backport support for external authentication*/
#define CFG80211_EXTERNAL_AUTH_SUPPORT 1
+/* Indicate backport support for processing user cell base hint */
+#define CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED 1
+
/**
* DOC: Introduction
*
@@ -1011,9 +1014,9 @@
* @RATE_INFO_BW_160: 160 MHz bandwidth
*/
enum rate_info_bw {
+ RATE_INFO_BW_20 = 0,
RATE_INFO_BW_5,
RATE_INFO_BW_10,
- RATE_INFO_BW_20,
RATE_INFO_BW_40,
RATE_INFO_BW_80,
RATE_INFO_BW_160,
diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h
index 8716d59..8fcf890 100644
--- a/include/net/slhc_vj.h
+++ b/include/net/slhc_vj.h
@@ -127,6 +127,7 @@
*/
struct cstate {
byte_t cs_this; /* connection id number (xmit) */
+ bool initialized; /* true if initialized */
struct cstate *next; /* next in ring (xmit) */
struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */
struct tcphdr cs_tcp;
diff --git a/include/net/x25.h b/include/net/x25.h
index c383aa4..6d30a01 100644
--- a/include/net/x25.h
+++ b/include/net/x25.h
@@ -298,10 +298,10 @@
/* sysctl_net_x25.c */
#ifdef CONFIG_SYSCTL
-void x25_register_sysctl(void);
+int x25_register_sysctl(void);
void x25_unregister_sysctl(void);
#else
-static inline void x25_register_sysctl(void) {};
+static inline int x25_register_sysctl(void) { return 0; };
static inline void x25_unregister_sysctl(void) {};
#endif /* CONFIG_SYSCTL */
diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h
index 818a38f..f888263 100644
--- a/include/rdma/ib_addr.h
+++ b/include/rdma/ib_addr.h
@@ -129,6 +129,8 @@
const unsigned char *dst_dev_addr);
int rdma_addr_size(struct sockaddr *addr);
+int rdma_addr_size_in6(struct sockaddr_in6 *addr);
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id);
int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h
index 0cd4c1147..226f915 100644
--- a/include/soc/fsl/qe/qe.h
+++ b/include/soc/fsl/qe/qe.h
@@ -668,6 +668,10 @@
#define UCC_FAST_GUMR_CTSS 0x00800000
#define UCC_FAST_GUMR_TXSY 0x00020000
#define UCC_FAST_GUMR_RSYN 0x00010000
+#define UCC_FAST_GUMR_SYNL_MASK 0x0000C000
+#define UCC_FAST_GUMR_SYNL_16 0x0000C000
+#define UCC_FAST_GUMR_SYNL_8 0x00008000
+#define UCC_FAST_GUMR_SYNL_AUTO 0x00004000
#define UCC_FAST_GUMR_RTSM 0x00002000
#define UCC_FAST_GUMR_REVD 0x00000400
#define UCC_FAST_GUMR_ENR 0x00000020
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h
index 760c969..12bbf8c 100644
--- a/include/sound/pcm_oss.h
+++ b/include/sound/pcm_oss.h
@@ -57,6 +57,7 @@
char *buffer; /* vmallocated period */
size_t buffer_used; /* used length from period buffer */
struct mutex params_lock;
+ atomic_t rw_ref; /* concurrent read/write accesses */
#ifdef CONFIG_SND_PCM_OSS_PLUGINS
struct snd_pcm_plugin *plugin_first;
struct snd_pcm_plugin *plugin_last;
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index e06df4d..b355ebf 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -713,10 +713,10 @@
TRACE_EVENT(sched_task_util,
TP_PROTO(struct task_struct *p, int next_cpu, int backup_cpu,
- int target_cpu, bool sync, bool need_idle,
+ int target_cpu, bool sync, bool need_idle, int fastpath,
bool placement_boost, int rtg_cpu, u64 start_t),
- TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle,
+ TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle, fastpath,
placement_boost, rtg_cpu, start_t),
TP_STRUCT__entry(
@@ -729,6 +729,7 @@
__field(int, target_cpu )
__field(bool, sync )
__field(bool, need_idle )
+ __field(int, fastpath )
__field(bool, placement_boost )
__field(int, rtg_cpu )
__field(u64, latency )
@@ -744,13 +745,14 @@
__entry->target_cpu = target_cpu;
__entry->sync = sync;
__entry->need_idle = need_idle;
+ __entry->fastpath = fastpath;
__entry->placement_boost = placement_boost;
__entry->rtg_cpu = rtg_cpu;
__entry->latency = (sched_clock() - start_t);
),
- TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d placement_boost=%d rtg_cpu=%d latency=%llu",
- __entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle, __entry->placement_boost, __entry->rtg_cpu, __entry->latency)
+ TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d fastpath=%d placement_boost=%d rtg_cpu=%d latency=%llu",
+ __entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle, __entry->fastpath, __entry->placement_boost, __entry->rtg_cpu, __entry->latency)
);
#endif
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index c9248e5a..5da3634 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -472,6 +472,8 @@
header-y += v4l2-dv-timings.h
header-y += v4l2-mediabus.h
header-y += v4l2-subdev.h
+header-y += msm_vidc_dec.h
+header-y += msm_vidc_enc.h
header-y += veth.h
header-y += vfio.h
header-y += vhost.h
diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h
index beed138..f85ed3a 100644
--- a/include/uapi/linux/fcntl.h
+++ b/include/uapi/linux/fcntl.h
@@ -43,6 +43,27 @@
/* (1U << 31) is reserved for signed error codes */
/*
+ * Set/Get write life time hints. {GET,SET}_RW_HINT operate on the
+ * underlying inode, while {GET,SET}_FILE_RW_HINT operate only on
+ * the specific file.
+ */
+#define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11)
+#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12)
+#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13)
+#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14)
+
+/*
+ * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be
+ * used to clear any hints previously set.
+ */
+#define RWF_WRITE_LIFE_NOT_SET 0
+#define RWH_WRITE_LIFE_NONE 1
+#define RWH_WRITE_LIFE_SHORT 2
+#define RWH_WRITE_LIFE_MEDIUM 3
+#define RWH_WRITE_LIFE_LONG 4
+#define RWH_WRITE_LIFE_EXTREME 5
+
+/*
* Types of directory notifications that may be requested.
*/
#define DN_ACCESS 0x00000001 /* File accessed */
diff --git a/include/uapi/linux/msm_vidc_dec.h b/include/uapi/linux/msm_vidc_dec.h
new file mode 100644
index 0000000..46af82b
--- /dev/null
+++ b/include/uapi/linux/msm_vidc_dec.h
@@ -0,0 +1,629 @@
+#ifndef _UAPI_MSM_VIDC_DEC_H_
+#define _UAPI_MSM_VIDC_DEC_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* STATUS CODES */
+/* Base value for status codes */
+#define VDEC_S_BASE 0x40000000
+/* Success */
+#define VDEC_S_SUCCESS (VDEC_S_BASE)
+/* General failure */
+#define VDEC_S_EFAIL (VDEC_S_BASE + 1)
+/* Fatal irrecoverable failure. Need to tear down session. */
+#define VDEC_S_EFATAL (VDEC_S_BASE + 2)
+/* Error detected in the passed parameters */
+#define VDEC_S_EBADPARAM (VDEC_S_BASE + 3)
+/* Command called in invalid state. */
+#define VDEC_S_EINVALSTATE (VDEC_S_BASE + 4)
+ /* Insufficient OS resources - thread, memory etc. */
+#define VDEC_S_ENOSWRES (VDEC_S_BASE + 5)
+ /* Insufficient HW resources - core capacity maxed out. */
+#define VDEC_S_ENOHWRES (VDEC_S_BASE + 6)
+/* Invalid command called */
+#define VDEC_S_EINVALCMD (VDEC_S_BASE + 7)
+/* Command timeout. */
+#define VDEC_S_ETIMEOUT (VDEC_S_BASE + 8)
+/* Pre-requirement is not met for API. */
+#define VDEC_S_ENOPREREQ (VDEC_S_BASE + 9)
+/* Command queue is full. */
+#define VDEC_S_ECMDQFULL (VDEC_S_BASE + 10)
+/* Command is not supported by this driver */
+#define VDEC_S_ENOTSUPP (VDEC_S_BASE + 11)
+/* Command is not implemented by thedriver. */
+#define VDEC_S_ENOTIMPL (VDEC_S_BASE + 12)
+/* Command is not implemented by the driver. */
+#define VDEC_S_BUSY (VDEC_S_BASE + 13)
+#define VDEC_S_INPUT_BITSTREAM_ERR (VDEC_S_BASE + 14)
+
+#define VDEC_INTF_VER 1
+#define VDEC_MSG_BASE 0x0000000
+/*
+ *Codes to identify asynchronous message responses and events that driver
+ *wants to communicate to the app.
+ */
+#define VDEC_MSG_INVALID (VDEC_MSG_BASE + 0)
+#define VDEC_MSG_RESP_INPUT_BUFFER_DONE (VDEC_MSG_BASE + 1)
+#define VDEC_MSG_RESP_OUTPUT_BUFFER_DONE (VDEC_MSG_BASE + 2)
+#define VDEC_MSG_RESP_INPUT_FLUSHED (VDEC_MSG_BASE + 3)
+#define VDEC_MSG_RESP_OUTPUT_FLUSHED (VDEC_MSG_BASE + 4)
+#define VDEC_MSG_RESP_FLUSH_INPUT_DONE (VDEC_MSG_BASE + 5)
+#define VDEC_MSG_RESP_FLUSH_OUTPUT_DONE (VDEC_MSG_BASE + 6)
+#define VDEC_MSG_RESP_START_DONE (VDEC_MSG_BASE + 7)
+#define VDEC_MSG_RESP_STOP_DONE (VDEC_MSG_BASE + 8)
+#define VDEC_MSG_RESP_PAUSE_DONE (VDEC_MSG_BASE + 9)
+#define VDEC_MSG_RESP_RESUME_DONE (VDEC_MSG_BASE + 10)
+#define VDEC_MSG_RESP_RESOURCE_LOADED (VDEC_MSG_BASE + 11)
+#define VDEC_EVT_RESOURCES_LOST (VDEC_MSG_BASE + 12)
+#define VDEC_MSG_EVT_CONFIG_CHANGED (VDEC_MSG_BASE + 13)
+#define VDEC_MSG_EVT_HW_ERROR (VDEC_MSG_BASE + 14)
+#define VDEC_MSG_EVT_INFO_CONFIG_CHANGED (VDEC_MSG_BASE + 15)
+#define VDEC_MSG_EVT_INFO_FIELD_DROPPED (VDEC_MSG_BASE + 16)
+#define VDEC_MSG_EVT_HW_OVERLOAD (VDEC_MSG_BASE + 17)
+#define VDEC_MSG_EVT_MAX_CLIENTS (VDEC_MSG_BASE + 18)
+#define VDEC_MSG_EVT_HW_UNSUPPORTED (VDEC_MSG_BASE + 19)
+
+/*Buffer flags bits masks.*/
+#define VDEC_BUFFERFLAG_EOS 0x00000001
+#define VDEC_BUFFERFLAG_DECODEONLY 0x00000004
+#define VDEC_BUFFERFLAG_DATACORRUPT 0x00000008
+#define VDEC_BUFFERFLAG_ENDOFFRAME 0x00000010
+#define VDEC_BUFFERFLAG_SYNCFRAME 0x00000020
+#define VDEC_BUFFERFLAG_EXTRADATA 0x00000040
+#define VDEC_BUFFERFLAG_CODECCONFIG 0x00000080
+
+/*Post processing flags bit masks*/
+#define VDEC_EXTRADATA_NONE 0x001
+#define VDEC_EXTRADATA_QP 0x004
+#define VDEC_EXTRADATA_MB_ERROR_MAP 0x008
+#define VDEC_EXTRADATA_SEI 0x010
+#define VDEC_EXTRADATA_VUI 0x020
+#define VDEC_EXTRADATA_VC1 0x040
+
+#define VDEC_EXTRADATA_EXT_DATA 0x0800
+#define VDEC_EXTRADATA_USER_DATA 0x1000
+#define VDEC_EXTRADATA_EXT_BUFFER 0x2000
+
+#define VDEC_CMDBASE 0x800
+#define VDEC_CMD_SET_INTF_VERSION (VDEC_CMDBASE)
+
+#define VDEC_IOCTL_MAGIC 'v'
+
+struct vdec_ioctl_msg {
+ void __user *in;
+ void __user *out;
+};
+
+/*
+ * CMD params: InputParam:enum vdec_codec
+ * OutputParam: struct vdec_profile_level
+ */
+#define VDEC_IOCTL_GET_PROFILE_LEVEL_SUPPORTED \
+ _IOWR(VDEC_IOCTL_MAGIC, 0, struct vdec_ioctl_msg)
+
+/*
+ * CMD params:InputParam: NULL
+ * OutputParam: uint32_t(bitmask)
+ */
+#define VDEC_IOCTL_GET_INTERLACE_FORMAT \
+ _IOR(VDEC_IOCTL_MAGIC, 1, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: InputParam: enum vdec_codec
+ * OutputParam: struct vdec_profile_level
+ */
+#define VDEC_IOCTL_GET_CURRENT_PROFILE_LEVEL \
+ _IOWR(VDEC_IOCTL_MAGIC, 2, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam: enum vdec_output_fromat OutputParam: NULL
+ * GET: InputParam: NULL OutputParam: enum vdec_output_fromat
+ */
+#define VDEC_IOCTL_SET_OUTPUT_FORMAT \
+ _IOWR(VDEC_IOCTL_MAGIC, 3, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_OUTPUT_FORMAT \
+ _IOWR(VDEC_IOCTL_MAGIC, 4, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam: enum vdec_codec OutputParam: NULL
+ * GET: InputParam: NULL OutputParam: enum vdec_codec
+ */
+#define VDEC_IOCTL_SET_CODEC \
+ _IOW(VDEC_IOCTL_MAGIC, 5, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_CODEC \
+ _IOR(VDEC_IOCTL_MAGIC, 6, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam: struct vdec_picsize outputparam: NULL
+ * GET: InputParam: NULL outputparam: struct vdec_picsize
+ */
+#define VDEC_IOCTL_SET_PICRES \
+ _IOW(VDEC_IOCTL_MAGIC, 7, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_PICRES \
+ _IOR(VDEC_IOCTL_MAGIC, 8, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_EXTRADATA \
+ _IOW(VDEC_IOCTL_MAGIC, 9, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_EXTRADATA \
+ _IOR(VDEC_IOCTL_MAGIC, 10, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_SEQUENCE_HEADER \
+ _IOW(VDEC_IOCTL_MAGIC, 11, struct vdec_ioctl_msg)
+
+/*
+ * CMD params: SET: InputParam - vdec_allocatorproperty, OutputParam - NULL
+ * GET: InputParam - NULL, OutputParam - vdec_allocatorproperty
+ */
+#define VDEC_IOCTL_SET_BUFFER_REQ \
+ _IOW(VDEC_IOCTL_MAGIC, 12, struct vdec_ioctl_msg)
+#define VDEC_IOCTL_GET_BUFFER_REQ \
+ _IOR(VDEC_IOCTL_MAGIC, 13, struct vdec_ioctl_msg)
+/* CMD params: InputParam - vdec_buffer, OutputParam - uint8_t** */
+#define VDEC_IOCTL_ALLOCATE_BUFFER \
+ _IOWR(VDEC_IOCTL_MAGIC, 14, struct vdec_ioctl_msg)
+/* CMD params: InputParam - uint8_t *, OutputParam - NULL.*/
+#define VDEC_IOCTL_FREE_BUFFER \
+ _IOW(VDEC_IOCTL_MAGIC, 15, struct vdec_ioctl_msg)
+
+/*CMD params: CMD: InputParam - struct vdec_setbuffer_cmd, OutputParam - NULL*/
+#define VDEC_IOCTL_SET_BUFFER \
+ _IOW(VDEC_IOCTL_MAGIC, 16, struct vdec_ioctl_msg)
+
+/* CMD params: InputParam - struct vdec_fillbuffer_cmd, OutputParam - NULL*/
+#define VDEC_IOCTL_FILL_OUTPUT_BUFFER \
+ _IOW(VDEC_IOCTL_MAGIC, 17, struct vdec_ioctl_msg)
+
+/*CMD params: InputParam - struct vdec_frameinfo , OutputParam - NULL*/
+#define VDEC_IOCTL_DECODE_FRAME \
+ _IOW(VDEC_IOCTL_MAGIC, 18, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_LOAD_RESOURCES _IO(VDEC_IOCTL_MAGIC, 19)
+#define VDEC_IOCTL_CMD_START _IO(VDEC_IOCTL_MAGIC, 20)
+#define VDEC_IOCTL_CMD_STOP _IO(VDEC_IOCTL_MAGIC, 21)
+#define VDEC_IOCTL_CMD_PAUSE _IO(VDEC_IOCTL_MAGIC, 22)
+#define VDEC_IOCTL_CMD_RESUME _IO(VDEC_IOCTL_MAGIC, 23)
+
+/*CMD params: InputParam - enum vdec_bufferflush , OutputParam - NULL */
+#define VDEC_IOCTL_CMD_FLUSH _IOW(VDEC_IOCTL_MAGIC, 24, struct vdec_ioctl_msg)
+
+/* ========================================================
+ * IOCTL for getting asynchronous notification from driver
+ * ========================================================
+ */
+
+/*IOCTL params: InputParam - NULL, OutputParam - struct vdec_msginfo*/
+#define VDEC_IOCTL_GET_NEXT_MSG \
+ _IOR(VDEC_IOCTL_MAGIC, 25, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_STOP_NEXT_MSG _IO(VDEC_IOCTL_MAGIC, 26)
+
+#define VDEC_IOCTL_GET_NUMBER_INSTANCES \
+ _IOR(VDEC_IOCTL_MAGIC, 27, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_PICTURE_ORDER \
+ _IOW(VDEC_IOCTL_MAGIC, 28, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_FRAME_RATE \
+ _IOW(VDEC_IOCTL_MAGIC, 29, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_H264_MV_BUFFER \
+ _IOW(VDEC_IOCTL_MAGIC, 30, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_FREE_H264_MV_BUFFER \
+ _IOW(VDEC_IOCTL_MAGIC, 31, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_MV_BUFFER_SIZE \
+ _IOR(VDEC_IOCTL_MAGIC, 32, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_IDR_ONLY_DECODING \
+ _IO(VDEC_IOCTL_MAGIC, 33)
+
+#define VDEC_IOCTL_SET_CONT_ON_RECONFIG \
+ _IO(VDEC_IOCTL_MAGIC, 34)
+
+#define VDEC_IOCTL_SET_DISABLE_DMX \
+ _IOW(VDEC_IOCTL_MAGIC, 35, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_DISABLE_DMX \
+ _IOR(VDEC_IOCTL_MAGIC, 36, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_GET_DISABLE_DMX_SUPPORT \
+ _IOR(VDEC_IOCTL_MAGIC, 37, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_PERF_CLK \
+ _IOR(VDEC_IOCTL_MAGIC, 38, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_SET_META_BUFFERS \
+ _IOW(VDEC_IOCTL_MAGIC, 39, struct vdec_ioctl_msg)
+
+#define VDEC_IOCTL_FREE_META_BUFFERS \
+ _IO(VDEC_IOCTL_MAGIC, 40)
+
+enum vdec_picture {
+ PICTURE_TYPE_I,
+ PICTURE_TYPE_P,
+ PICTURE_TYPE_B,
+ PICTURE_TYPE_BI,
+ PICTURE_TYPE_SKIP,
+ PICTURE_TYPE_IDR,
+ PICTURE_TYPE_UNKNOWN
+};
+
+enum vdec_buffer {
+ VDEC_BUFFER_TYPE_INPUT,
+ VDEC_BUFFER_TYPE_OUTPUT
+};
+
+struct vdec_allocatorproperty {
+ enum vdec_buffer buffer_type;
+ uint32_t mincount;
+ uint32_t maxcount;
+ uint32_t actualcount;
+ size_t buffer_size;
+ uint32_t alignment;
+ uint32_t buf_poolid;
+ size_t meta_buffer_size;
+};
+
+struct vdec_bufferpayload {
+ void __user *bufferaddr;
+ size_t buffer_len;
+ int pmem_fd;
+ size_t offset;
+ size_t mmaped_size;
+};
+
+struct vdec_setbuffer_cmd {
+ enum vdec_buffer buffer_type;
+ struct vdec_bufferpayload buffer;
+};
+
+struct vdec_fillbuffer_cmd {
+ struct vdec_bufferpayload buffer;
+ void *client_data;
+};
+
+enum vdec_bufferflush {
+ VDEC_FLUSH_TYPE_INPUT,
+ VDEC_FLUSH_TYPE_OUTPUT,
+ VDEC_FLUSH_TYPE_ALL
+};
+
+enum vdec_codec {
+ VDEC_CODECTYPE_H264 = 0x1,
+ VDEC_CODECTYPE_H263 = 0x2,
+ VDEC_CODECTYPE_MPEG4 = 0x3,
+ VDEC_CODECTYPE_DIVX_3 = 0x4,
+ VDEC_CODECTYPE_DIVX_4 = 0x5,
+ VDEC_CODECTYPE_DIVX_5 = 0x6,
+ VDEC_CODECTYPE_DIVX_6 = 0x7,
+ VDEC_CODECTYPE_XVID = 0x8,
+ VDEC_CODECTYPE_MPEG1 = 0x9,
+ VDEC_CODECTYPE_MPEG2 = 0xa,
+ VDEC_CODECTYPE_VC1 = 0xb,
+ VDEC_CODECTYPE_VC1_RCV = 0xc,
+ VDEC_CODECTYPE_HEVC = 0xd,
+ VDEC_CODECTYPE_MVC = 0xe,
+ VDEC_CODECTYPE_VP8 = 0xf,
+ VDEC_CODECTYPE_VP9 = 0x10,
+};
+
+enum vdec_mpeg2_profile {
+ VDEC_MPEG2ProfileSimple = 0x1,
+ VDEC_MPEG2ProfileMain = 0x2,
+ VDEC_MPEG2Profile422 = 0x4,
+ VDEC_MPEG2ProfileSNR = 0x8,
+ VDEC_MPEG2ProfileSpatial = 0x10,
+ VDEC_MPEG2ProfileHigh = 0x20,
+ VDEC_MPEG2ProfileKhronosExtensions = 0x6F000000,
+ VDEC_MPEG2ProfileVendorStartUnused = 0x7F000000,
+ VDEC_MPEG2ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg2_level {
+
+ VDEC_MPEG2LevelLL = 0x1,
+ VDEC_MPEG2LevelML = 0x2,
+ VDEC_MPEG2LevelH14 = 0x4,
+ VDEC_MPEG2LevelHL = 0x8,
+ VDEC_MPEG2LevelKhronosExtensions = 0x6F000000,
+ VDEC_MPEG2LevelVendorStartUnused = 0x7F000000,
+ VDEC_MPEG2LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg4_profile {
+ VDEC_MPEG4ProfileSimple = 0x01,
+ VDEC_MPEG4ProfileSimpleScalable = 0x02,
+ VDEC_MPEG4ProfileCore = 0x04,
+ VDEC_MPEG4ProfileMain = 0x08,
+ VDEC_MPEG4ProfileNbit = 0x10,
+ VDEC_MPEG4ProfileScalableTexture = 0x20,
+ VDEC_MPEG4ProfileSimpleFace = 0x40,
+ VDEC_MPEG4ProfileSimpleFBA = 0x80,
+ VDEC_MPEG4ProfileBasicAnimated = 0x100,
+ VDEC_MPEG4ProfileHybrid = 0x200,
+ VDEC_MPEG4ProfileAdvancedRealTime = 0x400,
+ VDEC_MPEG4ProfileCoreScalable = 0x800,
+ VDEC_MPEG4ProfileAdvancedCoding = 0x1000,
+ VDEC_MPEG4ProfileAdvancedCore = 0x2000,
+ VDEC_MPEG4ProfileAdvancedScalable = 0x4000,
+ VDEC_MPEG4ProfileAdvancedSimple = 0x8000,
+ VDEC_MPEG4ProfileKhronosExtensions = 0x6F000000,
+ VDEC_MPEG4ProfileVendorStartUnused = 0x7F000000,
+ VDEC_MPEG4ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_mpeg4_level {
+ VDEC_MPEG4Level0 = 0x01,
+ VDEC_MPEG4Level0b = 0x02,
+ VDEC_MPEG4Level1 = 0x04,
+ VDEC_MPEG4Level2 = 0x08,
+ VDEC_MPEG4Level3 = 0x10,
+ VDEC_MPEG4Level4 = 0x20,
+ VDEC_MPEG4Level4a = 0x40,
+ VDEC_MPEG4Level5 = 0x80,
+ VDEC_MPEG4LevelKhronosExtensions = 0x6F000000,
+ VDEC_MPEG4LevelVendorStartUnused = 0x7F000000,
+ VDEC_MPEG4LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_avc_profile {
+ VDEC_AVCProfileBaseline = 0x01,
+ VDEC_AVCProfileMain = 0x02,
+ VDEC_AVCProfileExtended = 0x04,
+ VDEC_AVCProfileHigh = 0x08,
+ VDEC_AVCProfileHigh10 = 0x10,
+ VDEC_AVCProfileHigh422 = 0x20,
+ VDEC_AVCProfileHigh444 = 0x40,
+ VDEC_AVCProfileKhronosExtensions = 0x6F000000,
+ VDEC_AVCProfileVendorStartUnused = 0x7F000000,
+ VDEC_AVCProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_avc_level {
+ VDEC_AVCLevel1 = 0x01,
+ VDEC_AVCLevel1b = 0x02,
+ VDEC_AVCLevel11 = 0x04,
+ VDEC_AVCLevel12 = 0x08,
+ VDEC_AVCLevel13 = 0x10,
+ VDEC_AVCLevel2 = 0x20,
+ VDEC_AVCLevel21 = 0x40,
+ VDEC_AVCLevel22 = 0x80,
+ VDEC_AVCLevel3 = 0x100,
+ VDEC_AVCLevel31 = 0x200,
+ VDEC_AVCLevel32 = 0x400,
+ VDEC_AVCLevel4 = 0x800,
+ VDEC_AVCLevel41 = 0x1000,
+ VDEC_AVCLevel42 = 0x2000,
+ VDEC_AVCLevel5 = 0x4000,
+ VDEC_AVCLevel51 = 0x8000,
+ VDEC_AVCLevelKhronosExtensions = 0x6F000000,
+ VDEC_AVCLevelVendorStartUnused = 0x7F000000,
+ VDEC_AVCLevelMax = 0x7FFFFFFF
+};
+
+enum vdec_divx_profile {
+ VDEC_DIVXProfile_qMobile = 0x01,
+ VDEC_DIVXProfile_Mobile = 0x02,
+ VDEC_DIVXProfile_HD = 0x04,
+ VDEC_DIVXProfile_Handheld = 0x08,
+ VDEC_DIVXProfile_Portable = 0x10,
+ VDEC_DIVXProfile_HomeTheater = 0x20
+};
+
+enum vdec_xvid_profile {
+ VDEC_XVIDProfile_Simple = 0x1,
+ VDEC_XVIDProfile_Advanced_Realtime_Simple = 0x2,
+ VDEC_XVIDProfile_Advanced_Simple = 0x4
+};
+
+enum vdec_xvid_level {
+ VDEC_XVID_LEVEL_S_L0 = 0x1,
+ VDEC_XVID_LEVEL_S_L1 = 0x2,
+ VDEC_XVID_LEVEL_S_L2 = 0x4,
+ VDEC_XVID_LEVEL_S_L3 = 0x8,
+ VDEC_XVID_LEVEL_ARTS_L1 = 0x10,
+ VDEC_XVID_LEVEL_ARTS_L2 = 0x20,
+ VDEC_XVID_LEVEL_ARTS_L3 = 0x40,
+ VDEC_XVID_LEVEL_ARTS_L4 = 0x80,
+ VDEC_XVID_LEVEL_AS_L0 = 0x100,
+ VDEC_XVID_LEVEL_AS_L1 = 0x200,
+ VDEC_XVID_LEVEL_AS_L2 = 0x400,
+ VDEC_XVID_LEVEL_AS_L3 = 0x800,
+ VDEC_XVID_LEVEL_AS_L4 = 0x1000
+};
+
+enum vdec_h263profile {
+ VDEC_H263ProfileBaseline = 0x01,
+ VDEC_H263ProfileH320Coding = 0x02,
+ VDEC_H263ProfileBackwardCompatible = 0x04,
+ VDEC_H263ProfileISWV2 = 0x08,
+ VDEC_H263ProfileISWV3 = 0x10,
+ VDEC_H263ProfileHighCompression = 0x20,
+ VDEC_H263ProfileInternet = 0x40,
+ VDEC_H263ProfileInterlace = 0x80,
+ VDEC_H263ProfileHighLatency = 0x100,
+ VDEC_H263ProfileKhronosExtensions = 0x6F000000,
+ VDEC_H263ProfileVendorStartUnused = 0x7F000000,
+ VDEC_H263ProfileMax = 0x7FFFFFFF
+};
+
+enum vdec_h263level {
+ VDEC_H263Level10 = 0x01,
+ VDEC_H263Level20 = 0x02,
+ VDEC_H263Level30 = 0x04,
+ VDEC_H263Level40 = 0x08,
+ VDEC_H263Level45 = 0x10,
+ VDEC_H263Level50 = 0x20,
+ VDEC_H263Level60 = 0x40,
+ VDEC_H263Level70 = 0x80,
+ VDEC_H263LevelKhronosExtensions = 0x6F000000,
+ VDEC_H263LevelVendorStartUnused = 0x7F000000,
+ VDEC_H263LevelMax = 0x7FFFFFFF
+};
+
+enum vdec_wmv_format {
+ VDEC_WMVFormatUnused = 0x01,
+ VDEC_WMVFormat7 = 0x02,
+ VDEC_WMVFormat8 = 0x04,
+ VDEC_WMVFormat9 = 0x08,
+ VDEC_WMFFormatKhronosExtensions = 0x6F000000,
+ VDEC_WMFFormatVendorStartUnused = 0x7F000000,
+ VDEC_WMVFormatMax = 0x7FFFFFFF
+};
+
+enum vdec_vc1_profile {
+ VDEC_VC1ProfileSimple = 0x1,
+ VDEC_VC1ProfileMain = 0x2,
+ VDEC_VC1ProfileAdvanced = 0x4
+};
+
+enum vdec_vc1_level {
+ VDEC_VC1_LEVEL_S_Low = 0x1,
+ VDEC_VC1_LEVEL_S_Medium = 0x2,
+ VDEC_VC1_LEVEL_M_Low = 0x4,
+ VDEC_VC1_LEVEL_M_Medium = 0x8,
+ VDEC_VC1_LEVEL_M_High = 0x10,
+ VDEC_VC1_LEVEL_A_L0 = 0x20,
+ VDEC_VC1_LEVEL_A_L1 = 0x40,
+ VDEC_VC1_LEVEL_A_L2 = 0x80,
+ VDEC_VC1_LEVEL_A_L3 = 0x100,
+ VDEC_VC1_LEVEL_A_L4 = 0x200
+};
+
+struct vdec_profile_level {
+ uint32_t profiles;
+ uint32_t levels;
+};
+
+enum vdec_interlaced_format {
+ VDEC_InterlaceFrameProgressive = 0x1,
+ VDEC_InterlaceInterleaveFrameTopFieldFirst = 0x2,
+ VDEC_InterlaceInterleaveFrameBottomFieldFirst = 0x4
+};
+
+#define VDEC_YUV_FORMAT_NV12_TP10_UBWC \
+ VDEC_YUV_FORMAT_NV12_TP10_UBWC
+
+enum vdec_output_fromat {
+ VDEC_YUV_FORMAT_NV12 = 0x1,
+ VDEC_YUV_FORMAT_TILE_4x2 = 0x2,
+ VDEC_YUV_FORMAT_NV12_UBWC = 0x3,
+ VDEC_YUV_FORMAT_NV12_TP10_UBWC = 0x4
+};
+
+enum vdec_output_order {
+ VDEC_ORDER_DISPLAY = 0x1,
+ VDEC_ORDER_DECODE = 0x2
+};
+
+struct vdec_picsize {
+ uint32_t frame_width;
+ uint32_t frame_height;
+ uint32_t stride;
+ uint32_t scan_lines;
+};
+
+struct vdec_seqheader {
+ void __user *ptr_seqheader;
+ size_t seq_header_len;
+ int pmem_fd;
+ size_t pmem_offset;
+};
+
+struct vdec_mberror {
+ void __user *ptr_errormap;
+ size_t err_mapsize;
+};
+
+struct vdec_input_frameinfo {
+ void __user *bufferaddr;
+ size_t offset;
+ size_t datalen;
+ uint32_t flags;
+ int64_t timestamp;
+ void *client_data;
+ int pmem_fd;
+ size_t pmem_offset;
+ void __user *desc_addr;
+ uint32_t desc_size;
+};
+
+struct vdec_framesize {
+ uint32_t left;
+ uint32_t top;
+ uint32_t right;
+ uint32_t bottom;
+};
+
+struct vdec_aspectratioinfo {
+ uint32_t aspect_ratio;
+ uint32_t par_width;
+ uint32_t par_height;
+};
+
+struct vdec_sep_metadatainfo {
+ void __user *metabufaddr;
+ uint32_t size;
+ int fd;
+ int offset;
+ uint32_t buffer_size;
+};
+
+struct vdec_output_frameinfo {
+ void __user *bufferaddr;
+ size_t offset;
+ size_t len;
+ uint32_t flags;
+ int64_t time_stamp;
+ enum vdec_picture pic_type;
+ void *client_data;
+ void *input_frame_clientdata;
+ struct vdec_picsize picsize;
+ struct vdec_framesize framesize;
+ enum vdec_interlaced_format interlaced_format;
+ struct vdec_aspectratioinfo aspect_ratio_info;
+ struct vdec_sep_metadatainfo metadata_info;
+};
+
+union vdec_msgdata {
+ struct vdec_output_frameinfo output_frame;
+ void *input_frame_clientdata;
+};
+
+struct vdec_msginfo {
+ uint32_t status_code;
+ uint32_t msgcode;
+ union vdec_msgdata msgdata;
+ size_t msgdatasize;
+};
+
+struct vdec_framerate {
+ unsigned long fps_denominator;
+ unsigned long fps_numerator;
+};
+
+struct vdec_h264_mv {
+ size_t size;
+ int count;
+ int pmem_fd;
+ int offset;
+};
+
+struct vdec_mv_buff_size {
+ int width;
+ int height;
+ int size;
+ int alignment;
+};
+
+struct vdec_meta_buffers {
+ size_t size;
+ int count;
+ int pmem_fd;
+ int pmem_fd_iommu;
+ int offset;
+};
+
+#endif /* end of macro _VDECDECODER_H_ */
diff --git a/include/uapi/linux/msm_vidc_enc.h b/include/uapi/linux/msm_vidc_enc.h
new file mode 100644
index 0000000..f4f1630
--- /dev/null
+++ b/include/uapi/linux/msm_vidc_enc.h
@@ -0,0 +1,752 @@
+#ifndef _UAPI_MSM_VIDC_ENC_H_
+#define _UAPI_MSM_VIDC_ENC_H_
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/** STATUS CODES*/
+/* Base value for status codes */
+#define VEN_S_BASE 0x00000000
+#define VEN_S_SUCCESS (VEN_S_BASE)/* Success */
+#define VEN_S_EFAIL (VEN_S_BASE+1)/* General failure */
+#define VEN_S_EFATAL (VEN_S_BASE+2)/* Fatal irrecoverable failure*/
+#define VEN_S_EBADPARAM (VEN_S_BASE+3)/* Error passed parameters*/
+/*Command called in invalid state*/
+#define VEN_S_EINVALSTATE (VEN_S_BASE+4)
+#define VEN_S_ENOSWRES (VEN_S_BASE+5)/* Insufficient OS resources*/
+#define VEN_S_ENOHWRES (VEN_S_BASE+6)/*Insufficient HW resources */
+#define VEN_S_EBUFFREQ (VEN_S_BASE+7)/* Buffer requirements were not met*/
+#define VEN_S_EINVALCMD (VEN_S_BASE+8)/* Invalid command called */
+#define VEN_S_ETIMEOUT (VEN_S_BASE+9)/* Command timeout. */
+/*Re-attempt was made when multiple invocation not supported for API.*/
+#define VEN_S_ENOREATMPT (VEN_S_BASE+10)
+#define VEN_S_ENOPREREQ (VEN_S_BASE+11)/*Pre-requirement is not met for API*/
+#define VEN_S_ECMDQFULL (VEN_S_BASE+12)/*Command queue is full*/
+#define VEN_S_ENOTSUPP (VEN_S_BASE+13)/*Command not supported*/
+#define VEN_S_ENOTIMPL (VEN_S_BASE+14)/*Command not implemented.*/
+#define VEN_S_ENOTPMEM (VEN_S_BASE+15)/*Buffer is not from PMEM*/
+#define VEN_S_EFLUSHED (VEN_S_BASE+16)/*returned buffer was flushed*/
+#define VEN_S_EINSUFBUF (VEN_S_BASE+17)/*provided buffer size insufficient*/
+#define VEN_S_ESAMESTATE (VEN_S_BASE+18)
+#define VEN_S_EINVALTRANS (VEN_S_BASE+19)
+
+#define VEN_INTF_VER 1
+
+/*Asynchronous messages from driver*/
+#define VEN_MSG_INDICATION 0
+#define VEN_MSG_INPUT_BUFFER_DONE 1
+#define VEN_MSG_OUTPUT_BUFFER_DONE 2
+#define VEN_MSG_NEED_OUTPUT_BUFFER 3
+#define VEN_MSG_FLUSH_INPUT_DONE 4
+#define VEN_MSG_FLUSH_OUTPUT_DONE 5
+#define VEN_MSG_START 6
+#define VEN_MSG_STOP 7
+#define VEN_MSG_PAUSE 8
+#define VEN_MSG_RESUME 9
+#define VEN_MSG_STOP_READING_MSG 10
+#define VEN_MSG_LTRUSE_FAILED 11
+#define VEN_MSG_HW_OVERLOAD 12
+#define VEN_MSG_MAX_CLIENTS 13
+
+
+/*Buffer flags bits masks*/
+#define VEN_BUFFLAG_EOS 0x00000001
+#define VEN_BUFFLAG_ENDOFFRAME 0x00000010
+#define VEN_BUFFLAG_SYNCFRAME 0x00000020
+#define VEN_BUFFLAG_EXTRADATA 0x00000040
+#define VEN_BUFFLAG_CODECCONFIG 0x00000080
+
+/*Post processing flags bit masks*/
+#define VEN_EXTRADATA_NONE 0x001
+#define VEN_EXTRADATA_QCOMFILLER 0x002
+#define VEN_EXTRADATA_SLICEINFO 0x100
+#define VEN_EXTRADATA_LTRINFO 0x200
+#define VEN_EXTRADATA_MBINFO 0x400
+
+/*ENCODER CONFIGURATION CONSTANTS*/
+
+/*Encoded video frame types*/
+#define VEN_FRAME_TYPE_I 1/* I frame type */
+#define VEN_FRAME_TYPE_P 2/* P frame type */
+#define VEN_FRAME_TYPE_B 3/* B frame type */
+
+/*Video codec types*/
+#define VEN_CODEC_MPEG4 1/* MPEG4 Codec */
+#define VEN_CODEC_H264 2/* H.264 Codec */
+#define VEN_CODEC_H263 3/* H.263 Codec */
+
+/*Video codec profile types.*/
+#define VEN_PROFILE_MPEG4_SP 1/* 1 - MPEG4 SP profile */
+#define VEN_PROFILE_MPEG4_ASP 2/* 2 - MPEG4 ASP profile */
+#define VEN_PROFILE_H264_BASELINE 3/* 3 - H264 Baseline profile */
+#define VEN_PROFILE_H264_MAIN 4/* 4 - H264 Main profile */
+#define VEN_PROFILE_H264_HIGH 5/* 5 - H264 High profile */
+#define VEN_PROFILE_H263_BASELINE 6/* 6 - H263 Baseline profile */
+
+/*Video codec profile level types.*/
+#define VEN_LEVEL_MPEG4_0 0x1/* MPEG4 Level 0 */
+#define VEN_LEVEL_MPEG4_1 0x2/* MPEG4 Level 1 */
+#define VEN_LEVEL_MPEG4_2 0x3/* MPEG4 Level 2 */
+#define VEN_LEVEL_MPEG4_3 0x4/* MPEG4 Level 3 */
+#define VEN_LEVEL_MPEG4_4 0x5/* MPEG4 Level 4 */
+#define VEN_LEVEL_MPEG4_5 0x6/* MPEG4 Level 5 */
+#define VEN_LEVEL_MPEG4_3b 0x7/* MPEG4 Level 3b */
+#define VEN_LEVEL_MPEG4_6 0x8/* MPEG4 Level 6 */
+
+#define VEN_LEVEL_H264_1 0x9/* H.264 Level 1 */
+#define VEN_LEVEL_H264_1b 0xA/* H.264 Level 1b */
+#define VEN_LEVEL_H264_1p1 0xB/* H.264 Level 1.1 */
+#define VEN_LEVEL_H264_1p2 0xC/* H.264 Level 1.2 */
+#define VEN_LEVEL_H264_1p3 0xD/* H.264 Level 1.3 */
+#define VEN_LEVEL_H264_2 0xE/* H.264 Level 2 */
+#define VEN_LEVEL_H264_2p1 0xF/* H.264 Level 2.1 */
+#define VEN_LEVEL_H264_2p2 0x10/* H.264 Level 2.2 */
+#define VEN_LEVEL_H264_3 0x11/* H.264 Level 3 */
+#define VEN_LEVEL_H264_3p1 0x12/* H.264 Level 3.1 */
+#define VEN_LEVEL_H264_3p2 0x13/* H.264 Level 3.2 */
+#define VEN_LEVEL_H264_4 0x14/* H.264 Level 4 */
+
+#define VEN_LEVEL_H263_10 0x15/* H.263 Level 10 */
+#define VEN_LEVEL_H263_20 0x16/* H.263 Level 20 */
+#define VEN_LEVEL_H263_30 0x17/* H.263 Level 30 */
+#define VEN_LEVEL_H263_40 0x18/* H.263 Level 40 */
+#define VEN_LEVEL_H263_45 0x19/* H.263 Level 45 */
+#define VEN_LEVEL_H263_50 0x1A/* H.263 Level 50 */
+#define VEN_LEVEL_H263_60 0x1B/* H.263 Level 60 */
+#define VEN_LEVEL_H263_70 0x1C/* H.263 Level 70 */
+
+/*Entropy coding model selection for H.264 encoder.*/
+#define VEN_ENTROPY_MODEL_CAVLC 1
+#define VEN_ENTROPY_MODEL_CABAC 2
+/*Cabac model number (0,1,2) for encoder.*/
+#define VEN_CABAC_MODEL_0 1/* CABAC Model 0. */
+#define VEN_CABAC_MODEL_1 2/* CABAC Model 1. */
+#define VEN_CABAC_MODEL_2 3/* CABAC Model 2. */
+
+/*Deblocking filter control type for encoder.*/
+#define VEN_DB_DISABLE 1/* 1 - Disable deblocking filter*/
+#define VEN_DB_ALL_BLKG_BNDRY 2/* 2 - All blocking boundary filtering*/
+#define VEN_DB_SKIP_SLICE_BNDRY 3/* 3 - Filtering except sliceboundary*/
+
+/*Different methods of Multi slice selection.*/
+#define VEN_MSLICE_OFF 1
+#define VEN_MSLICE_CNT_MB 2 /*number of MBscount per slice*/
+#define VEN_MSLICE_CNT_BYTE 3 /*number of bytes count per slice.*/
+#define VEN_MSLICE_GOB 4 /*Multi slice by GOB for H.263 only.*/
+
+/*Different modes for Rate Control.*/
+#define VEN_RC_OFF 1
+#define VEN_RC_VBR_VFR 2
+#define VEN_RC_VBR_CFR 3
+#define VEN_RC_CBR_VFR 4
+#define VEN_RC_CBR_CFR 5
+
+/*Different modes for flushing buffers*/
+#define VEN_FLUSH_INPUT 1
+#define VEN_FLUSH_OUTPUT 2
+#define VEN_FLUSH_ALL 3
+
+/*Different input formats for YUV data.*/
+#define VEN_INPUTFMT_NV12 1/* NV12 Linear */
+#define VEN_INPUTFMT_NV21 2/* NV21 Linear */
+#define VEN_INPUTFMT_NV12_16M2KA 3/* NV12 Linear */
+
+/*Different allowed rotation modes.*/
+#define VEN_ROTATION_0 1/* 0 degrees */
+#define VEN_ROTATION_90 2/* 90 degrees */
+#define VEN_ROTATION_180 3/* 180 degrees */
+#define VEN_ROTATION_270 4/* 270 degrees */
+
+/*IOCTL timeout values*/
+#define VEN_TIMEOUT_INFINITE 0xffffffff
+
+/*Different allowed intra refresh modes.*/
+#define VEN_IR_OFF 1
+#define VEN_IR_CYCLIC 2
+#define VEN_IR_RANDOM 3
+
+/*IOCTL BASE CODES Not to be used directly by the client.*/
+/* Base value for ioctls that are not related to encoder configuration.*/
+#define VEN_IOCTLBASE_NENC 0x800
+/* Base value for encoder configuration ioctls*/
+#define VEN_IOCTLBASE_ENC 0x850
+
+struct venc_ioctl_msg {
+ void __user *in;
+ void __user *out;
+};
+
+/*NON ENCODER CONFIGURATION IOCTLs*/
+
+/*IOCTL params:SET: InputData - unsigned long, OutputData - NULL*/
+#define VEN_IOCTL_SET_INTF_VERSION \
+ _IOW(VEN_IOCTLBASE_NENC, 0, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_timeout, OutputData - venc_msg*/
+#define VEN_IOCTL_CMD_READ_NEXT_MSG \
+ _IOWR(VEN_IOCTLBASE_NENC, 1, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - NULL, OutputData - NULL*/
+#define VEN_IOCTL_CMD_STOP_READ_MSG _IO(VEN_IOCTLBASE_NENC, 2)
+
+/*
+ * IOCTL params:SET: InputData - venc_allocatorproperty, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_allocatorproperty
+ */
+#define VEN_IOCTL_SET_INPUT_BUFFER_REQ \
+ _IOW(VEN_IOCTLBASE_NENC, 3, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INPUT_BUFFER_REQ \
+ _IOR(VEN_IOCTLBASE_NENC, 4, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_ALLOC_INPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 5, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_SET_INPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 6, struct venc_ioctl_msg)
+
+/*IOCTL params: CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_FREE_INPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 7, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_allocatorproperty, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_allocatorproperty
+ */
+#define VEN_IOCTL_SET_OUTPUT_BUFFER_REQ \
+ _IOW(VEN_IOCTLBASE_NENC, 8, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_OUTPUT_BUFFER_REQ \
+ _IOR(VEN_IOCTLBASE_NENC, 9, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_CMD_ALLOC_OUTPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 10, struct venc_ioctl_msg)
+
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL*/
+#define VEN_IOCTL_SET_OUTPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 11, struct venc_ioctl_msg)
+
+/*IOCTL params:CMD: InputData - venc_bufferpayload, OutputData - NULL.*/
+#define VEN_IOCTL_CMD_FREE_OUTPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 12, struct venc_ioctl_msg)
+
+
+/* Asynchronous respone message code:* VEN_MSG_START*/
+#define VEN_IOCTL_CMD_START _IO(VEN_IOCTLBASE_NENC, 13)
+
+
+/*
+ * IOCTL params:CMD: InputData - venc_buffer, OutputData - NULL
+ * Asynchronous respone message code:VEN_MSG_INPUT_BUFFER_DONE
+ */
+#define VEN_IOCTL_CMD_ENCODE_FRAME \
+ _IOW(VEN_IOCTLBASE_NENC, 14, struct venc_ioctl_msg)
+
+
+/*
+ *IOCTL params:CMD: InputData - venc_buffer, OutputData - NULL
+ *Asynchronous response message code:VEN_MSG_OUTPUT_BUFFER_DONE
+ */
+#define VEN_IOCTL_CMD_FILL_OUTPUT_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 15, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:CMD: InputData - venc_bufferflush, OutputData - NULL
+ * Asynchronous response message code:VEN_MSG_INPUT_BUFFER_DONE
+ */
+#define VEN_IOCTL_CMD_FLUSH \
+ _IOW(VEN_IOCTLBASE_NENC, 16, struct venc_ioctl_msg)
+
+
+/*Asynchronous respone message code:VEN_MSG_PAUSE*/
+#define VEN_IOCTL_CMD_PAUSE _IO(VEN_IOCTLBASE_NENC, 17)
+
+/*Asynchronous respone message code:VEN_MSG_RESUME*/
+#define VEN_IOCTL_CMD_RESUME _IO(VEN_IOCTLBASE_NENC, 18)
+
+/* Asynchronous respone message code:VEN_MSG_STOP*/
+#define VEN_IOCTL_CMD_STOP _IO(VEN_IOCTLBASE_NENC, 19)
+
+#define VEN_IOCTL_SET_RECON_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 20, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_FREE_RECON_BUFFER \
+ _IOW(VEN_IOCTLBASE_NENC, 21, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_RECON_BUFFER_SIZE \
+ _IOW(VEN_IOCTLBASE_NENC, 22, struct venc_ioctl_msg)
+
+
+
+/*ENCODER PROPERTY CONFIGURATION & CAPABILITY IOCTLs*/
+
+/*
+ * IOCTL params:SET: InputData - venc_basecfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_basecfg
+ */
+#define VEN_IOCTL_SET_BASE_CFG \
+ _IOW(VEN_IOCTLBASE_ENC, 1, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_BASE_CFG \
+ _IOR(VEN_IOCTLBASE_ENC, 2, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_LIVE_MODE \
+ _IOW(VEN_IOCTLBASE_ENC, 3, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_LIVE_MODE \
+ _IOR(VEN_IOCTLBASE_ENC, 4, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_profile, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_profile
+ */
+#define VEN_IOCTL_SET_CODEC_PROFILE \
+ _IOW(VEN_IOCTLBASE_ENC, 5, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_CODEC_PROFILE \
+ _IOR(VEN_IOCTLBASE_ENC, 6, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - ven_profilelevel, OutputData - NULL
+ * GET: InputData - NULL, OutputData - ven_profilelevel
+ */
+#define VEN_IOCTL_SET_PROFILE_LEVEL \
+ _IOW(VEN_IOCTLBASE_ENC, 7, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_PROFILE_LEVEL \
+ _IOR(VEN_IOCTLBASE_ENC, 8, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_SHORT_HDR \
+ _IOW(VEN_IOCTLBASE_ENC, 9, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_SHORT_HDR \
+ _IOR(VEN_IOCTLBASE_ENC, 10, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params: SET: InputData - venc_sessionqp, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_sessionqp
+ */
+#define VEN_IOCTL_SET_SESSION_QP \
+ _IOW(VEN_IOCTLBASE_ENC, 11, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_SESSION_QP \
+ _IOR(VEN_IOCTLBASE_ENC, 12, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_intraperiod, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_intraperiod
+ */
+#define VEN_IOCTL_SET_INTRA_PERIOD \
+ _IOW(VEN_IOCTLBASE_ENC, 13, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INTRA_PERIOD \
+ _IOR(VEN_IOCTLBASE_ENC, 14, struct venc_ioctl_msg)
+
+
+/* Request an Iframe*/
+#define VEN_IOCTL_CMD_REQUEST_IFRAME _IO(VEN_IOCTLBASE_ENC, 15)
+
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_capability*/
+#define VEN_IOCTL_GET_CAPABILITY \
+ _IOR(VEN_IOCTLBASE_ENC, 16, struct venc_ioctl_msg)
+
+
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_seqheader*/
+#define VEN_IOCTL_GET_SEQUENCE_HDR \
+ _IOR(VEN_IOCTLBASE_ENC, 17, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_entropycfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_entropycfg
+ */
+#define VEN_IOCTL_SET_ENTROPY_CFG \
+ _IOW(VEN_IOCTLBASE_ENC, 18, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_ENTROPY_CFG \
+ _IOR(VEN_IOCTLBASE_ENC, 19, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_dbcfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_dbcfg
+ */
+#define VEN_IOCTL_SET_DEBLOCKING_CFG \
+ _IOW(VEN_IOCTLBASE_ENC, 20, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_DEBLOCKING_CFG \
+ _IOR(VEN_IOCTLBASE_ENC, 21, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_intrarefresh, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_intrarefresh
+ */
+#define VEN_IOCTL_SET_INTRA_REFRESH \
+ _IOW(VEN_IOCTLBASE_ENC, 22, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_INTRA_REFRESH \
+ _IOR(VEN_IOCTLBASE_ENC, 23, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_multiclicecfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_multiclicecfg
+ */
+#define VEN_IOCTL_SET_MULTI_SLICE_CFG \
+ _IOW(VEN_IOCTLBASE_ENC, 24, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_MULTI_SLICE_CFG \
+ _IOR(VEN_IOCTLBASE_ENC, 25, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_ratectrlcfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_ratectrlcfg
+ */
+#define VEN_IOCTL_SET_RATE_CTRL_CFG \
+ _IOW(VEN_IOCTLBASE_ENC, 26, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_RATE_CTRL_CFG \
+ _IOR(VEN_IOCTLBASE_ENC, 27, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_voptimingcfg, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_voptimingcfg
+ */
+#define VEN_IOCTL_SET_VOP_TIMING_CFG \
+ _IOW(VEN_IOCTLBASE_ENC, 28, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_VOP_TIMING_CFG \
+ _IOR(VEN_IOCTLBASE_ENC, 29, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_framerate, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_framerate
+ */
+#define VEN_IOCTL_SET_FRAME_RATE \
+ _IOW(VEN_IOCTLBASE_ENC, 30, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_FRAME_RATE \
+ _IOR(VEN_IOCTLBASE_ENC, 31, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_targetbitrate, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_targetbitrate
+ */
+#define VEN_IOCTL_SET_TARGET_BITRATE \
+ _IOW(VEN_IOCTLBASE_ENC, 32, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_TARGET_BITRATE \
+ _IOR(VEN_IOCTLBASE_ENC, 33, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_rotation, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_rotation
+ */
+#define VEN_IOCTL_SET_ROTATION \
+ _IOW(VEN_IOCTLBASE_ENC, 34, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_ROTATION \
+ _IOR(VEN_IOCTLBASE_ENC, 35, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_headerextension, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_headerextension
+ */
+#define VEN_IOCTL_SET_HEC \
+ _IOW(VEN_IOCTLBASE_ENC, 36, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_HEC \
+ _IOR(VEN_IOCTLBASE_ENC, 37, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_DATA_PARTITION \
+ _IOW(VEN_IOCTLBASE_ENC, 38, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_DATA_PARTITION \
+ _IOR(VEN_IOCTLBASE_ENC, 39, struct venc_ioctl_msg)
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_RVLC \
+ _IOW(VEN_IOCTLBASE_ENC, 40, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_RVLC \
+ _IOR(VEN_IOCTLBASE_ENC, 41, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_switch, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_switch
+ */
+#define VEN_IOCTL_SET_AC_PREDICTION \
+ _IOW(VEN_IOCTLBASE_ENC, 42, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_AC_PREDICTION \
+ _IOR(VEN_IOCTLBASE_ENC, 43, struct venc_ioctl_msg)
+
+
+/*
+ * IOCTL params:SET: InputData - venc_qprange, OutputData - NULL
+ * GET: InputData - NULL, OutputData - venc_qprange
+ */
+#define VEN_IOCTL_SET_QP_RANGE \
+ _IOW(VEN_IOCTLBASE_ENC, 44, struct venc_ioctl_msg)
+#define VEN_IOCTL_GET_QP_RANGE \
+ _IOR(VEN_IOCTLBASE_ENC, 45, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_GET_NUMBER_INSTANCES \
+ _IOR(VEN_IOCTLBASE_ENC, 46, struct venc_ioctl_msg)
+
+#define VEN_IOCTL_SET_METABUFFER_MODE \
+ _IOW(VEN_IOCTLBASE_ENC, 47, struct venc_ioctl_msg)
+
+
+/*IOCTL params:SET: InputData - unsigned int, OutputData - NULL.*/
+#define VEN_IOCTL_SET_EXTRADATA \
+ _IOW(VEN_IOCTLBASE_ENC, 48, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - unsigned int.*/
+#define VEN_IOCTL_GET_EXTRADATA \
+ _IOR(VEN_IOCTLBASE_ENC, 49, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - NULL, OutputData - NULL.*/
+#define VEN_IOCTL_SET_SLICE_DELIVERY_MODE \
+ _IO(VEN_IOCTLBASE_ENC, 50)
+
+#define VEN_IOCTL_SET_H263_PLUSPTYPE \
+ _IOW(VEN_IOCTLBASE_ENC, 51, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_range, OutputData - NULL.*/
+#define VEN_IOCTL_SET_CAPABILITY_LTRCOUNT \
+ _IOW(VEN_IOCTLBASE_ENC, 52, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_range.*/
+#define VEN_IOCTL_GET_CAPABILITY_LTRCOUNT \
+ _IOR(VEN_IOCTLBASE_ENC, 53, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmode, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMODE \
+ _IOW(VEN_IOCTLBASE_ENC, 54, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmode.*/
+#define VEN_IOCTL_GET_LTRMODE \
+ _IOR(VEN_IOCTLBASE_ENC, 55, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrcount, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRCOUNT \
+ _IOW(VEN_IOCTLBASE_ENC, 56, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrcount.*/
+#define VEN_IOCTL_GET_LTRCOUNT \
+ _IOR(VEN_IOCTLBASE_ENC, 57, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrperiod, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRPERIOD \
+ _IOW(VEN_IOCTLBASE_ENC, 58, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrperiod.*/
+#define VEN_IOCTL_GET_LTRPERIOD \
+ _IOR(VEN_IOCTLBASE_ENC, 59, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltruse, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRUSE \
+ _IOW(VEN_IOCTLBASE_ENC, 60, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltruse.*/
+#define VEN_IOCTL_GET_LTRUSE \
+ _IOR(VEN_IOCTLBASE_ENC, 61, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - venc_ltrmark, OutputData - NULL.*/
+#define VEN_IOCTL_SET_LTRMARK \
+ _IOW(VEN_IOCTLBASE_ENC, 62, struct venc_ioctl_msg)
+/*IOCTL params:GET: InputData - NULL, OutputData - venc_ltrmark.*/
+#define VEN_IOCTL_GET_LTRMARK \
+ _IOR(VEN_IOCTLBASE_ENC, 63, struct venc_ioctl_msg)
+
+/*IOCTL params:SET: InputData - unsigned int, OutputData - NULL*/
+#define VEN_IOCTL_SET_SPS_PPS_FOR_IDR \
+ _IOW(VEN_IOCTLBASE_ENC, 64, struct venc_ioctl_msg)
+
+struct venc_range {
+ unsigned long max;
+ unsigned long min;
+ unsigned long step_size;
+};
+
+struct venc_switch {
+ unsigned char status;
+};
+
+struct venc_allocatorproperty {
+ unsigned long mincount;
+ unsigned long maxcount;
+ unsigned long actualcount;
+ unsigned long datasize;
+ unsigned long suffixsize;
+ unsigned long alignment;
+ unsigned long bufpoolid;
+};
+
+struct venc_bufferpayload {
+ unsigned char *pbuffer;
+ size_t sz;
+ int fd;
+ unsigned int offset;
+ unsigned int maped_size;
+ unsigned long filled_len;
+};
+
+struct venc_buffer {
+ unsigned char *ptrbuffer;
+ unsigned long sz;
+ unsigned long len;
+ unsigned long offset;
+ long long timestamp;
+ unsigned long flags;
+ void *clientdata;
+};
+
+struct venc_basecfg {
+ unsigned long input_width;
+ unsigned long input_height;
+ unsigned long dvs_width;
+ unsigned long dvs_height;
+ unsigned long codectype;
+ unsigned long fps_num;
+ unsigned long fps_den;
+ unsigned long targetbitrate;
+ unsigned long inputformat;
+};
+
+struct venc_profile {
+ unsigned long profile;
+};
+struct ven_profilelevel {
+ unsigned long level;
+};
+
+struct venc_sessionqp {
+ unsigned long iframeqp;
+ unsigned long pframqp;
+};
+
+struct venc_qprange {
+ unsigned long maxqp;
+ unsigned long minqp;
+};
+
+struct venc_plusptype {
+ unsigned long plusptype_enable;
+};
+
+struct venc_intraperiod {
+ unsigned long num_pframes;
+ unsigned long num_bframes;
+};
+struct venc_seqheader {
+ unsigned char *hdrbufptr;
+ unsigned long bufsize;
+ unsigned long hdrlen;
+};
+
+struct venc_capability {
+ unsigned long codec_types;
+ unsigned long maxframe_width;
+ unsigned long maxframe_height;
+ unsigned long maxtarget_bitrate;
+ unsigned long maxframe_rate;
+ unsigned long input_formats;
+ unsigned char dvs;
+};
+
+struct venc_entropycfg {
+ unsigned int longentropysel;
+ unsigned long cabacmodel;
+};
+
+struct venc_dbcfg {
+ unsigned long db_mode;
+ unsigned long slicealpha_offset;
+ unsigned long slicebeta_offset;
+};
+
+struct venc_intrarefresh {
+ unsigned long irmode;
+ unsigned long mbcount;
+};
+
+struct venc_multiclicecfg {
+ unsigned long mslice_mode;
+ unsigned long mslice_size;
+};
+
+struct venc_bufferflush {
+ unsigned long flush_mode;
+};
+
+struct venc_ratectrlcfg {
+ unsigned long rcmode;
+};
+
+struct venc_voptimingcfg {
+ unsigned long voptime_resolution;
+};
+struct venc_framerate {
+ unsigned long fps_denominator;
+ unsigned long fps_numerator;
+};
+
+struct venc_targetbitrate {
+ unsigned long target_bitrate;
+};
+
+
+struct venc_rotation {
+ unsigned long rotation;
+};
+
+struct venc_timeout {
+ unsigned long millisec;
+};
+
+struct venc_headerextension {
+ unsigned long header_extension;
+};
+
+struct venc_msg {
+ unsigned long statuscode;
+ unsigned long msgcode;
+ struct venc_buffer buf;
+ unsigned long msgdata_size;
+};
+
+struct venc_recon_addr {
+ unsigned char *pbuffer;
+ unsigned long buffer_size;
+ unsigned long pmem_fd;
+ unsigned long offset;
+};
+
+struct venc_recon_buff_size {
+ int width;
+ int height;
+ int size;
+ int alignment;
+};
+
+struct venc_ltrmode {
+ unsigned long ltr_mode;
+};
+
+struct venc_ltrcount {
+ unsigned long ltr_count;
+};
+
+struct venc_ltrperiod {
+ unsigned long ltr_period;
+};
+
+struct venc_ltruse {
+ unsigned long ltr_id;
+ unsigned long ltr_frames;
+};
+
+#endif /* _UAPI_MSM_VIDC_ENC_H_ */
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 2c5810a..b67cfd8 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -106,7 +106,7 @@
#define PCI_SUBSYSTEM_ID 0x2e
#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */
#define PCI_ROM_ADDRESS_ENABLE 0x01
-#define PCI_ROM_ADDRESS_MASK (~0x7ffUL)
+#define PCI_ROM_ADDRESS_MASK (~0x7ffU)
#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */
diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
index 3d7a0fc..39930ca 100644
--- a/include/uapi/linux/psci.h
+++ b/include/uapi/linux/psci.h
@@ -87,6 +87,9 @@
(((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT)
#define PSCI_VERSION_MINOR(ver) \
((ver) & PSCI_VERSION_MINOR_MASK)
+#define PSCI_VERSION(maj, min) \
+ ((((maj) << PSCI_VERSION_MAJOR_SHIFT) & PSCI_VERSION_MAJOR_MASK) | \
+ ((min) & PSCI_VERSION_MINOR_MASK))
/* PSCI features decoding (>=1.0) */
#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1
diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h
index 54488ff..2c7b49a 100644
--- a/include/uapi/linux/qg.h
+++ b/include/uapi/linux/qg.h
@@ -12,8 +12,8 @@
QG_ESR,
QG_CHARGE_COUNTER,
QG_FIFO_TIME_DELTA,
- QG_RESERVED_1,
- QG_RESERVED_2,
+ QG_BATT_SOC,
+ QG_CC_SOC,
QG_RESERVED_3,
QG_RESERVED_4,
QG_RESERVED_5,
@@ -25,6 +25,9 @@
QG_MAX,
};
+#define QG_BATT_SOC QG_BATT_SOC
+#define QG_CC_SOC QG_CC_SOC
+
struct fifo_data {
unsigned int v;
unsigned int i;
diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h
index 3f93d16..b455b0d 100644
--- a/include/uapi/linux/random.h
+++ b/include/uapi/linux/random.h
@@ -34,6 +34,9 @@
/* Clear the entropy pool and associated counters. (Superuser only.) */
#define RNDCLEARPOOL _IO( 'R', 0x06 )
+/* Reseed CRNG. (Superuser only.) */
+#define RNDRESEEDCRNG _IO( 'R', 0x07 )
+
struct rand_pool_info {
int entropy_count;
int buf_size;
diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h
index 4f12e5c..3fd0c88 100644
--- a/include/uapi/media/msm_media_info.h
+++ b/include/uapi/media/msm_media_info.h
@@ -1229,6 +1229,7 @@
{
const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height);
unsigned int uv_alignment = 0, size = 0;
+ unsigned int w_alignment = 512;
unsigned int y_plane, uv_plane, y_stride,
uv_stride, y_sclines, uv_sclines;
unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0;
@@ -1252,6 +1253,17 @@
switch (color_fmt) {
case COLOR_FMT_NV21:
case COLOR_FMT_NV12:
+ uv_alignment = 4096;
+ y_plane = y_stride * y_sclines;
+ uv_plane = uv_stride * uv_sclines + uv_alignment;
+ size = y_plane + uv_plane +
+ MSM_MEDIA_MAX(extra_size, 8 * y_stride);
+ size = MSM_MEDIA_ALIGN(size, 4096);
+
+ /* Additional size to cover last row of non-aligned frame */
+ size += MSM_MEDIA_ALIGN(width, w_alignment) * w_alignment;
+ size = MSM_MEDIA_ALIGN(size, 4096);
+ break;
case COLOR_FMT_P010:
uv_alignment = 4096;
y_plane = y_stride * y_sclines;
@@ -1288,6 +1300,10 @@
uv_meta_plane)*2 +
MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride);
size = MSM_MEDIA_ALIGN(size, 4096);
+
+ /* Additional size to cover last row of non-aligned frame */
+ size += MSM_MEDIA_ALIGN(width, w_alignment) * w_alignment;
+ size = MSM_MEDIA_ALIGN(size, 4096);
break;
case COLOR_FMT_NV12_BPP10_UBWC:
y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
diff --git a/init/Kconfig b/init/Kconfig
index 854bd5d..e3929edd 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -840,6 +840,16 @@
13 => 8 KB
12 => 4 KB
+config CONSOLE_FLUSH_ON_HOTPLUG
+ bool "Enable console flush configurable in hot plug code path"
+ depends on HOTPLUG_CPU
+ def_bool n
+ help
+ In cpu hot plug path console lock acquire and release causes the
+ console to flush. If console lock is not free hot plug latency
+ increases. So make console flush configurable in hot plug path
+ and default disabled to help in cpu hot plug latencies.
+
config LOG_CPU_MAX_BUF_SHIFT
int "CPU kernel log buffer size contribution (13 => 8 KB, 17 => 128KB)"
depends on SMP
diff --git a/init/main.c b/init/main.c
index 17e439f..f9cd3f0 100644
--- a/init/main.c
+++ b/init/main.c
@@ -81,6 +81,7 @@
#include <linux/proc_ns.h>
#include <linux/io.h>
#include <linux/kaiser.h>
+#include <linux/cache.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -913,14 +914,16 @@
static noinline void __init kernel_init_freeable(void);
-#ifdef CONFIG_DEBUG_RODATA
-static bool rodata_enabled = true;
+#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_SET_MODULE_RONX)
+bool rodata_enabled __ro_after_init = true;
static int __init set_debug_rodata(char *str)
{
return strtobool(str, &rodata_enabled);
}
__setup("rodata=", set_debug_rodata);
+#endif
+#ifdef CONFIG_DEBUG_RODATA
static void mark_readonly(void)
{
if (rodata_enabled)
diff --git a/ipc/shm.c b/ipc/shm.c
index e2072ae..b626745 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -198,6 +198,12 @@
if (IS_ERR(shp))
return PTR_ERR(shp);
+ if (shp->shm_file != sfd->file) {
+ /* ID was reused */
+ shm_unlock(shp);
+ return -EINVAL;
+ }
+
shp->shm_atim = get_seconds();
shp->shm_lprid = task_tgid_vnr(current);
shp->shm_nattch++;
@@ -381,6 +387,17 @@
return sfd->vm_ops->fault(vma, vmf);
}
+static int shm_split(struct vm_area_struct *vma, unsigned long addr)
+{
+ struct file *file = vma->vm_file;
+ struct shm_file_data *sfd = shm_file_data(file);
+
+ if (sfd->vm_ops && sfd->vm_ops->split)
+ return sfd->vm_ops->split(vma, addr);
+
+ return 0;
+}
+
#ifdef CONFIG_NUMA
static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
{
@@ -414,8 +431,9 @@
int ret;
/*
- * In case of remap_file_pages() emulation, the file can represent
- * removed IPC ID: propogate shm_lock() error to caller.
+ * In case of remap_file_pages() emulation, the file can represent an
+ * IPC ID that was removed, and possibly even reused by another shm
+ * segment already. Propagate this case as an error to caller.
*/
ret =__shm_open(vma);
if (ret)
@@ -439,6 +457,7 @@
struct shm_file_data *sfd = shm_file_data(file);
put_ipc_ns(sfd->ns);
+ fput(sfd->file);
shm_file_data(file) = NULL;
kfree(sfd);
return 0;
@@ -503,6 +522,7 @@
.open = shm_open, /* callback for a new vm-area open */
.close = shm_close, /* callback for when the vm-area is released */
.fault = shm_fault,
+ .split = shm_split,
#if defined(CONFIG_NUMA)
.set_policy = shm_set_policy,
.get_policy = shm_get_policy,
@@ -1200,7 +1220,16 @@
file->f_mapping = shp->shm_file->f_mapping;
sfd->id = shp->shm_perm.id;
sfd->ns = get_ipc_ns(ns);
- sfd->file = shp->shm_file;
+ /*
+ * We need to take a reference to the real shm file to prevent the
+ * pointer from becoming stale in cases where the lifetime of the outer
+ * file extends beyond that of the shm segment. It's not usually
+ * possible, but it can happen during remap_file_pages() emulation as
+ * that unmaps the memory, then does ->mmap() via file reference only.
+ * We'll deny the ->mmap() if the shm segment was since removed, but to
+ * detect shm ID reuse we need to compare the file pointers.
+ */
+ sfd->file = get_file(shp->shm_file);
sfd->vm_ops = NULL;
err = security_mmap_file(file, prot, flags);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index c68d150..3f3b7f8 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -64,6 +64,12 @@
static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state);
+#if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP)
+static struct lock_class_key cpuhp_state_key;
+static struct lockdep_map cpuhp_state_lock_map =
+ STATIC_LOCKDEP_MAP_INIT("cpuhp_state", &cpuhp_state_key);
+#endif
+
/**
* cpuhp_step - Hotplug state machine step
* @name: Name of the step
@@ -572,6 +578,7 @@
st->should_run = false;
+ lock_map_acquire(&cpuhp_state_lock_map);
/* Single callback invocation for [un]install ? */
if (st->single) {
if (st->cb_state < CPUHP_AP_ONLINE) {
@@ -603,6 +610,7 @@
else if (st->state > st->target)
ret = cpuhp_ap_offline(cpu, st);
}
+ lock_map_release(&cpuhp_state_lock_map);
st->result = ret;
complete(&st->done);
}
@@ -617,6 +625,9 @@
if (!cpu_online(cpu))
return 0;
+ lock_map_acquire(&cpuhp_state_lock_map);
+ lock_map_release(&cpuhp_state_lock_map);
+
/*
* If we are up and running, use the hotplug thread. For early calls
* we invoke the thread function directly.
@@ -660,6 +671,8 @@
enum cpuhp_state state = st->state;
trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work);
+ lock_map_acquire(&cpuhp_state_lock_map);
+ lock_map_release(&cpuhp_state_lock_map);
__cpuhp_kick_ap_work(st);
wait_for_completion(&st->done);
trace_cpuhp_exit(cpu, st->state, state, st->result);
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index e9fdb52..411226b 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -227,12 +227,18 @@
}
if (regs) {
+ mm_segment_t fs;
+
if (crosstask)
goto exit_put;
if (add_mark)
perf_callchain_store_context(&ctx, PERF_CONTEXT_USER);
+
+ fs = get_fs();
+ set_fs(USER_DS);
perf_callchain_user(&ctx, regs);
+ set_fs(fs);
}
}
diff --git a/kernel/events/core.c b/kernel/events/core.c
index cd941f8..2ea4eb1 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4181,6 +4181,9 @@
if (event->ctx)
put_ctx(event->ctx);
+ if (event->hw.target)
+ put_task_struct(event->hw.target);
+
exclusive_event_destroy(event);
module_put(event->pmu->module);
@@ -5799,9 +5802,6 @@
__output_copy(handle, values, n * sizeof(u64));
}
-/*
- * XXX PERF_FORMAT_GROUP vs inherited events seems difficult.
- */
static void perf_output_read_group(struct perf_output_handle *handle,
struct perf_event *event,
u64 enabled, u64 running)
@@ -5846,6 +5846,13 @@
#define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\
PERF_FORMAT_TOTAL_TIME_RUNNING)
+/*
+ * XXX PERF_SAMPLE_READ vs inherited events seems difficult.
+ *
+ * The problem is that its both hard and excessively expensive to iterate the
+ * child list, not to mention that its impossible to IPI the children running
+ * on another CPU, from interrupt/NMI context.
+ */
static void perf_output_read(struct perf_output_handle *handle,
struct perf_event *event)
{
@@ -9462,6 +9469,7 @@
* and we cannot use the ctx information because we need the
* pmu before we get a ctx.
*/
+ get_task_struct(task);
event->hw.target = task;
}
@@ -9511,9 +9519,10 @@
local64_set(&hwc->period_left, hwc->sample_period);
/*
- * we currently do not support PERF_FORMAT_GROUP on inherited events
+ * We currently do not support PERF_SAMPLE_READ on inherited events.
+ * See perf_output_read().
*/
- if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP))
+ if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ))
goto err_ns;
if (!has_branch_stack(event))
@@ -9541,8 +9550,10 @@
event->addr_filters_offs = kcalloc(pmu->nr_addr_filters,
sizeof(unsigned long),
GFP_KERNEL);
- if (!event->addr_filters_offs)
+ if (!event->addr_filters_offs) {
+ err = -ENOMEM;
goto err_per_task;
+ }
/* force hw sync on the address filters */
event->addr_filters_gen = 1;
@@ -9576,6 +9587,8 @@
perf_detach_cgroup(event);
if (event->ns)
put_pid_ns(event->ns);
+ if (event->hw.target)
+ put_task_struct(event->hw.target);
kfree(event);
return ERR_PTR(err);
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index 3f8cb1e..253ae2d 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -427,16 +427,9 @@
* modify_user_hw_breakpoint - modify a user-space hardware breakpoint
* @bp: the breakpoint structure to modify
* @attr: new breakpoint attributes
- * @triggered: callback to trigger when we hit the breakpoint
- * @tsk: pointer to 'task_struct' of the process to which the address belongs
*/
int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr)
{
- u64 old_addr = bp->attr.bp_addr;
- u64 old_len = bp->attr.bp_len;
- int old_type = bp->attr.bp_type;
- int err = 0;
-
/*
* modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it
* will not be possible to raise IPIs that invoke __perf_event_disable.
@@ -451,27 +444,18 @@
bp->attr.bp_addr = attr->bp_addr;
bp->attr.bp_type = attr->bp_type;
bp->attr.bp_len = attr->bp_len;
+ bp->attr.disabled = 1;
- if (attr->disabled)
- goto end;
+ if (!attr->disabled) {
+ int err = validate_hw_breakpoint(bp);
- err = validate_hw_breakpoint(bp);
- if (!err)
+ if (err)
+ return err;
+
perf_event_enable(bp);
-
- if (err) {
- bp->attr.bp_addr = old_addr;
- bp->attr.bp_type = old_type;
- bp->attr.bp_len = old_len;
- if (!bp->attr.disabled)
- perf_event_enable(bp);
-
- return err;
+ bp->attr.disabled = 0;
}
-end:
- bp->attr.disabled = attr->disabled;
-
return 0;
}
EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint);
diff --git a/kernel/exit.c b/kernel/exit.c
index 2c2cc1a..4b4f03a 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -54,6 +54,7 @@
#include <linux/writeback.h>
#include <linux/shm.h>
#include <linux/kcov.h>
+#include <linux/cpufreq_times.h>
#include "sched/tune.h"
@@ -171,6 +172,9 @@
{
struct task_struct *leader;
int zap_leader;
+#ifdef CONFIG_CPU_FREQ_TIMES
+ cpufreq_task_times_exit(p);
+#endif
repeat:
/* don't need to get the RCU readlock here - the process is dead and
* can't be modifying its own credentials. But shut RCU-lockdep up */
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index c1195eb..c93d4df 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -853,7 +853,7 @@
* This code is triggered unconditionally. Check the affinity
* mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out.
*/
- if (desc->irq_common_data.affinity)
+ if (cpumask_available(desc->irq_common_data.affinity))
cpumask_copy(mask, desc->irq_common_data.affinity);
else
valid = false;
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index a1a07cf..6948518 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -125,7 +125,7 @@
return module_alloc(PAGE_SIZE);
}
-static void free_insn_page(void *page)
+void __weak free_insn_page(void *page)
{
module_memfree(page);
}
diff --git a/kernel/module.c b/kernel/module.c
index dec20c7..13ad2f8 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1911,6 +1911,9 @@
/* livepatching wants to disable read-only so it can frob module. */
void module_disable_ro(const struct module *mod)
{
+ if (!rodata_enabled)
+ return;
+
frob_text(&mod->core_layout, set_memory_rw);
frob_rodata(&mod->core_layout, set_memory_rw);
frob_ro_after_init(&mod->core_layout, set_memory_rw);
@@ -1920,6 +1923,9 @@
void module_enable_ro(const struct module *mod, bool after_init)
{
+ if (!rodata_enabled)
+ return;
+
frob_text(&mod->core_layout, set_memory_ro);
frob_rodata(&mod->core_layout, set_memory_ro);
frob_text(&mod->init_layout, set_memory_ro);
@@ -1952,6 +1958,9 @@
{
struct module *mod;
+ if (!rodata_enabled)
+ return;
+
mutex_lock(&module_mutex);
list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED)
@@ -1968,6 +1977,9 @@
{
struct module *mod;
+ if (!rodata_enabled)
+ return;
+
mutex_lock(&module_mutex);
list_for_each_entry_rcu(mod, &modules, list) {
if (mod->state == MODULE_STATE_UNFORMED)
@@ -1981,10 +1993,12 @@
static void disable_ro_nx(const struct module_layout *layout)
{
- frob_text(layout, set_memory_rw);
- frob_rodata(layout, set_memory_rw);
+ if (rodata_enabled) {
+ frob_text(layout, set_memory_rw);
+ frob_rodata(layout, set_memory_rw);
+ frob_ro_after_init(layout, set_memory_rw);
+ }
frob_rodata(layout, set_memory_x);
- frob_ro_after_init(layout, set_memory_rw);
frob_ro_after_init(layout, set_memory_x);
frob_writable_data(layout, set_memory_x);
}
diff --git a/kernel/pid.c b/kernel/pid.c
index 693a643..fa704f8 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -322,8 +322,10 @@
}
if (unlikely(is_child_reaper(pid))) {
- if (pid_ns_prepare_proc(ns))
+ if (pid_ns_prepare_proc(ns)) {
+ disable_pid_allocation(ns);
goto out_free;
+ }
}
get_pid_ns(ns);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index a29eaee..bf60b37 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -94,6 +94,16 @@
For more details, refer to the description of CONFIG_HIBERNATION
for booting without resuming.
+config HIBERNATION_SKIP_CRC
+ bool "Skip LZO image CRC check"
+ default n
+ depends on HIBERNATION
+ ---help---
+ Some filesystem devices may have hw based integrity checks. In this
+ scenario, repeating the integrity check in software is unnecessary
+ and wasteful. This config option has no effect if uncompressed
+ hibernation images are used.
+
config ARCH_SAVE_PAGE_KEYS
bool
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 95db6b79..1f6aef2 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -606,9 +606,10 @@
}
atomic_set(&d->ready, 0);
- for (i = 0; i < d->run_threads; i++)
- *d->crc32 = crc32_le(*d->crc32,
- d->unc[i], *d->unc_len[i]);
+ if (!IS_ENABLED(CONFIG_HIBERNATION_SKIP_CRC))
+ for (i = 0; i < d->run_threads; i++)
+ *d->crc32 = crc32_le(*d->crc32,
+ d->unc[i], *d->unc_len[i]);
atomic_set(&d->stop, 1);
wake_up(&d->done);
}
@@ -1455,7 +1456,8 @@
if (!snapshot_image_loaded(snapshot))
ret = -ENODATA;
if (!ret) {
- if (swsusp_header->flags & SF_CRC32_MODE) {
+ if ((swsusp_header->flags & SF_CRC32_MODE) &&
+ (!IS_ENABLED(CONFIG_HIBERNATION_SKIP_CRC))) {
if(handle->crc32 != swsusp_header->crc32) {
printk(KERN_ERR
"PM: Invalid image CRC32!\n");
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 3012f95..396b020 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2172,6 +2172,8 @@
console_unlock();
}
+#ifdef CONFIG_CONSOLE_FLUSH_ON_HOTPLUG
+
/**
* console_cpu_notify - print deferred console messages after CPU hotplug
* @self: notifier struct
@@ -2197,6 +2199,8 @@
return NOTIFY_OK;
}
+#endif
+
/**
* console_lock - lock the console system for exclusive use.
*
@@ -2850,7 +2854,9 @@
unregister_console(con);
}
}
+#ifdef CONFIG_CONSOLE_FLUSH_ON_HOTPLUG
hotcpu_notifier(console_cpu_notify, 0);
+#endif
return 0;
}
late_initcall(printk_late_init);
diff --git a/kernel/resource.c b/kernel/resource.c
index 89778a3..fbea5af 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -633,7 +633,8 @@
alloc.start = constraint->alignf(constraint->alignf_data, &avail,
size, constraint->align);
alloc.end = alloc.start + size - 1;
- if (resource_contains(&avail, &alloc)) {
+ if (alloc.start <= alloc.end &&
+ resource_contains(&avail, &alloc)) {
new->start = alloc.start;
new->end = alloc.end;
return 0;
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 93c00e9..fb2e56c 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -76,6 +76,7 @@
#include <linux/frame.h>
#include <linux/prefetch.h>
#include <linux/irq.h>
+#include <linux/cpufreq_times.h>
#include <asm/switch_to.h>
#include <asm/tlb.h>
@@ -2307,6 +2308,7 @@
dl_se->dl_period = 0;
dl_se->flags = 0;
dl_se->dl_bw = 0;
+ dl_se->dl_density = 0;
dl_se->dl_throttled = 0;
dl_se->dl_yielded = 0;
@@ -2342,6 +2344,10 @@
memset(&p->se.statistics, 0, sizeof(p->se.statistics));
#endif
+#ifdef CONFIG_CPU_FREQ_TIMES
+ cpufreq_task_times_init(p);
+#endif
+
RB_CLEAR_NODE(&p->dl.rb_node);
init_dl_task_timer(&p->dl);
__dl_clear_params(p);
@@ -4152,6 +4158,7 @@
dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline;
dl_se->flags = attr->sched_flags;
dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime);
+ dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime);
/*
* Changing the parameters of a task is 'tricky' and we're not doing
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index e4f48f1..50f2ea8 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -4,6 +4,7 @@
#include <linux/kernel_stat.h>
#include <linux/static_key.h>
#include <linux/context_tracking.h>
+#include <linux/cpufreq_times.h>
#include "sched.h"
#ifdef CONFIG_PARAVIRT
#include <asm/paravirt.h>
@@ -157,6 +158,11 @@
/* Account for user time used */
acct_account_cputime(p);
+
+#ifdef CONFIG_CPU_FREQ_TIMES
+ /* Account power usage for user time */
+ cpufreq_acct_update_power(p, cputime);
+#endif
}
/*
@@ -207,6 +213,10 @@
/* Account for system time used */
acct_account_cputime(p);
+#ifdef CONFIG_CPU_FREQ_TIMES
+ /* Account power usage for system time */
+ cpufreq_acct_update_power(p, cputime);
+#endif
}
/*
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 0a295ac..d7c7dd6 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -485,13 +485,84 @@
}
/*
- * When a -deadline entity is queued back on the runqueue, its runtime and
- * deadline might need updating.
+ * Revised wakeup rule [1]: For self-suspending tasks, rather then
+ * re-initializing task's runtime and deadline, the revised wakeup
+ * rule adjusts the task's runtime to avoid the task to overrun its
+ * density.
*
- * The policy here is that we update the deadline of the entity only if:
- * - the current deadline is in the past,
- * - using the remaining runtime with the current deadline would make
- * the entity exceed its bandwidth.
+ * Reasoning: a task may overrun the density if:
+ * runtime / (deadline - t) > dl_runtime / dl_deadline
+ *
+ * Therefore, runtime can be adjusted to:
+ * runtime = (dl_runtime / dl_deadline) * (deadline - t)
+ *
+ * In such way that runtime will be equal to the maximum density
+ * the task can use without breaking any rule.
+ *
+ * [1] Luca Abeni, Giuseppe Lipari, and Juri Lelli. 2015. Constant
+ * bandwidth server revisited. SIGBED Rev. 11, 4 (January 2015), 19-24.
+ */
+static void
+update_dl_revised_wakeup(struct sched_dl_entity *dl_se, struct rq *rq)
+{
+ u64 laxity = dl_se->deadline - rq_clock(rq);
+
+ /*
+ * If the task has deadline < period, and the deadline is in the past,
+ * it should already be throttled before this check.
+ *
+ * See update_dl_entity() comments for further details.
+ */
+ WARN_ON(dl_time_before(dl_se->deadline, rq_clock(rq)));
+
+ dl_se->runtime = (dl_se->dl_density * laxity) >> 20;
+}
+
+/*
+ * Regarding the deadline, a task with implicit deadline has a relative
+ * deadline == relative period. A task with constrained deadline has a
+ * relative deadline <= relative period.
+ *
+ * We support constrained deadline tasks. However, there are some restrictions
+ * applied only for tasks which do not have an implicit deadline. See
+ * update_dl_entity() to know more about such restrictions.
+ *
+ * The dl_is_implicit() returns true if the task has an implicit deadline.
+ */
+static inline bool dl_is_implicit(struct sched_dl_entity *dl_se)
+{
+ return dl_se->dl_deadline == dl_se->dl_period;
+}
+
+/*
+ * When a deadline entity is placed in the runqueue, its runtime and deadline
+ * might need to be updated. This is done by a CBS wake up rule. There are two
+ * different rules: 1) the original CBS; and 2) the Revisited CBS.
+ *
+ * When the task is starting a new period, the Original CBS is used. In this
+ * case, the runtime is replenished and a new absolute deadline is set.
+ *
+ * When a task is queued before the begin of the next period, using the
+ * remaining runtime and deadline could make the entity to overflow, see
+ * dl_entity_overflow() to find more about runtime overflow. When such case
+ * is detected, the runtime and deadline need to be updated.
+ *
+ * If the task has an implicit deadline, i.e., deadline == period, the Original
+ * CBS is applied. the runtime is replenished and a new absolute deadline is
+ * set, as in the previous cases.
+ *
+ * However, the Original CBS does not work properly for tasks with
+ * deadline < period, which are said to have a constrained deadline. By
+ * applying the Original CBS, a constrained deadline task would be able to run
+ * runtime/deadline in a period. With deadline < period, the task would
+ * overrun the runtime/period allowed bandwidth, breaking the admission test.
+ *
+ * In order to prevent this misbehave, the Revisited CBS is used for
+ * constrained deadline tasks when a runtime overflow is detected. In the
+ * Revisited CBS, rather than replenishing & setting a new absolute deadline,
+ * the remaining runtime of the task is reduced to avoid runtime overflow.
+ * Please refer to the comments update_dl_revised_wakeup() function to find
+ * more about the Revised CBS rule.
*/
static void update_dl_entity(struct sched_dl_entity *dl_se,
struct sched_dl_entity *pi_se)
@@ -501,6 +572,14 @@
if (dl_time_before(dl_se->deadline, rq_clock(rq)) ||
dl_entity_overflow(dl_se, pi_se, rq_clock(rq))) {
+
+ if (unlikely(!dl_is_implicit(dl_se) &&
+ !dl_time_before(dl_se->deadline, rq_clock(rq)) &&
+ !dl_se->dl_boosted)){
+ update_dl_revised_wakeup(dl_se, rq);
+ return;
+ }
+
dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline;
dl_se->runtime = pi_se->dl_runtime;
}
@@ -964,11 +1043,6 @@
__dequeue_dl_entity(dl_se);
}
-static inline bool dl_is_constrained(struct sched_dl_entity *dl_se)
-{
- return dl_se->dl_deadline < dl_se->dl_period;
-}
-
static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
{
struct task_struct *pi_task = rt_mutex_get_top_task(p);
@@ -1000,7 +1074,7 @@
* If that is the case, the task will be throttled and
* the replenishment timer will be set to the next period.
*/
- if (!p->dl.dl_throttled && dl_is_constrained(&p->dl))
+ if (!p->dl.dl_throttled && !dl_is_implicit(&p->dl))
dl_check_constrained_dl(&p->dl);
/*
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 04ba6d0..78c433a 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -2511,7 +2511,8 @@
return;
- down_read(&mm->mmap_sem);
+ if (!down_read_trylock(&mm->mmap_sem))
+ return;
vma = find_vma(mm, start);
if (!vma) {
reset_ptenuma_scan(p);
@@ -6871,6 +6872,13 @@
if (!sg->group_weight)
return true;
+ /*
+ * Don't skip a group if a task affinity allows it
+ * to run only on that group.
+ */
+ if (cpumask_subset(tsk_cpus_allowed(p), sched_group_cpus(sg)))
+ return false;
+
if (!task_fits_max(p, fcpu))
return true;
@@ -7357,6 +7365,12 @@
}
#endif
+enum fastpaths {
+ NONE = 0,
+ SYNC_WAKEUP,
+ PREV_CPU_BIAS,
+};
+
static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync)
{
bool boosted, prefer_idle;
@@ -7367,6 +7381,7 @@
struct cpumask *rtg_target = find_rtg_target(p);
struct find_best_target_env fbt_env;
u64 start_t = 0;
+ int fastpath = 0;
if (trace_sched_task_util_enabled())
start_t = sched_clock();
@@ -7403,12 +7418,17 @@
if (bias_to_waker_cpu(p, cpu, rtg_target)) {
schedstat_inc(p->se.statistics.nr_wakeups_secb_sync);
schedstat_inc(this_rq()->eas_stats.secb_sync);
- return cpu;
+ target_cpu = cpu;
+ fastpath = SYNC_WAKEUP;
+ goto out;
}
}
- if (bias_to_prev_cpu(p, rtg_target))
- return prev_cpu;
+ if (bias_to_prev_cpu(p, rtg_target)) {
+ target_cpu = prev_cpu;
+ fastpath = PREV_CPU_BIAS;
+ goto out;
+ }
rcu_read_lock();
@@ -7495,11 +7515,12 @@
schedstat_inc(this_rq()->eas_stats.secb_count);
unlock:
- trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync,
- fbt_env.need_idle, fbt_env.placement_boost,
- rtg_target ? cpumask_first(rtg_target) : -1,
- start_t);
rcu_read_unlock();
+out:
+ trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync,
+ fbt_env.need_idle, fastpath,
+ fbt_env.placement_boost, rtg_target ?
+ cpumask_first(rtg_target) : -1, start_t);
return target_cpu;
}
@@ -8790,13 +8811,12 @@
int max_cap_cpu;
unsigned long flags;
- capacity = min(capacity, thermal_cap(cpu));
-
- cpu_rq(cpu)->cpu_capacity_orig = capacity;
-
capacity *= arch_scale_max_freq_capacity(sd, cpu);
capacity >>= SCHED_CAPACITY_SHIFT;
+ capacity = min(capacity, thermal_cap(cpu));
+ cpu_rq(cpu)->cpu_capacity_orig = capacity;
+
mcc = &cpu_rq(cpu)->rd->max_cpu_capacity;
raw_spin_lock_irqsave(&mcc->lock, flags);
diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c
index c8f6e00..a2debf9 100644
--- a/kernel/sched/walt.c
+++ b/kernel/sched/walt.c
@@ -847,8 +847,7 @@
if (p == src_rq->ed_task) {
src_rq->ed_task = NULL;
- if (!dest_rq->ed_task)
- dest_rq->ed_task = p;
+ dest_rq->ed_task = p;
}
done:
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index 1650578..10c5a3a 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -121,7 +121,45 @@
}
if (kthread_should_park()) {
+ /*
+ * Serialize against wakeup. If we take the lock first,
+ * wakeup is skipped. If we run later, we observe,
+ * TASK_RUNNING update from wakeup path, before moving
+ * forward. This helps avoid the race, where wakeup
+ * observes TASK_INTERRUPTIBLE, and also observes
+ * the TASK_PARKED in kthread_parkme() before updating
+ * task state to TASK_RUNNING. In this case, kthread
+ * gets parked in TASK_RUNNING state. This results
+ * in panic later on in kthread_unpark(), as it sees
+ * KTHREAD_IS_PARKED flag set but fails to rebind the
+ * kthread, due to it being not in TASK_PARKED state.
+ *
+ * Control thread Hotplug Thread
+ *
+ * kthread_park()
+ * set KTHREAD_SHOULD_PARK
+ * smpboot_thread_fn()
+ * set_current_state(
+ * TASK_INTERRUPTIBLE);
+ * kthread_parkme()
+ *
+ * wake_up_process()
+ *
+ * raw_spin_lock_irqsave(&p->pi_lock, flags);
+ * if (!(p->state & state))
+ * goto out;
+ *
+ * __set_current_state(
+ * TASK_PARKED);
+ *
+ * if (p->on_rq && ttwu_remote(p, wake_flags))
+ * ttwu_remote()
+ * p->state = TASK_RUNNING;
+ * schedule();
+ */
+ raw_spin_lock(¤t->pi_lock);
__set_current_state(TASK_RUNNING);
+ raw_spin_unlock(¤t->pi_lock);
preempt_enable();
if (ht->park && td->status == HP_THREAD_ACTIVE) {
BUG_ON(td->cpu != smp_processor_id());
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 79bbaf0..59b482f 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -478,14 +478,11 @@
#ifdef CONFIG_PREEMPTIRQ_EVENTS
struct irqsoff_store *is = &per_cpu(the_irqsoff,
raw_smp_processor_id());
+ u64 delta = sched_clock() - is->ts;
- if (!is->ts) {
- is->ts = sched_clock();
- is->caddr[0] = CALLER_ADDR0;
- is->caddr[1] = CALLER_ADDR1;
- is->caddr[2] = CALLER_ADDR2;
- is->caddr[3] = CALLER_ADDR3;
- }
+ if (delta > sysctl_irqsoff_tracing_threshold_ns)
+ trace_irqs_disable(delta, is->caddr[0], is->caddr[1],
+ is->caddr[2], is->caddr[3]);
#endif /* CONFIG_PREEMPTIRQ_EVENTS */
if (!preempt_trace() && irq_trace())
@@ -497,15 +494,12 @@
#ifdef CONFIG_PREEMPTIRQ_EVENTS
struct irqsoff_store *is = &per_cpu(the_irqsoff,
raw_smp_processor_id());
- u64 delta = 0;
- if (is->ts) {
- delta = sched_clock() - is->ts;
- is->ts = 0;
- }
- if (delta > sysctl_irqsoff_tracing_threshold_ns)
- trace_irqs_disable(delta, is->caddr[0], is->caddr[1],
- is->caddr[2], is->caddr[3]);
+ is->ts = sched_clock();
+ is->caddr[0] = CALLER_ADDR0;
+ is->caddr[1] = CALLER_ADDR1;
+ is->caddr[2] = CALLER_ADDR2;
+ is->caddr[3] = CALLER_ADDR3;
#endif /* CONFIG_PREEMPTIRQ_EVENTS */
if (!preempt_trace() && irq_trace())
diff --git a/kernel/user.c b/kernel/user.c
index b069ccb..41e94e4 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/export.h>
#include <linux/user_namespace.h>
+#include <linux/proc_fs.h>
#include <linux/proc_ns.h>
/*
@@ -201,6 +202,7 @@
}
spin_unlock_irq(&uidhash_lock);
}
+ proc_register_uid(uid);
return up;
@@ -222,6 +224,7 @@
spin_lock_irq(&uidhash_lock);
uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID));
spin_unlock_irq(&uidhash_lock);
+ proc_register_uid(GLOBAL_ROOT_UID);
return 0;
}
diff --git a/mm/cma.c b/mm/cma.c
index 5fc1809..e97ad01 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -438,6 +438,8 @@
struct page *page = NULL;
int retry_after_sleep = 0;
int ret = -ENOMEM;
+ int max_retries = 2;
+ int available_regions = 0;
if (!cma || !cma->count)
return NULL;
@@ -464,9 +466,16 @@
bitmap_maxno, start, bitmap_count, mask,
offset);
if (bitmap_no >= bitmap_maxno) {
- if (retry_after_sleep < 2) {
+ if (retry_after_sleep < max_retries) {
start = 0;
/*
+ * update max retries if available free regions
+ * are less.
+ */
+ if (available_regions < 3)
+ max_retries = 5;
+ available_regions = 0;
+ /*
* Page may be momentarily pinned by some other
* process which has been scheduled out, eg.
* in exit path, during unmap call, or process
@@ -483,6 +492,8 @@
break;
}
}
+
+ available_regions++;
bitmap_set(cma->bitmap, bitmap_no, bitmap_count);
/*
* It's safe to drop the lock here. We've marked this region for
diff --git a/mm/filemap.c b/mm/filemap.c
index 03c79ef..211df83 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -618,7 +618,7 @@
VM_BUG_ON_PAGE(!PageLocked(new), new);
VM_BUG_ON_PAGE(new->mapping, new);
- error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
+ error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK);
if (!error) {
struct address_space *mapping = old->mapping;
void (*freepage)(struct page *);
@@ -674,7 +674,7 @@
return error;
}
- error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
+ error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK);
if (error) {
if (!huge)
mem_cgroup_cancel_charge(page, memcg, false);
@@ -1249,8 +1249,7 @@
if (fgp_flags & FGP_ACCESSED)
__SetPageReferenced(page);
- err = add_to_page_cache_lru(page, mapping, offset,
- gfp_mask & GFP_RECLAIM_MASK);
+ err = add_to_page_cache_lru(page, mapping, offset, gfp_mask);
if (unlikely(err)) {
put_page(page);
page = NULL;
@@ -1998,7 +1997,7 @@
if (!page)
return -ENOMEM;
- ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL);
+ ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask);
if (ret == 0)
ret = mapping->a_ops->readpage(file, page);
else if (ret == -EEXIST)
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index e6fbdf4..ca18dc0 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2506,13 +2506,13 @@
if (mapping && mapping_cap_account_dirty(mapping)) {
struct inode *inode = mapping->host;
struct bdi_writeback *wb;
- bool locked;
+ struct wb_lock_cookie cookie = {};
- wb = unlocked_inode_to_wb_begin(inode, &locked);
+ wb = unlocked_inode_to_wb_begin(inode, &cookie);
current->nr_dirtied--;
dec_node_page_state(page, NR_DIRTIED);
dec_wb_stat(wb, WB_DIRTIED);
- unlocked_inode_to_wb_end(inode, locked);
+ unlocked_inode_to_wb_end(inode, &cookie);
}
}
EXPORT_SYMBOL(account_page_redirty);
@@ -2618,15 +2618,15 @@
if (mapping_cap_account_dirty(mapping)) {
struct inode *inode = mapping->host;
struct bdi_writeback *wb;
- bool locked;
+ struct wb_lock_cookie cookie = {};
lock_page_memcg(page);
- wb = unlocked_inode_to_wb_begin(inode, &locked);
+ wb = unlocked_inode_to_wb_begin(inode, &cookie);
if (TestClearPageDirty(page))
account_page_cleaned(page, mapping, wb);
- unlocked_inode_to_wb_end(inode, locked);
+ unlocked_inode_to_wb_end(inode, &cookie);
unlock_page_memcg(page);
} else {
ClearPageDirty(page);
@@ -2658,7 +2658,7 @@
if (mapping && mapping_cap_account_dirty(mapping)) {
struct inode *inode = mapping->host;
struct bdi_writeback *wb;
- bool locked;
+ struct wb_lock_cookie cookie = {};
/*
* Yes, Virginia, this is indeed insane.
@@ -2695,7 +2695,7 @@
* always locked coming in here, so we get the desired
* exclusion.
*/
- wb = unlocked_inode_to_wb_begin(inode, &locked);
+ wb = unlocked_inode_to_wb_begin(inode, &cookie);
if (TestClearPageDirty(page)) {
mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY);
dec_node_page_state(page, NR_FILE_DIRTY);
@@ -2703,7 +2703,7 @@
dec_wb_stat(wb, WB_RECLAIMABLE);
ret = 1;
}
- unlocked_inode_to_wb_end(inode, locked);
+ unlocked_inode_to_wb_end(inode, &cookie);
return ret;
}
return TestClearPageDirty(page);
diff --git a/mm/slab.c b/mm/slab.c
index 1f82d16..c59844d 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -4096,7 +4096,8 @@
next_reap_node();
out:
/* Set up the next iteration */
- schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_AC));
+ schedule_delayed_work_on(smp_processor_id(), work,
+ round_jiffies_relative(REAPTIMEOUT_AC));
}
#ifdef CONFIG_SLABINFO
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 658d62c..c5b94d61 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -3023,7 +3023,7 @@
unsigned long nr_reclaimed;
struct scan_control sc = {
.nr_to_reclaim = SWAP_CLUSTER_MAX,
- .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
+ .gfp_mask = memalloc_noio_flags(gfp_mask),
.reclaim_idx = gfp_zone(gfp_mask),
.order = order,
.nodemask = nodemask,
@@ -3038,12 +3038,12 @@
* 1 is returned so that the page allocator does not OOM kill at this
* point.
*/
- if (throttle_direct_reclaim(gfp_mask, zonelist, nodemask))
+ if (throttle_direct_reclaim(sc.gfp_mask, zonelist, nodemask))
return 1;
trace_mm_vmscan_direct_reclaim_begin(order,
sc.may_writepage,
- gfp_mask,
+ sc.gfp_mask,
sc.reclaim_idx);
nr_reclaimed = do_try_to_free_pages(zonelist, &sc);
@@ -3827,16 +3827,15 @@
const unsigned long nr_pages = 1 << order;
struct task_struct *p = current;
struct reclaim_state reclaim_state;
- int classzone_idx = gfp_zone(gfp_mask);
struct scan_control sc = {
.nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX),
- .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)),
+ .gfp_mask = memalloc_noio_flags(gfp_mask),
.order = order,
.priority = NODE_RECLAIM_PRIORITY,
.may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE),
.may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP),
.may_swap = 1,
- .reclaim_idx = classzone_idx,
+ .reclaim_idx = gfp_zone(gfp_mask),
};
cond_resched();
@@ -3846,7 +3845,7 @@
* and RECLAIM_UNMAP.
*/
p->flags |= PF_MEMALLOC | PF_SWAPWRITE;
- lockdep_set_current_reclaim_state(gfp_mask);
+ lockdep_set_current_reclaim_state(sc.gfp_mask);
reclaim_state.reclaimed_slab = 0;
p->reclaim_state = &reclaim_state;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index f97fb09..8bd62ed 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1356,8 +1356,6 @@
return zone == compare;
}
- /* The zone must be somewhere! */
- WARN_ON_ONCE(1);
return false;
}
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 7671441..fb3e2a5 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -29,6 +29,7 @@
#include <linux/net_tstamp.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
+#include <linux/phy.h>
#include <net/arp.h>
#include <net/switchdev.h>
@@ -658,8 +659,11 @@
{
const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops;
+ struct phy_device *phydev = vlan->real_dev->phydev;
- if (ops->get_ts_info) {
+ if (phydev && phydev->drv && phydev->drv->ts_info) {
+ return phydev->drv->ts_info(phydev, info);
+ } else if (ops->get_ts_info) {
return ops->get_ts_info(vlan->real_dev, info);
} else {
info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index dc59eae..cc06149 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -749,18 +749,31 @@
}
static void hci_req_add_le_create_conn(struct hci_request *req,
- struct hci_conn *conn)
+ struct hci_conn *conn,
+ bdaddr_t *direct_rpa)
{
struct hci_cp_le_create_conn cp;
struct hci_dev *hdev = conn->hdev;
u8 own_addr_type;
- /* Update random address, but set require_privacy to false so
- * that we never connect with an non-resolvable address.
+ /* If direct address was provided we use it instead of current
+ * address.
*/
- if (hci_update_random_address(req, false, conn_use_rpa(conn),
- &own_addr_type))
- return;
+ if (direct_rpa) {
+ if (bacmp(&req->hdev->random_addr, direct_rpa))
+ hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
+ direct_rpa);
+
+ /* direct address is always RPA */
+ own_addr_type = ADDR_LE_DEV_RANDOM;
+ } else {
+ /* Update random address, but set require_privacy to false so
+ * that we never connect with an non-resolvable address.
+ */
+ if (hci_update_random_address(req, false, conn_use_rpa(conn),
+ &own_addr_type))
+ return;
+ }
memset(&cp, 0, sizeof(cp));
@@ -825,7 +838,7 @@
struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
u8 dst_type, u8 sec_level, u16 conn_timeout,
- u8 role)
+ u8 role, bdaddr_t *direct_rpa)
{
struct hci_conn_params *params;
struct hci_conn *conn;
@@ -940,7 +953,7 @@
hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED);
}
- hci_req_add_le_create_conn(&req, conn);
+ hci_req_add_le_create_conn(&req, conn, direct_rpa);
create_conn:
err = hci_req_run(&req, create_le_conn_complete);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 3ac89e9..4bd72d2 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -548,6 +548,7 @@
{
struct hci_dev *hdev = req->hdev;
u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ bool changed = false;
/* If Connectionless Slave Broadcast master role is supported
* enable all necessary events for it.
@@ -557,6 +558,7 @@
events[1] |= 0x80; /* Synchronization Train Complete */
events[2] |= 0x10; /* Slave Page Response Timeout */
events[2] |= 0x20; /* CSB Channel Map Change */
+ changed = true;
}
/* If Connectionless Slave Broadcast slave role is supported
@@ -567,13 +569,24 @@
events[2] |= 0x02; /* CSB Receive */
events[2] |= 0x04; /* CSB Timeout */
events[2] |= 0x08; /* Truncated Page Complete */
+ changed = true;
}
/* Enable Authenticated Payload Timeout Expired event if supported */
- if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING)
+ if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) {
events[2] |= 0x80;
+ changed = true;
+ }
- hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
+ /* Some Broadcom based controllers indicate support for Set Event
+ * Mask Page 2 command, but then actually do not support it. Since
+ * the default value is all bits set to zero, the command is only
+ * required if the event mask has to be changed. In case no change
+ * to the event mask is needed, skip this command.
+ */
+ if (changed)
+ hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2,
+ sizeof(events), events);
}
static int hci_init3_req(struct hci_request *req, unsigned long opt)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index e17aacb..d2f9eb1 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -4646,7 +4646,8 @@
/* This function requires the caller holds hdev->lock */
static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev,
bdaddr_t *addr,
- u8 addr_type, u8 adv_type)
+ u8 addr_type, u8 adv_type,
+ bdaddr_t *direct_rpa)
{
struct hci_conn *conn;
struct hci_conn_params *params;
@@ -4697,7 +4698,8 @@
}
conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW,
- HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER);
+ HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER,
+ direct_rpa);
if (!IS_ERR(conn)) {
/* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned
* by higher layer that tried to connect, if no then
@@ -4807,8 +4809,13 @@
bdaddr_type = irk->addr_type;
}
- /* Check if we have been requested to connect to this device */
- conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type);
+ /* Check if we have been requested to connect to this device.
+ *
+ * direct_addr is set only for directed advertising reports (it is NULL
+ * for advertising reports) and is already verified to be RPA above.
+ */
+ conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type,
+ direct_addr);
if (conn && type == LE_ADV_IND) {
/* Store report for later inclusion by
* mgmt_device_connected
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2bbca23..1fc23cb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7148,7 +7148,7 @@
hcon = hci_connect_le(hdev, dst, dst_type,
chan->sec_level,
HCI_LE_CONN_TIMEOUT,
- HCI_ROLE_SLAVE);
+ HCI_ROLE_SLAVE, NULL);
else
hcon = hci_connect_le_scan(hdev, dst, dst_type,
chan->sec_level,
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 658c900..ead4d1b 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -2233,8 +2233,14 @@
else
sec_level = authreq_to_seclevel(auth);
- if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK))
+ if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) {
+ /* If link is already encrypted with sufficient security we
+ * still need refresh encryption as per Core Spec 5.0 Vol 3,
+ * Part H 2.4.6
+ */
+ smp_ltk_encrypt(conn, hcon->sec_level);
return 0;
+ }
if (sec_level > hcon->pending_sec_level)
hcon->pending_sec_level = sec_level;
diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c
index 9637a68..9adf162 100644
--- a/net/bridge/netfilter/ebt_among.c
+++ b/net/bridge/netfilter/ebt_among.c
@@ -177,6 +177,28 @@
return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
}
+static bool wormhash_offset_invalid(int off, unsigned int len)
+{
+ if (off == 0) /* not present */
+ return false;
+
+ if (off < (int)sizeof(struct ebt_among_info) ||
+ off % __alignof__(struct ebt_mac_wormhash))
+ return true;
+
+ off += sizeof(struct ebt_mac_wormhash);
+
+ return off > len;
+}
+
+static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b)
+{
+ if (a == 0)
+ a = sizeof(struct ebt_among_info);
+
+ return ebt_mac_wormhash_size(wh) + a == b;
+}
+
static int ebt_among_mt_check(const struct xt_mtchk_param *par)
{
const struct ebt_among_info *info = par->matchinfo;
@@ -189,6 +211,10 @@
if (expected_length > em->match_size)
return -EINVAL;
+ if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) ||
+ wormhash_offset_invalid(info->wh_src_ofs, em->match_size))
+ return -EINVAL;
+
wh_dst = ebt_among_wh_dst(info);
if (poolsize_invalid(wh_dst))
return -EINVAL;
@@ -201,6 +227,14 @@
if (poolsize_invalid(wh_src))
return -EINVAL;
+ if (info->wh_src_ofs < info->wh_dst_ofs) {
+ if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs))
+ return -EINVAL;
+ } else {
+ if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs))
+ return -EINVAL;
+ }
+
expected_length += ebt_mac_wormhash_size(wh_src);
if (em->match_size != EBT_ALIGN(expected_length)) {
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index d3f6c26..255c0a0 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -295,6 +295,7 @@
u32 yes;
struct crush_rule *r;
+ err = -EINVAL;
ceph_decode_32_safe(p, end, yes, bad);
if (!yes) {
dout("crush_decode NO rule %d off %x %p to %p\n",
diff --git a/net/core/dev.c b/net/core/dev.c
index fe1dc21..802b3fa 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -995,7 +995,7 @@
{
if (*name == '\0')
return false;
- if (strlen(name) >= IFNAMSIZ)
+ if (strnlen(name, IFNAMSIZ) == IFNAMSIZ)
return false;
if (!strcmp(name, ".") || !strcmp(name, ".."))
return false;
@@ -2669,7 +2669,7 @@
if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
return 0;
- eth = (struct ethhdr *)skb_mac_header(skb);
+ eth = (struct ethhdr *)skb->data;
type = eth->h_proto;
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index eecad95..cb9a16b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1139,10 +1139,6 @@
lladdr = neigh->ha;
}
- if (new & NUD_CONNECTED)
- neigh->confirmed = jiffies;
- neigh->updated = jiffies;
-
/* If entry was valid and address is not changed,
do not change entry state, if new one is STALE.
*/
@@ -1164,6 +1160,16 @@
}
}
+ /* Update timestamps only once we know we will make a change to the
+ * neighbour entry. Otherwise we risk to move the locktime window with
+ * noop updates and ignore relevant ARP updates.
+ */
+ if (new != old || lladdr != neigh->ha) {
+ if (new & NUD_CONNECTED)
+ neigh->confirmed = jiffies;
+ neigh->updated = jiffies;
+ }
+
if (new != old) {
neigh_del_timer(neigh);
if (new & NUD_PROBE)
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index b7efe2f..04fd04c 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -312,6 +312,25 @@
goto out;
}
+static int __net_init net_defaults_init_net(struct net *net)
+{
+ net->core.sysctl_somaxconn = SOMAXCONN;
+ return 0;
+}
+
+static struct pernet_operations net_defaults_ops = {
+ .init = net_defaults_init_net,
+};
+
+static __init int net_defaults_init(void)
+{
+ if (register_pernet_subsys(&net_defaults_ops))
+ panic("Cannot initialize net default settings");
+
+ return 0;
+}
+
+core_initcall(net_defaults_init);
#ifdef CONFIG_NET_NS
static struct ucounts *inc_net_namespaces(struct user_namespace *ns)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2cc4a1b..e2136eb 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2621,7 +2621,8 @@
{
int pos = skb_headlen(skb);
- skb_shinfo(skb1)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG;
+ skb_shinfo(skb1)->tx_flags |= skb_shinfo(skb)->tx_flags &
+ SKBTX_SHARED_FRAG;
if (len < pos) /* Split line is inside header. */
skb_split_inside_header(skb, skb1, len, pos);
else /* Second chunk has no header, nothing to copy. */
@@ -3234,8 +3235,8 @@
skb_copy_from_linear_data_offset(head_skb, offset,
skb_put(nskb, hsize), hsize);
- skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags &
- SKBTX_SHARED_FRAG;
+ skb_shinfo(nskb)->tx_flags |= skb_shinfo(head_skb)->tx_flags &
+ SKBTX_SHARED_FRAG;
while (pos < offset + len) {
if (i >= nfrags) {
@@ -3481,24 +3482,18 @@
NULL);
}
-/**
- * skb_to_sgvec - Fill a scatter-gather list from a socket buffer
- * @skb: Socket buffer containing the buffers to be mapped
- * @sg: The scatter-gather list to map into
- * @offset: The offset into the buffer's contents to start mapping
- * @len: Length of buffer space to be mapped
- *
- * Fill the specified scatter-gather list with mappings/pointers into a
- * region of the buffer space attached to a socket buffer.
- */
static int
-__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
+ unsigned int recursion_level)
{
int start = skb_headlen(skb);
int i, copy = start - offset;
struct sk_buff *frag_iter;
int elt = 0;
+ if (unlikely(recursion_level >= 24))
+ return -EMSGSIZE;
+
if (copy > 0) {
if (copy > len)
copy = len;
@@ -3517,6 +3512,8 @@
end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
if ((copy = end - offset) > 0) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ if (unlikely(elt && sg_is_last(&sg[elt - 1])))
+ return -EMSGSIZE;
if (copy > len)
copy = len;
@@ -3531,16 +3528,22 @@
}
skb_walk_frags(skb, frag_iter) {
- int end;
+ int end, ret;
WARN_ON(start > offset + len);
end = start + frag_iter->len;
if ((copy = end - offset) > 0) {
+ if (unlikely(elt && sg_is_last(&sg[elt - 1])))
+ return -EMSGSIZE;
+
if (copy > len)
copy = len;
- elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start,
- copy);
+ ret = __skb_to_sgvec(frag_iter, sg+elt, offset - start,
+ copy, recursion_level + 1);
+ if (unlikely(ret < 0))
+ return ret;
+ elt += ret;
if ((len -= copy) == 0)
return elt;
offset += copy;
@@ -3551,6 +3554,31 @@
return elt;
}
+/**
+ * skb_to_sgvec - Fill a scatter-gather list from a socket buffer
+ * @skb: Socket buffer containing the buffers to be mapped
+ * @sg: The scatter-gather list to map into
+ * @offset: The offset into the buffer's contents to start mapping
+ * @len: Length of buffer space to be mapped
+ *
+ * Fill the specified scatter-gather list with mappings/pointers into a
+ * region of the buffer space attached to a socket buffer. Returns either
+ * the number of scatterlist items used, or -EMSGSIZE if the contents
+ * could not fit.
+ */
+int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+{
+ int nsg = __skb_to_sgvec(skb, sg, offset, len, 0);
+
+ if (nsg <= 0)
+ return nsg;
+
+ sg_mark_end(&sg[nsg - 1]);
+
+ return nsg;
+}
+EXPORT_SYMBOL_GPL(skb_to_sgvec);
+
/* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given
* sglist without mark the sg which contain last skb data as the end.
* So the caller can mannipulate sg list as will when padding new data after
@@ -3573,19 +3601,11 @@
int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
int offset, int len)
{
- return __skb_to_sgvec(skb, sg, offset, len);
+ return __skb_to_sgvec(skb, sg, offset, len, 0);
}
EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark);
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
-{
- int nsg = __skb_to_sgvec(skb, sg, offset, len);
- sg_mark_end(&sg[nsg - 1]);
-
- return nsg;
-}
-EXPORT_SYMBOL_GPL(skb_to_sgvec);
/**
* skb_cow_data - Check that a socket buffer's data buffers are writable
@@ -3868,7 +3888,8 @@
return;
if (tsonly) {
- skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags;
+ skb_shinfo(skb)->tx_flags |= skb_shinfo(orig_skb)->tx_flags &
+ SKBTX_ANY_TSTAMP;
skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey;
}
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 1b46190..546ba76 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -438,8 +438,6 @@
{
struct ctl_table *tbl;
- net->core.sysctl_somaxconn = SOMAXCONN;
-
tbl = netns_core_table;
if (!net_eq(net, &init_net)) {
tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL);
diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c
index 4ebe2aa..04b5450 100644
--- a/net/hsr/hsr_forward.c
+++ b/net/hsr/hsr_forward.c
@@ -324,8 +324,7 @@
unsigned long irqflags;
frame->is_supervision = is_supervision_frame(port->hsr, skb);
- frame->node_src = hsr_get_node(&port->hsr->node_db, skb,
- frame->is_supervision);
+ frame->node_src = hsr_get_node(port, skb, frame->is_supervision);
if (frame->node_src == NULL)
return -1; /* Unknown node and !is_supervision, or no mem */
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 7ea9258..284a9b8 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -158,9 +158,10 @@
/* Get the hsr_node from which 'skb' was sent.
*/
-struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
+struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
bool is_sup)
{
+ struct list_head *node_db = &port->hsr->node_db;
struct hsr_node *node;
struct ethhdr *ethhdr;
u16 seq_out;
@@ -186,7 +187,11 @@
*/
seq_out = hsr_get_skb_sequence_nr(skb) - 1;
} else {
- WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
+ /* this is called also for frames from master port and
+ * so warn only for non master ports
+ */
+ if (port->type != HSR_PT_MASTER)
+ WARN_ONCE(1, "%s: Non-HSR frame\n", __func__);
seq_out = HSR_SEQNR_START;
}
diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h
index 438b40f..4e04f0e 100644
--- a/net/hsr/hsr_framereg.h
+++ b/net/hsr/hsr_framereg.h
@@ -18,7 +18,7 @@
struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[],
u16 seq_out);
-struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb,
+struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb,
bool is_sup);
void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr,
struct hsr_port *port);
diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c
index e0bd013..bf5d26d 100644
--- a/net/ieee802154/socket.c
+++ b/net/ieee802154/socket.c
@@ -304,12 +304,12 @@
skb->sk = sk;
skb->protocol = htons(ETH_P_IEEE802154);
- dev_put(dev);
-
err = dev_queue_xmit(skb);
if (err > 0)
err = net_xmit_errno(err);
+ dev_put(dev);
+
return err ?: size;
out_skb:
@@ -693,12 +693,12 @@
skb->sk = sk;
skb->protocol = htons(ETH_P_IEEE802154);
- dev_put(dev);
-
err = dev_queue_xmit(skb);
if (err > 0)
err = net_xmit_errno(err);
+ dev_put(dev);
+
return err ?: size;
out_skb:
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 22377c8..e8f8623 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -220,7 +220,9 @@
ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
sg_init_table(sg, nfrags + sglists);
- skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ if (unlikely(err < 0))
+ goto out_free;
if (x->props.flags & XFRM_STATE_ESN) {
/* Attach seqhi sg right after packet payload */
@@ -393,7 +395,9 @@
skb_push(skb, ihl);
sg_init_table(sg, nfrags + sglists);
- skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ if (unlikely(err < 0))
+ goto out_free;
if (x->props.flags & XFRM_STATE_ESN) {
/* Attach seqhi sg right after packet payload */
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index e60517e..8cae791 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -437,7 +437,7 @@
/*unsigned long now; */
struct net *net = dev_net(dev);
- rt = ip_route_output(net, sip, tip, 0, 0);
+ rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev));
if (IS_ERR(rt))
return 1;
if (rt->dst.dev != dev) {
@@ -658,6 +658,7 @@
unsigned char *arp_ptr;
struct rtable *rt;
unsigned char *sha;
+ unsigned char *tha = NULL;
__be32 sip, tip;
u16 dev_type = dev->type;
int addr_type;
@@ -729,6 +730,7 @@
break;
#endif
default:
+ tha = arp_ptr;
arp_ptr += dev->addr_len;
}
memcpy(&tip, arp_ptr, 4);
@@ -847,8 +849,18 @@
It is possible, that this option should be enabled for some
devices (strip is candidate)
*/
- is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip &&
- addr_type == RTN_UNICAST;
+ is_garp = tip == sip && addr_type == RTN_UNICAST;
+
+ /* Unsolicited ARP _replies_ also require target hwaddr to be
+ * the same as source.
+ */
+ if (is_garp && arp->ar_op == htons(ARPOP_REPLY))
+ is_garp =
+ /* IPv4 over IEEE 1394 doesn't provide target
+ * hardware address field in its ARP payload.
+ */
+ tha &&
+ !memcmp(tha, sha, dev->addr_len);
if (!n &&
((arp->ar_op == htons(ARPOP_REPLY) &&
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 20fb25e..3d8021d 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -268,10 +268,11 @@
esph->spi = x->id.spi;
sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg,
- (unsigned char *)esph - skb->data,
- assoclen + ivlen + clen + alen);
-
+ err = skb_to_sgvec(skb, sg,
+ (unsigned char *)esph - skb->data,
+ assoclen + ivlen + clen + alen);
+ if (unlikely(err < 0))
+ goto error;
aead_request_set_crypt(req, sg, sg, ivlen + clen, iv);
aead_request_set_ad(req, assoclen);
@@ -481,7 +482,9 @@
}
sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg, 0, skb->len);
+ err = skb_to_sgvec(skb, sg, 0, skb->len);
+ if (unlikely(err < 0))
+ goto out;
aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
aead_request_set_ad(req, assoclen);
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 7e7b7a3..e1be244 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -1611,18 +1611,20 @@
bool first = false;
for_nexthops(fi) {
+ if (net->ipv4.sysctl_fib_multipath_use_neigh) {
+ if (!fib_good_nh(nh))
+ continue;
+ if (!first) {
+ res->nh_sel = nhsel;
+ first = true;
+ }
+ }
+
if (hash > atomic_read(&nh->nh_upper_bound))
continue;
- if (!net->ipv4.sysctl_fib_multipath_use_neigh ||
- fib_good_nh(nh)) {
- res->nh_sel = nhsel;
- return;
- }
- if (!first) {
- res->nh_sel = nhsel;
- first = true;
- }
+ res->nh_sel = nhsel;
+ return;
} endfor_nexthops(fi);
}
#endif
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 96536a0..e1271e75 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -253,13 +253,14 @@
struct net_device *dev;
char name[IFNAMSIZ];
- if (parms->name[0])
- strlcpy(name, parms->name, IFNAMSIZ);
- else {
- if (strlen(ops->kind) > (IFNAMSIZ - 3)) {
- err = -E2BIG;
+ err = -E2BIG;
+ if (parms->name[0]) {
+ if (!dev_valid_name(parms->name))
goto failed;
- }
+ strlcpy(name, parms->name, IFNAMSIZ);
+ } else {
+ if (strlen(ops->kind) > (IFNAMSIZ - 3))
+ goto failed;
strlcpy(name, ops->kind, IFNAMSIZ);
strncat(name, "%d", 2);
}
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 27089f5..742a343 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1929,6 +1929,20 @@
struct net *net = dev_net(skb->dev);
int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL;
struct mr_table *mrt;
+ struct net_device *dev;
+
+ /* skb->dev passed in is the loX master dev for vrfs.
+ * As there are no vifs associated with loopback devices,
+ * get the proper interface that does have a vif associated with it.
+ */
+ dev = skb->dev;
+ if (netif_is_l3_master(skb->dev)) {
+ dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
+ if (!dev) {
+ kfree_skb(skb);
+ return -ENODEV;
+ }
+ }
/* Packet is looped back after forward, it should not be
* forwarded second time, but still can be delivered locally.
@@ -1966,7 +1980,7 @@
/* already under rcu_read_lock() */
cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr);
if (!cache) {
- int vif = ipmr_find_vif(mrt, skb->dev);
+ int vif = ipmr_find_vif(mrt, dev);
if (vif >= 0)
cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr,
@@ -1986,7 +2000,7 @@
}
read_lock(&mrt_lock);
- vif = ipmr_find_vif(mrt, skb->dev);
+ vif = ipmr_find_vif(mrt, dev);
if (vif >= 0) {
int err2 = ipmr_cache_unresolved(mrt, vif, skb);
read_unlock(&mrt_lock);
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 574f7eb..ac8342d 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -252,16 +252,16 @@
if (set_h245_addr(skb, protoff, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
htons((port & htons(1)) ? nated_port + 1 :
- nated_port)) == 0) {
- /* Save ports */
- info->rtp_port[i][dir] = rtp_port;
- info->rtp_port[i][!dir] = htons(nated_port);
- } else {
+ nated_port))) {
nf_ct_unexpect_related(rtp_exp);
nf_ct_unexpect_related(rtcp_exp);
return -1;
}
+ /* Save ports */
+ info->rtp_port[i][dir] = rtp_port;
+ info->rtp_port[i][!dir] = htons(nated_port);
+
/* Success */
pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
&rtp_exp->tuple.src.u3.ip,
@@ -370,15 +370,15 @@
/* Modify signal */
if (set_h225_addr(skb, protoff, data, dataoff, taddr,
&ct->tuplehash[!dir].tuple.dst.u3,
- htons(nated_port)) == 0) {
- /* Save ports */
- info->sig_port[dir] = port;
- info->sig_port[!dir] = htons(nated_port);
- } else {
+ htons(nated_port))) {
nf_ct_unexpect_related(exp);
return -1;
}
+ /* Save ports */
+ info->sig_port[dir] = port;
+ info->sig_port[!dir] = htons(nated_port);
+
pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
&exp->tuple.src.u3.ip,
ntohs(exp->tuple.src.u.tcp.port),
@@ -462,24 +462,27 @@
/* Modify signal */
if (set_h225_addr(skb, protoff, data, 0, &taddr[idx],
&ct->tuplehash[!dir].tuple.dst.u3,
- htons(nated_port)) == 0) {
- /* Save ports */
- info->sig_port[dir] = port;
- info->sig_port[!dir] = htons(nated_port);
-
- /* Fix for Gnomemeeting */
- if (idx > 0 &&
- get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
- (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
- set_h225_addr(skb, protoff, data, 0, &taddr[0],
- &ct->tuplehash[!dir].tuple.dst.u3,
- info->sig_port[!dir]);
- }
- } else {
+ htons(nated_port))) {
nf_ct_unexpect_related(exp);
return -1;
}
+ /* Save ports */
+ info->sig_port[dir] = port;
+ info->sig_port[!dir] = htons(nated_port);
+
+ /* Fix for Gnomemeeting */
+ if (idx > 0 &&
+ get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
+ (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
+ if (set_h225_addr(skb, protoff, data, 0, &taddr[0],
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ info->sig_port[!dir])) {
+ nf_ct_unexpect_related(exp);
+ return -1;
+ }
+ }
+
/* Success */
pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
&exp->tuple.src.u3.ip,
@@ -550,9 +553,9 @@
}
/* Modify signal */
- if (!set_h225_addr(skb, protoff, data, dataoff, taddr,
- &ct->tuplehash[!dir].tuple.dst.u3,
- htons(nated_port)) == 0) {
+ if (set_h225_addr(skb, protoff, data, dataoff, taddr,
+ &ct->tuplehash[!dir].tuple.dst.u3,
+ htons(nated_port))) {
nf_ct_unexpect_related(exp);
return -1;
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c14c213..16d3619 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -116,6 +116,7 @@
#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */
#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */
#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */
+#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */
#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED)
#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED)
@@ -3619,7 +3620,8 @@
if (before(ack, prior_snd_una)) {
/* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */
if (before(ack, prior_snd_una - tp->max_window)) {
- tcp_send_challenge_ack(sk, skb);
+ if (!(flag & FLAG_NO_CHALLENGE_ACK))
+ tcp_send_challenge_ack(sk, skb);
return -1;
}
goto old_ack;
@@ -5971,13 +5973,17 @@
/* step 5: check the ACK field */
acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH |
- FLAG_UPDATE_TS_RECENT) > 0;
+ FLAG_UPDATE_TS_RECENT |
+ FLAG_NO_CHALLENGE_ACK) > 0;
+ if (!acceptable) {
+ if (sk->sk_state == TCP_SYN_RECV)
+ return 1; /* send one RST */
+ tcp_send_challenge_ack(sk, skb);
+ goto discard;
+ }
switch (sk->sk_state) {
case TCP_SYN_RECV:
- if (!acceptable)
- return 1;
-
if (!tp->srtt_us)
tcp_synack_rtt_meas(sk, req);
@@ -6047,14 +6053,6 @@
* our SYNACK so stop the SYNACK timer.
*/
if (req) {
- /* Return RST if ack_seq is invalid.
- * Note that RFC793 only says to generate a
- * DUPACK for it but for TCP Fast Open it seems
- * better to treat this case like TCP_SYN_RECV
- * above.
- */
- if (!acceptable)
- return 1;
/* We no longer need the request sock. */
reqsk_fastopen_remove(sk, req, false);
tcp_rearm_rto(sk);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a5c1ff3..9077060 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -994,7 +994,10 @@
INIT_HLIST_NODE(&ifa->addr_lst);
ifa->scope = scope;
ifa->prefix_len = pfxlen;
- ifa->flags = flags | IFA_F_TENTATIVE;
+ ifa->flags = flags;
+ /* No need to add the TENTATIVE flag for addresses with NODAD */
+ if (!(flags & IFA_F_NODAD))
+ ifa->flags |= IFA_F_TENTATIVE;
ifa->valid_lft = valid_lft;
ifa->prefered_lft = prefered_lft;
ifa->cstamp = ifa->tstamp = jiffies;
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 189eb10..e742c4d 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -423,7 +423,9 @@
ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
sg_init_table(sg, nfrags + sglists);
- skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ if (unlikely(err < 0))
+ goto out_free;
if (x->props.flags & XFRM_STATE_ESN) {
/* Attach seqhi sg right after packet payload */
@@ -603,7 +605,9 @@
ip6h->hop_limit = 0;
sg_init_table(sg, nfrags + sglists);
- skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
+ if (unlikely(err < 0))
+ goto out_free;
if (x->props.flags & XFRM_STATE_ESN) {
/* Attach seqhi sg right after packet payload */
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index cbcdd5d..44a2010 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -248,9 +248,11 @@
esph->spi = x->id.spi;
sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg,
- (unsigned char *)esph - skb->data,
- assoclen + ivlen + clen + alen);
+ err = skb_to_sgvec(skb, sg,
+ (unsigned char *)esph - skb->data,
+ assoclen + ivlen + clen + alen);
+ if (unlikely(err < 0))
+ goto error;
aead_request_set_crypt(req, sg, sg, ivlen + clen, iv);
aead_request_set_ad(req, assoclen);
@@ -423,7 +425,9 @@
}
sg_init_table(sg, nfrags);
- skb_to_sgvec(skb, sg, 0, skb->len);
+ ret = skb_to_sgvec(skb, sg, 0, skb->len);
+ if (unlikely(ret < 0))
+ goto out;
aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
aead_request_set_ad(req, assoclen);
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 21bd54f..a88aff0 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -319,11 +319,13 @@
if (t || !create)
return t;
- if (parms->name[0])
+ if (parms->name[0]) {
+ if (!dev_valid_name(parms->name))
+ return NULL;
strlcpy(name, parms->name, IFNAMSIZ);
- else
+ } else {
strcpy(name, "ip6gre%d");
-
+ }
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ip6gre_tunnel_setup);
if (!dev)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 55ca65c..de0188e 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -365,6 +365,11 @@
static inline int ip6_forward_finish(struct net *net, struct sock *sk,
struct sk_buff *skb)
{
+ struct dst_entry *dst = skb_dst(skb);
+
+ __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
+ __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
+
return dst_output(net, sk, skb);
}
@@ -558,8 +563,6 @@
hdr->hop_limit--;
- __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
- __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len);
return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD,
net, NULL, skb, skb->dev, dst->dev,
ip6_forward_finish);
@@ -1276,7 +1279,7 @@
if (np->frag_size)
mtu = np->frag_size;
}
- if (mtu < IPV6_MIN_MTU)
+ if (!(rt->dst.flags & DST_XFRM_TUNNEL) && mtu < IPV6_MIN_MTU)
return -EINVAL;
cork->base.fragsize = mtu;
if (dst_allfrag(rt->dst.path))
@@ -1299,7 +1302,7 @@
const struct sockcm_cookie *sockc)
{
struct sk_buff *skb, *skb_prev = NULL;
- unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
+ unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
int exthdrlen = 0;
int dst_exthdrlen = 0;
int hh_len;
@@ -1335,6 +1338,12 @@
sizeof(struct frag_hdr) : 0) +
rt->rt6i_nfheader_len;
+ /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
+ * the first fragment
+ */
+ if (headersize + transhdrlen > mtu)
+ goto emsgsize;
+
if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
(sk->sk_protocol == IPPROTO_UDP ||
sk->sk_protocol == IPPROTO_RAW)) {
@@ -1350,9 +1359,8 @@
if (cork->length + length > maxnonfragsize - headersize) {
emsgsize:
- ipv6_local_error(sk, EMSGSIZE, fl6,
- mtu - headersize +
- sizeof(struct ipv6hdr));
+ pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0);
+ ipv6_local_error(sk, EMSGSIZE, fl6, pmtu);
return -EMSGSIZE;
}
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 8ff62e4..f338848 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -298,13 +298,16 @@
struct net_device *dev;
struct ip6_tnl *t;
char name[IFNAMSIZ];
- int err = -ENOMEM;
+ int err = -E2BIG;
- if (p->name[0])
+ if (p->name[0]) {
+ if (!dev_valid_name(p->name))
+ goto failed;
strlcpy(name, p->name, IFNAMSIZ);
- else
+ } else {
sprintf(name, "ip6tnl%%d");
-
+ }
+ err = -ENOMEM;
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ip6_tnl_dev_setup);
if (!dev)
@@ -1097,6 +1100,9 @@
if (!dst) {
route_lookup:
+ /* add dsfield to flowlabel for route lookup */
+ fl6->flowlabel = ip6_make_flowinfo(dsfield, fl6->flowlabel);
+
dst = ip6_route_output(net, NULL, fl6);
if (dst->error)
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c
index 2e3f4f1..5ae1681 100644
--- a/net/ipv6/ip6_vti.c
+++ b/net/ipv6/ip6_vti.c
@@ -212,10 +212,13 @@
char name[IFNAMSIZ];
int err;
- if (p->name[0])
+ if (p->name[0]) {
+ if (!dev_valid_name(p->name))
+ goto failed;
strlcpy(name, p->name, IFNAMSIZ);
- else
+ } else {
sprintf(name, "ip6_vti%%d");
+ }
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup);
if (!dev)
@@ -626,7 +629,6 @@
{
struct net_device *dev = t->dev;
struct __ip6_tnl_parm *p = &t->parms;
- struct net_device *tdev = NULL;
memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
@@ -639,25 +641,6 @@
dev->flags |= IFF_POINTOPOINT;
else
dev->flags &= ~IFF_POINTOPOINT;
-
- if (p->flags & IP6_TNL_F_CAP_XMIT) {
- int strict = (ipv6_addr_type(&p->raddr) &
- (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
- struct rt6_info *rt = rt6_lookup(t->net,
- &p->raddr, &p->laddr,
- p->link, strict);
-
- if (rt)
- tdev = rt->dst.dev;
- ip6_rt_put(rt);
- }
-
- if (!tdev && p->link)
- tdev = __dev_get_by_index(t->net, p->link);
-
- if (tdev)
- dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len,
- IPV6_MIN_MTU);
}
/**
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 0d54cc5..96be019 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -847,6 +847,9 @@
struct fib6_node *fn;
struct rt6_info *rt;
+ if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
+ flags &= ~RT6_LOOKUP_F_IFACE;
+
read_lock_bh(&table->tb6_lock);
fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
restart:
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index d4d84da..dcb2921 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -244,11 +244,13 @@
if (!create)
goto failed;
- if (parms->name[0])
+ if (parms->name[0]) {
+ if (!dev_valid_name(parms->name))
+ goto failed;
strlcpy(name, parms->name, IFNAMSIZ);
- else
+ } else {
strcpy(name, "sit%d");
-
+ }
dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN,
ipip6_tunnel_setup);
if (!dev)
@@ -657,6 +659,7 @@
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/key/af_key.c b/net/key/af_key.c
index 6482b00..15150b4 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3305,7 +3305,7 @@
p += pol->sadb_x_policy_len*8;
sec_ctx = (struct sadb_x_sec_ctx *)p;
if (len < pol->sadb_x_policy_len*8 +
- sec_ctx->sadb_x_sec_len) {
+ sec_ctx->sadb_x_sec_len*8) {
*dir = -EINVAL;
goto out;
}
diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c
index ee03bc8..ce12384 100644
--- a/net/l2tp/l2tp_netlink.c
+++ b/net/l2tp/l2tp_netlink.c
@@ -750,6 +750,8 @@
if ((session->ifname[0] &&
nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) ||
+ (session->offset &&
+ nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) ||
(session->cookie_len &&
nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len,
&session->cookie[0])) ||
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index db916cf..f7caf0f 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -309,6 +309,8 @@
int rc = -EINVAL;
dprintk("%s: binding %02X\n", __func__, addr->sllc_sap);
+
+ lock_sock(sk);
if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr)))
goto out;
rc = -EAFNOSUPPORT;
@@ -380,6 +382,7 @@
out_put:
llc_sap_put(sap);
out:
+ release_sock(sk);
return rc;
}
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index efa2a2f..d7801f6 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2341,10 +2341,17 @@
struct ieee80211_sub_if_data *sdata;
enum nl80211_tx_power_setting txp_type = type;
bool update_txp_type = false;
+ bool has_monitor = false;
if (wdev) {
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ sdata = rtnl_dereference(local->monitor_sdata);
+ if (!sdata)
+ return -EOPNOTSUPP;
+ }
+
switch (type) {
case NL80211_TX_POWER_AUTOMATIC:
sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
@@ -2383,15 +2390,34 @@
mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR) {
+ has_monitor = true;
+ continue;
+ }
sdata->user_power_level = local->user_power_level;
if (txp_type != sdata->vif.bss_conf.txpower_type)
update_txp_type = true;
sdata->vif.bss_conf.txpower_type = txp_type;
}
- list_for_each_entry(sdata, &local->interfaces, list)
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+ continue;
ieee80211_recalc_txpower(sdata, update_txp_type);
+ }
mutex_unlock(&local->iflist_mtx);
+ if (has_monitor) {
+ sdata = rtnl_dereference(local->monitor_sdata);
+ if (sdata) {
+ sdata->user_power_level = local->user_power_level;
+ if (txp_type != sdata->vif.bss_conf.txpower_type)
+ update_txp_type = true;
+ sdata->vif.bss_conf.txpower_type = txp_type;
+
+ ieee80211_recalc_txpower(sdata, update_txp_type);
+ }
+ }
+
return 0;
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 09f77e4..49c8a9c 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -164,7 +164,8 @@
if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE ||
sdata->vif.type == NL80211_IFTYPE_NAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
- !sdata->vif.mu_mimo_owner)))
+ !sdata->vif.mu_mimo_owner &&
+ !(changed & BSS_CHANGED_TXPOWER))))
return;
if (!check_sdata_in_driver(sdata))
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index d31818e..a5acaf1 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -427,7 +427,7 @@
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
cfg80211_chandef_create(&chandef, cbss->channel,
- NL80211_CHAN_WIDTH_20_NOHT);
+ NL80211_CHAN_NO_HT);
chandef.width = sdata->u.ibss.chandef.width;
break;
case NL80211_CHAN_WIDTH_80:
@@ -439,7 +439,7 @@
default:
/* fall back to 20 MHz for unsupported modes */
cfg80211_chandef_create(&chandef, cbss->channel,
- NL80211_CHAN_WIDTH_20_NOHT);
+ NL80211_CHAN_NO_HT);
break;
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0519edb..973adf3 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4332,6 +4332,10 @@
if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data))
return -EINVAL;
+ /* If a reconfig is happening, bail out */
+ if (local->in_reconfig)
+ return -EBUSY;
+
if (assoc) {
rcu_read_lock();
have_sta = sta_info_get(sdata, cbss->bssid);
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index dbceb42..e6096df 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -173,9 +173,11 @@
/* try default if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo);
- /* try built-in one if specific alg requested but not found */
- if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
+ /* Note: check for > 0 is intentional to avoid clang warning */
+ if (!ops && (strlen(CONFIG_MAC80211_RC_DEFAULT) > 0))
+ /* try built-in one if specific alg requested but not found */
ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
+
kernel_param_unlock(THIS_MODULE);
return ops;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index f66c08f..18e96a2 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1621,7 +1621,6 @@
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
struct hlist_nulls_node *n;
- int cpu;
spinlock_t *lockp;
for (; *bucket < nf_conntrack_htable_size; (*bucket)++) {
@@ -1643,18 +1642,6 @@
cond_resched();
}
- for_each_possible_cpu(cpu) {
- struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
-
- spin_lock_bh(&pcpu->lock);
- hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
- ct = nf_ct_tuplehash_to_ctrack(h);
- if (iter(ct, data))
- set_bit(IPS_DYING_BIT, &ct->status);
- }
- spin_unlock_bh(&pcpu->lock);
- cond_resched();
- }
return NULL;
found:
atomic_inc(&ct->ct_general.use);
@@ -1663,6 +1650,34 @@
return ct;
}
+static void
+__nf_ct_unconfirmed_destroy(struct net *net)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct nf_conntrack_tuple_hash *h;
+ struct hlist_nulls_node *n;
+ struct ct_pcpu *pcpu;
+
+ pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
+
+ spin_lock_bh(&pcpu->lock);
+ hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) {
+ struct nf_conn *ct;
+
+ ct = nf_ct_tuplehash_to_ctrack(h);
+
+ /* we cannot call iter() on unconfirmed list, the
+ * owning cpu can reallocate ct->ext at any time.
+ */
+ set_bit(IPS_DYING_BIT, &ct->status);
+ }
+ spin_unlock_bh(&pcpu->lock);
+ cond_resched();
+ }
+}
+
void nf_ct_iterate_cleanup(struct net *net,
int (*iter)(struct nf_conn *i, void *data),
void *data, u32 portid, int report)
@@ -1675,6 +1690,10 @@
if (atomic_read(&net->ct.count) == 0)
return;
+ __nf_ct_unconfirmed_destroy(net);
+
+ synchronize_net();
+
while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) {
/* Time to push up daises... */
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 3c37253..c9ca529 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -894,8 +894,13 @@
}
out:
local_bh_enable();
- if (last)
+ if (last) {
+ /* nf ct hash resize happened, now clear the leftover. */
+ if ((struct nf_conn *)cb->args[1] == last)
+ cb->args[1] = 0;
+
nf_ct_put(last);
+ }
while (i) {
i--;
@@ -1012,9 +1017,8 @@
static int
ctnetlink_parse_tuple(const struct nlattr * const cda[],
- struct nf_conntrack_tuple *tuple,
- enum ctattr_type type, u_int8_t l3num,
- struct nf_conntrack_zone *zone)
+ struct nf_conntrack_tuple *tuple, u32 type,
+ u_int8_t l3num, struct nf_conntrack_zone *zone)
{
struct nlattr *tb[CTA_TUPLE_MAX+1];
int err;
@@ -2424,7 +2428,7 @@
static int ctnetlink_exp_dump_tuple(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple,
- enum ctattr_expect type)
+ u32 type)
{
struct nlattr *nest_parms;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 7ad1a86..59be898 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -367,6 +367,36 @@
return buf;
}
+/**
+ * xt_check_proc_name - check that name is suitable for /proc file creation
+ *
+ * @name: file name candidate
+ * @size: length of buffer
+ *
+ * some x_tables modules wish to create a file in /proc.
+ * This function makes sure that the name is suitable for this
+ * purpose, it checks that name is NUL terminated and isn't a 'special'
+ * name, like "..".
+ *
+ * returns negative number on error or 0 if name is useable.
+ */
+int xt_check_proc_name(const char *name, unsigned int size)
+{
+ if (name[0] == '\0')
+ return -EINVAL;
+
+ if (strnlen(name, size) == size)
+ return -ENAMETOOLONG;
+
+ if (strcmp(name, ".") == 0 ||
+ strcmp(name, "..") == 0 ||
+ strchr(name, '/'))
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL(xt_check_proc_name);
+
int xt_check_match(struct xt_mtchk_param *par,
unsigned int size, u_int8_t proto, bool inv_proto)
{
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index b89b688..a1a29cd 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -794,8 +794,9 @@
struct hashlimit_cfg2 cfg = {};
int ret;
- if (info->name[sizeof(info->name) - 1] != '\0')
- return -EINVAL;
+ ret = xt_check_proc_name(info->name, sizeof(info->name));
+ if (ret)
+ return ret;
ret = cfg_copy(&cfg, (void *)&info->cfg, 1);
@@ -809,9 +810,11 @@
static int hashlimit_mt_check(const struct xt_mtchk_param *par)
{
struct xt_hashlimit_mtinfo2 *info = par->matchinfo;
+ int ret;
- if (info->name[sizeof(info->name) - 1] != '\0')
- return -EINVAL;
+ ret = xt_check_proc_name(info->name, sizeof(info->name));
+ if (ret)
+ return ret;
return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg,
info->name, 2);
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index e3b7a09..79d7ad6 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -361,9 +361,9 @@
info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
return -EINVAL;
}
- if (info->name[0] == '\0' ||
- strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
- return -EINVAL;
+ ret = xt_check_proc_name(info->name, sizeof(info->name));
+ if (ret)
+ return ret;
if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot)
nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1;
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index c1f59a0..1e97b8d 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1054,6 +1054,9 @@
if (addr->sa_family != AF_NETLINK)
return -EINVAL;
+ if (alen < sizeof(struct sockaddr_nl))
+ return -EINVAL;
+
if ((nladdr->nl_groups || nladdr->nl_pid) &&
!netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
return -EPERM;
diff --git a/net/rds/bind.c b/net/rds/bind.c
index 095f6ce..adb53ae 100644
--- a/net/rds/bind.c
+++ b/net/rds/bind.c
@@ -114,6 +114,7 @@
rs, &addr, (int)ntohs(*port));
break;
} else {
+ rs->rs_bound_addr = 0;
rds_sock_put(rs);
ret = -ENOMEM;
break;
diff --git a/net/rds/send.c b/net/rds/send.c
index ef53d164..50241d3 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006 Oracle. All rights reserved.
+ * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -983,10 +983,15 @@
if (conn->c_npaths == 0 && hash != 0) {
rds_send_ping(conn);
- if (conn->c_npaths == 0) {
- wait_event_interruptible(conn->c_hs_waitq,
- (conn->c_npaths != 0));
- }
+ /* The underlying connection is not up yet. Need to wait
+ * until it is up to be sure that the non-zero c_path can be
+ * used. But if we are interrupted, we have to use the zero
+ * c_path in case the connection ends up being non-MP capable.
+ */
+ if (conn->c_npaths == 0)
+ if (wait_event_interruptible(conn->c_hs_waitq,
+ conn->c_npaths != 0))
+ hash = 0;
if (conn->c_npaths == 1)
hash = 0;
}
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 4374e7b..90df95e 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -229,7 +229,9 @@
len &= ~(call->conn->size_align - 1);
sg_init_table(sg, nsg);
- skb_to_sgvec(skb, sg, 0, len);
+ err = skb_to_sgvec(skb, sg, 0, len);
+ if (unlikely(err < 0))
+ goto out;
skcipher_request_set_crypt(req, sg, sg, len, iv.x);
crypto_skcipher_encrypt(req);
@@ -325,7 +327,7 @@
struct sk_buff *trailer;
u32 data_size, buf;
u16 check;
- int nsg;
+ int nsg, ret;
_enter("");
@@ -342,7 +344,9 @@
goto nomem;
sg_init_table(sg, nsg);
- skb_to_sgvec(skb, sg, offset, 8);
+ ret = skb_to_sgvec(skb, sg, offset, 8);
+ if (unlikely(ret < 0))
+ return ret;
/* start the decryption afresh */
memset(&iv, 0, sizeof(iv));
@@ -405,7 +409,7 @@
struct sk_buff *trailer;
u32 data_size, buf;
u16 check;
- int nsg;
+ int nsg, ret;
_enter(",{%d}", skb->len);
@@ -429,7 +433,12 @@
}
sg_init_table(sg, nsg);
- skb_to_sgvec(skb, sg, offset, len);
+ ret = skb_to_sgvec(skb, sg, offset, len);
+ if (unlikely(ret < 0)) {
+ if (sg != _sg)
+ kfree(sg);
+ return ret;
+ }
/* decrypt from the session key */
token = call->conn->params.key->payload.data[0];
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index f311732..67adb4e 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -95,8 +95,10 @@
continue;
nest = nla_nest_start(skb, n_i);
- if (nest == NULL)
+ if (nest == NULL) {
+ index--;
goto nla_put_failure;
+ }
err = tcf_action_dump_1(skb, p, 0, 0);
if (err < 0) {
index--;
diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c
index 1d39600..40496f3 100644
--- a/net/sched/act_bpf.c
+++ b/net/sched/act_bpf.c
@@ -245,10 +245,14 @@
static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg)
{
- if (cfg->is_ebpf)
- bpf_prog_put(cfg->filter);
- else
- bpf_prog_destroy(cfg->filter);
+ struct bpf_prog *filter = cfg->filter;
+
+ if (filter) {
+ if (cfg->is_ebpf)
+ bpf_prog_put(filter);
+ else
+ bpf_prog_destroy(filter);
+ }
kfree(cfg->bpf_ops);
kfree(cfg->bpf_name);
diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c
index f85313d..bd8e86c 100644
--- a/net/sched/act_skbmod.c
+++ b/net/sched/act_skbmod.c
@@ -192,7 +192,8 @@
struct tcf_skbmod_params *p;
p = rcu_dereference_protected(d->skbmod_p, 1);
- kfree_rcu(p, rcu);
+ if (p)
+ kfree_rcu(p, rcu);
}
static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a,
diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c
index b6e3abe..901fb8b 100644
--- a/net/sched/act_tunnel_key.c
+++ b/net/sched/act_tunnel_key.c
@@ -196,11 +196,12 @@
struct tcf_tunnel_key_params *params;
params = rcu_dereference_protected(t->params, 1);
+ if (params) {
+ if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
+ dst_release(¶ms->tcft_enc_metadata->dst);
- if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
- dst_release(¶ms->tcft_enc_metadata->dst);
-
- kfree_rcu(params, rcu);
+ kfree_rcu(params, rcu);
+ }
}
static int tunnel_key_dump_addresses(struct sk_buff *skb,
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 11f69d4..355d95a7 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -727,8 +727,10 @@
sctp_v6_map_v4(addr);
}
- if (addr->sa.sa_family == AF_INET)
+ if (addr->sa.sa_family == AF_INET) {
+ memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
return sizeof(struct sockaddr_in);
+ }
return sizeof(struct sockaddr_in6);
}
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 8cdd6bb..78f3805 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -335,11 +335,14 @@
if (!opt->pf->af_supported(addr->sa.sa_family, opt))
return NULL;
- /* V4 mapped address are really of AF_INET family */
- if (addr->sa.sa_family == AF_INET6 &&
- ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
- !opt->pf->af_supported(AF_INET, opt))
- return NULL;
+ if (addr->sa.sa_family == AF_INET6) {
+ if (len < SIN6_LEN_RFC2133)
+ return NULL;
+ /* V4 mapped address are really of AF_INET family */
+ if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) &&
+ !opt->pf->af_supported(AF_INET, opt))
+ return NULL;
+ }
/* If we get this far, af is valid. */
af = sctp_get_af_specific(addr->sa.sa_family);
@@ -1519,7 +1522,7 @@
pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout);
- lock_sock(sk);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
sk->sk_shutdown = SHUTDOWN_MASK;
sk->sk_state = SCTP_SS_CLOSING;
@@ -1569,7 +1572,7 @@
* held and that should be grabbed before socket lock.
*/
spin_lock_bh(&net->sctp.addr_wq_lock);
- bh_lock_sock(sk);
+ bh_lock_sock_nested(sk);
/* Hold the sock, since sk_common_release() will put sock_put()
* and we have just a little more cleanup.
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
index b5c279b..6cbc935 100644
--- a/net/strparser/strparser.c
+++ b/net/strparser/strparser.c
@@ -59,7 +59,7 @@
strp->rx_stopped = 1;
/* Report an error on the lower socket */
- csk->sk_err = err;
+ csk->sk_err = -err;
csk->sk_error_report(csk);
}
@@ -422,7 +422,7 @@
/* Message assembly timed out */
STRP_STATS_INCR(strp->stats.rx_msg_timeouts);
lock_sock(strp->sk);
- strp->cb.abort_parser(strp, ETIMEDOUT);
+ strp->cb.abort_parser(strp, -ETIMEDOUT);
release_sock(strp->sk);
}
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index 79aec90..4afd414 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -237,9 +237,6 @@
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
- err = crypto_ahash_init(req);
- if (err)
- goto out;
err = crypto_ahash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength);
if (err)
goto out;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 61a504f..34f9405 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -1375,6 +1375,7 @@
struct dentry *clnt_dir = pipe_dentry->d_parent;
struct dentry *gssd_dir = clnt_dir->d_parent;
+ dget(pipe_dentry);
__rpc_rmpipe(d_inode(clnt_dir), pipe_dentry);
__rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
__rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index d24d14e..1bf9153 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2384,7 +2384,12 @@
case -EHOSTUNREACH:
case -EADDRINUSE:
case -ENOBUFS:
- /* retry with existing socket, after a delay */
+ /*
+ * xs_tcp_force_close() wakes tasks with -EIO.
+ * We need to wake them first to ensure the
+ * correct error code.
+ */
+ xprt_wake_pending_tasks(xprt, status);
xs_tcp_force_close(xprt);
goto out;
}
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 76e308f..f00e7d3 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4133,7 +4133,7 @@
struct nlattr *rate;
u32 bitrate;
u16 bitrate_compat;
- enum nl80211_attrs rate_flg;
+ enum nl80211_rate_info rate_flg;
rate = nla_nest_start(msg, attr);
if (!rate)
@@ -14868,7 +14868,8 @@
if (!ft_event->target_ap)
return;
- msg = nlmsg_new(100 + ft_event->ric_ies_len, GFP_KERNEL);
+ msg = nlmsg_new(100 + ft_event->ies_len + ft_event->ric_ies_len,
+ GFP_KERNEL);
if (!msg)
return;
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index bc0ebd4..9195f23 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -2142,6 +2142,21 @@
reg_free_request(reg_request);
}
+static void notify_self_managed_wiphys(struct regulatory_request *request)
+{
+ struct cfg80211_registered_device *rdev;
+ struct wiphy *wiphy;
+
+ list_for_each_entry(rdev, &cfg80211_rdev_list, list) {
+ wiphy = &rdev->wiphy;
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED &&
+ request->initiator == NL80211_REGDOM_SET_BY_USER &&
+ request->user_reg_hint_type ==
+ NL80211_USER_REG_HINT_CELL_BASE)
+ reg_call_notifier(wiphy, request);
+ }
+}
+
static bool reg_only_self_managed_wiphys(void)
{
struct cfg80211_registered_device *rdev;
@@ -2193,6 +2208,7 @@
spin_unlock(®_requests_lock);
+ notify_self_managed_wiphys(reg_request);
if (reg_only_self_managed_wiphys()) {
reg_free_request(reg_request);
return;
@@ -3073,17 +3089,26 @@
void wiphy_regulatory_register(struct wiphy *wiphy)
{
- struct regulatory_request *lr;
+ struct regulatory_request *lr = get_last_request();
- /* self-managed devices ignore external hints */
- if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED)
+ /* self-managed devices ignore beacon hints and country IE */
+ if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS |
REGULATORY_COUNTRY_IE_IGNORE;
+ /*
+ * The last request may have been received before this
+ * registration call. Call the driver notifier if
+ * initiator is USER and user type is CELL_BASE.
+ */
+ if (lr->initiator == NL80211_REGDOM_SET_BY_USER &&
+ lr->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE)
+ reg_call_notifier(wiphy, lr);
+ }
+
if (!reg_dev_ignore_cell_hint(wiphy))
reg_num_devs_support_basehint++;
- lr = get_last_request();
wiphy_update_regulatory(wiphy, lr->initiator);
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 29c5661..13ff407 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -549,7 +549,7 @@
int offset, int len)
{
struct skb_shared_info *sh = skb_shinfo(skb);
- const skb_frag_t *frag = &sh->frags[-1];
+ const skb_frag_t *frag = &sh->frags[0];
struct page *frag_page;
void *frag_ptr;
int frag_len, frag_size;
@@ -562,10 +562,10 @@
while (offset >= frag_size) {
offset -= frag_size;
- frag++;
frag_page = skb_frag_page(frag);
frag_ptr = skb_frag_address(frag);
frag_size = skb_frag_size(frag);
+ frag++;
}
frag_ptr += offset;
@@ -577,12 +577,12 @@
len -= cur_len;
while (len > 0) {
- frag++;
frag_len = skb_frag_size(frag);
cur_len = min(len, frag_len);
__frame_add_frag(frame, skb_frag_page(frag),
skb_frag_address(frag), cur_len, frag_len);
len -= cur_len;
+ frag++;
}
}
diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c
index f83b74d..0077216 100644
--- a/net/x25/af_x25.c
+++ b/net/x25/af_x25.c
@@ -1790,32 +1790,40 @@
static int __init x25_init(void)
{
- int rc = proto_register(&x25_proto, 0);
+ int rc;
- if (rc != 0)
+ rc = proto_register(&x25_proto, 0);
+ if (rc)
goto out;
rc = sock_register(&x25_family_ops);
- if (rc != 0)
+ if (rc)
goto out_proto;
dev_add_pack(&x25_packet_type);
rc = register_netdevice_notifier(&x25_dev_notifier);
- if (rc != 0)
+ if (rc)
goto out_sock;
+ rc = x25_register_sysctl();
+ if (rc)
+ goto out_dev;
+
+ rc = x25_proc_init();
+ if (rc)
+ goto out_sysctl;
+
pr_info("Linux Version 0.2\n");
- x25_register_sysctl();
- rc = x25_proc_init();
- if (rc != 0)
- goto out_dev;
out:
return rc;
+out_sysctl:
+ x25_unregister_sysctl();
out_dev:
unregister_netdevice_notifier(&x25_dev_notifier);
out_sock:
+ dev_remove_pack(&x25_packet_type);
sock_unregister(AF_X25);
out_proto:
proto_unregister(&x25_proto);
diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c
index 4323952..703d46a 100644
--- a/net/x25/sysctl_net_x25.c
+++ b/net/x25/sysctl_net_x25.c
@@ -73,9 +73,12 @@
{ 0, },
};
-void __init x25_register_sysctl(void)
+int __init x25_register_sysctl(void)
{
x25_table_header = register_net_sysctl(&init_net, "net/x25", x25_table);
+ if (!x25_table_header)
+ return -ENOMEM;
+ return 0;
}
void x25_unregister_sysctl(void)
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c
index ccfdc71..a00ec71 100644
--- a/net/xfrm/xfrm_ipcomp.c
+++ b/net/xfrm/xfrm_ipcomp.c
@@ -283,7 +283,7 @@
struct crypto_comp *tfm;
/* This can be any valid CPU ID so we don't need locking. */
- tfm = __this_cpu_read(*pos->tfms);
+ tfm = this_cpu_read(*pos->tfms);
if (!strcmp(crypto_comp_name(tfm), alg_name)) {
pos->users++;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 74f2e8f..d869b1d 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -1246,6 +1246,8 @@
x->curlft.add_time = orig->curlft.add_time;
x->km.state = orig->km.state;
x->km.seq = orig->km.seq;
+ x->replay = orig->replay;
+ x->preplay = orig->preplay;
return x;
@@ -1883,6 +1885,11 @@
struct xfrm_mgr *km;
struct xfrm_policy *pol = NULL;
+#ifdef CONFIG_COMPAT
+ if (in_compat_syscall())
+ return -EOPNOTSUPP;
+#endif
+
if (!optval && !optlen) {
xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 3b3455a..35e60d3 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -121,22 +121,17 @@
struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
struct xfrm_replay_state_esn *rs;
- if (p->flags & XFRM_STATE_ESN) {
- if (!rt)
- return -EINVAL;
-
- rs = nla_data(rt);
-
- if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
- return -EINVAL;
-
- if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
- nla_len(rt) != sizeof(*rs))
- return -EINVAL;
- }
-
if (!rt)
- return 0;
+ return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
+
+ rs = nla_data(rt);
+
+ if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
+ return -EINVAL;
+
+ if (nla_len(rt) < xfrm_replay_state_esn_len(rs) &&
+ nla_len(rt) != sizeof(*rs))
+ return -EINVAL;
/* As only ESP and AH support ESN feature. */
if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
diff --git a/scripts/tags.sh b/scripts/tags.sh
index a2ff338..2a61db3 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -106,6 +106,7 @@
case "$i" in
*.[cS])
j=${i/\.[cS]/\.o}
+ j="${j#$tree}"
if [ -e $j ]; then
echo $i
fi
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 52f3c55..84d9a2e 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -348,26 +348,27 @@
struct avc_xperms_decision_node *xpd_node;
struct extended_perms_decision *xpd;
- xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, GFP_NOWAIT);
+ xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep,
+ GFP_NOWAIT | __GFP_NOWARN);
if (!xpd_node)
return NULL;
xpd = &xpd_node->xpd;
if (which & XPERMS_ALLOWED) {
xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep,
- GFP_NOWAIT);
+ GFP_NOWAIT | __GFP_NOWARN);
if (!xpd->allowed)
goto error;
}
if (which & XPERMS_AUDITALLOW) {
xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep,
- GFP_NOWAIT);
+ GFP_NOWAIT | __GFP_NOWARN);
if (!xpd->auditallow)
goto error;
}
if (which & XPERMS_DONTAUDIT) {
xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep,
- GFP_NOWAIT);
+ GFP_NOWAIT | __GFP_NOWARN);
if (!xpd->dontaudit)
goto error;
}
@@ -395,7 +396,8 @@
{
struct avc_xperms_node *xp_node;
- xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_NOWAIT);
+ xp_node = kmem_cache_zalloc(avc_xperms_cachep,
+ GFP_NOWAIT | __GFP_NOWARN);
if (!xp_node)
return xp_node;
INIT_LIST_HEAD(&xp_node->xpd_head);
@@ -548,7 +550,7 @@
{
struct avc_node *node;
- node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT);
+ node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT | __GFP_NOWARN);
if (!node)
goto out;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index da939fd..8e12ffe 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -407,18 +407,6 @@
kfree(sbsec);
}
-/* The file system's label must be initialized prior to use. */
-
-static const char *labeling_behaviors[7] = {
- "uses xattr",
- "uses transition SIDs",
- "uses task SIDs",
- "uses genfs_contexts",
- "not configured for labeling",
- "uses mountpoint labeling",
- "uses native labeling",
-};
-
static inline int inode_doinit(struct inode *inode)
{
return inode_doinit_with_dentry(inode, NULL);
@@ -530,10 +518,6 @@
}
}
- if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
- printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
- sb->s_id, sb->s_type->name);
-
sbsec->flags |= SE_SBINITIALIZED;
if (selinux_is_sblabel_mnt(sb))
sbsec->flags |= SBLABEL_MNT;
@@ -2062,8 +2046,9 @@
static inline u32 open_file_to_av(struct file *file)
{
u32 av = file_to_av(file);
+ struct inode *inode = file_inode(file);
- if (selinux_policycap_openperm)
+ if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC)
av |= FILE__OPEN;
return av;
@@ -3066,6 +3051,7 @@
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
{
const struct cred *cred = current_cred();
+ struct inode *inode = d_backing_inode(dentry);
unsigned int ia_valid = iattr->ia_valid;
__u32 av = FILE__WRITE;
@@ -3081,8 +3067,10 @@
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
return dentry_has_perm(cred, dentry, FILE__SETATTR);
- if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
- && !(ia_valid & ATTR_FILE))
+ if (selinux_policycap_openperm &&
+ inode->i_sb->s_magic != SOCKFS_MAGIC &&
+ (ia_valid & ATTR_SIZE) &&
+ !(ia_valid & ATTR_FILE))
av |= FILE__OPEN;
return dentry_has_perm(cred, dentry, av);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 66ea81c..9b517a4 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -154,7 +154,7 @@
}
k = 0;
- while (p_in->perms && p_in->perms[k]) {
+ while (p_in->perms[k]) {
/* An empty permission string skips ahead */
if (!*p_in->perms[k]) {
k++;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 3e7c357..cfb8f58 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -834,8 +834,25 @@
return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
}
-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
- bool trylock)
+/* parameter locking: returns immediately if tried during streaming */
+static int lock_params(struct snd_pcm_runtime *runtime)
+{
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ if (atomic_read(&runtime->oss.rw_ref)) {
+ mutex_unlock(&runtime->oss.params_lock);
+ return -EBUSY;
+ }
+ return 0;
+}
+
+static void unlock_params(struct snd_pcm_runtime *runtime)
+{
+ mutex_unlock(&runtime->oss.params_lock);
+}
+
+/* call with params_lock held */
+static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_pcm_hw_params *params, *sparams;
@@ -849,11 +866,8 @@
struct snd_mask sformat_mask;
struct snd_mask mask;
- if (trylock) {
- if (!(mutex_trylock(&runtime->oss.params_lock)))
- return -EAGAIN;
- } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
- return -EINTR;
+ if (!runtime->oss.params)
+ return 0;
sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
params = kmalloc(sizeof(*params), GFP_KERNEL);
sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
@@ -1079,6 +1093,23 @@
kfree(sw_params);
kfree(params);
kfree(sparams);
+ return err;
+}
+
+/* this one takes the lock by itself */
+static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
+ bool trylock)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ if (trylock) {
+ if (!(mutex_trylock(&runtime->oss.params_lock)))
+ return -EAGAIN;
+ } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+
+ err = snd_pcm_oss_change_params_locked(substream);
mutex_unlock(&runtime->oss.params_lock);
return err;
}
@@ -1107,6 +1138,10 @@
return 0;
}
+/* call with params_lock held */
+/* NOTE: this always call PREPARE unconditionally no matter whether
+ * runtime->oss.prepare is set or not
+ */
static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
{
int err;
@@ -1131,8 +1166,6 @@
struct snd_pcm_runtime *runtime;
int err;
- if (substream == NULL)
- return 0;
runtime = substream->runtime;
if (runtime->oss.params) {
err = snd_pcm_oss_change_params(substream, false);
@@ -1140,6 +1173,29 @@
return err;
}
if (runtime->oss.prepare) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ err = snd_pcm_oss_prepare(substream);
+ mutex_unlock(&runtime->oss.params_lock);
+ if (err < 0)
+ return err;
+ }
+ return 0;
+}
+
+/* call with params_lock held */
+static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime;
+ int err;
+
+ runtime = substream->runtime;
+ if (runtime->oss.params) {
+ err = snd_pcm_oss_change_params_locked(substream);
+ if (err < 0)
+ return err;
+ }
+ if (runtime->oss.prepare) {
err = snd_pcm_oss_prepare(substream);
if (err < 0)
return err;
@@ -1361,19 +1417,21 @@
static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
{
size_t xfer = 0;
- ssize_t tmp;
+ ssize_t tmp = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return -ENXIO;
- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
- return tmp;
+ atomic_inc(&runtime->oss.rw_ref);
while (bytes > 0) {
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
tmp = -ERESTARTSYS;
break;
}
+ tmp = snd_pcm_oss_make_ready_locked(substream);
+ if (tmp < 0)
+ goto err;
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
tmp = bytes;
if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
@@ -1429,6 +1487,7 @@
}
tmp = 0;
}
+ atomic_dec(&runtime->oss.rw_ref);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
@@ -1468,19 +1527,21 @@
static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
{
size_t xfer = 0;
- ssize_t tmp;
+ ssize_t tmp = 0;
struct snd_pcm_runtime *runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
return -ENXIO;
- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
- return tmp;
+ atomic_inc(&runtime->oss.rw_ref);
while (bytes > 0) {
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
tmp = -ERESTARTSYS;
break;
}
+ tmp = snd_pcm_oss_make_ready_locked(substream);
+ if (tmp < 0)
+ goto err;
if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
if (runtime->oss.buffer_used == 0) {
tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
@@ -1521,6 +1582,7 @@
}
tmp = 0;
}
+ atomic_dec(&runtime->oss.rw_ref);
return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
}
@@ -1536,10 +1598,12 @@
continue;
runtime = substream->runtime;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ mutex_lock(&runtime->oss.params_lock);
runtime->oss.prepare = 1;
runtime->oss.buffer_used = 0;
runtime->oss.prev_hw_ptr_period = 0;
runtime->oss.period_ptr = 0;
+ mutex_unlock(&runtime->oss.params_lock);
}
return 0;
}
@@ -1625,9 +1689,13 @@
goto __direct;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
return err;
+ atomic_inc(&runtime->oss.rw_ref);
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ atomic_dec(&runtime->oss.rw_ref);
+ return -ERESTARTSYS;
+ }
format = snd_pcm_oss_format_from(runtime->oss.format);
width = snd_pcm_format_physical_width(format);
- mutex_lock(&runtime->oss.params_lock);
if (runtime->oss.buffer_used > 0) {
#ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "sync: buffer_used\n");
@@ -1637,10 +1705,8 @@
runtime->oss.buffer + runtime->oss.buffer_used,
size);
err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
- if (err < 0) {
- mutex_unlock(&runtime->oss.params_lock);
- return err;
- }
+ if (err < 0)
+ goto unlock;
} else if (runtime->oss.period_ptr > 0) {
#ifdef OSS_DEBUG
pcm_dbg(substream->pcm, "sync: period_ptr\n");
@@ -1650,10 +1716,8 @@
runtime->oss.buffer,
size * 8 / width);
err = snd_pcm_oss_sync1(substream, size);
- if (err < 0) {
- mutex_unlock(&runtime->oss.params_lock);
- return err;
- }
+ if (err < 0)
+ goto unlock;
}
/*
* The ALSA's period might be a bit large than OSS one.
@@ -1684,7 +1748,11 @@
snd_pcm_lib_writev(substream, buffers, size);
}
}
+unlock:
mutex_unlock(&runtime->oss.params_lock);
+ atomic_dec(&runtime->oss.rw_ref);
+ if (err < 0)
+ return err;
/*
* finish sync: drain the buffer
*/
@@ -1695,7 +1763,9 @@
substream->f_flags = saved_f_flags;
if (err < 0)
return err;
+ mutex_lock(&runtime->oss.params_lock);
runtime->oss.prepare = 1;
+ mutex_unlock(&runtime->oss.params_lock);
}
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
@@ -1706,8 +1776,10 @@
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
if (err < 0)
return err;
+ mutex_lock(&runtime->oss.params_lock);
runtime->oss.buffer_used = 0;
runtime->oss.prepare = 1;
+ mutex_unlock(&runtime->oss.params_lock);
}
return 0;
}
@@ -1719,6 +1791,8 @@
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
struct snd_pcm_runtime *runtime;
+ int err;
+
if (substream == NULL)
continue;
runtime = substream->runtime;
@@ -1726,10 +1800,14 @@
rate = 1000;
else if (rate > 192000)
rate = 192000;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
if (runtime->oss.rate != rate) {
runtime->oss.params = 1;
runtime->oss.rate = rate;
}
+ unlock_params(runtime);
}
return snd_pcm_oss_get_rate(pcm_oss_file);
}
@@ -1754,13 +1832,19 @@
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
struct snd_pcm_runtime *runtime;
+ int err;
+
if (substream == NULL)
continue;
runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
if (runtime->oss.channels != channels) {
runtime->oss.params = 1;
runtime->oss.channels = channels;
}
+ unlock_params(runtime);
}
return snd_pcm_oss_get_channels(pcm_oss_file);
}
@@ -1833,6 +1917,7 @@
static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
{
int formats, idx;
+ int err;
if (format != AFMT_QUERY) {
formats = snd_pcm_oss_get_formats(pcm_oss_file);
@@ -1846,10 +1931,14 @@
if (substream == NULL)
continue;
runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
if (runtime->oss.format != format) {
runtime->oss.params = 1;
runtime->oss.format = format;
}
+ unlock_params(runtime);
}
}
return snd_pcm_oss_get_format(pcm_oss_file);
@@ -1869,8 +1958,6 @@
{
struct snd_pcm_runtime *runtime;
- if (substream == NULL)
- return 0;
runtime = substream->runtime;
if (subdivide == 0) {
subdivide = runtime->oss.subdivision;
@@ -1894,9 +1981,17 @@
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
+
if (substream == NULL)
continue;
- if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
+ runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
+ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+ unlock_params(runtime);
+ if (err < 0)
return err;
}
return err;
@@ -1906,8 +2001,6 @@
{
struct snd_pcm_runtime *runtime;
- if (substream == NULL)
- return 0;
runtime = substream->runtime;
if (runtime->oss.subdivision || runtime->oss.fragshift)
return -EINVAL;
@@ -1927,9 +2020,17 @@
for (idx = 1; idx >= 0; --idx) {
struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
+
if (substream == NULL)
continue;
- if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
+ runtime = substream->runtime;
+ err = lock_params(runtime);
+ if (err < 0)
+ return err;
+ err = snd_pcm_oss_set_fragment1(substream, val);
+ unlock_params(runtime);
+ if (err < 0)
return err;
}
return err;
@@ -2013,6 +2114,9 @@
}
if (psubstream) {
runtime = psubstream->runtime;
+ cmd = 0;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
if (trigger & PCM_ENABLE_OUTPUT) {
if (runtime->oss.trigger)
goto _skip1;
@@ -2030,13 +2134,19 @@
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
- if (err < 0)
- return err;
- }
_skip1:
+ mutex_unlock(&runtime->oss.params_lock);
+ if (cmd) {
+ err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
if (csubstream) {
runtime = csubstream->runtime;
+ cmd = 0;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
if (trigger & PCM_ENABLE_INPUT) {
if (runtime->oss.trigger)
goto _skip2;
@@ -2051,11 +2161,14 @@
cmd = SNDRV_PCM_IOCTL_DROP;
runtime->oss.prepare = 1;
}
- err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
- if (err < 0)
- return err;
- }
_skip2:
+ mutex_unlock(&runtime->oss.params_lock);
+ if (cmd) {
+ err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
@@ -2307,6 +2420,7 @@
runtime->oss.maxfrags = 0;
runtime->oss.subdivision = 0;
substream->pcm_release = snd_pcm_oss_release_substream;
+ atomic_set(&runtime->oss.rw_ref, 0);
}
static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index 48f6aee..d79a04e 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -28,6 +28,7 @@
#include <sound/core.h>
#include <sound/minors.h>
#include <sound/pcm.h>
+#include <sound/timer.h>
#include <sound/control.h>
#include <sound/info.h>
@@ -1036,8 +1037,13 @@
snd_free_pages((void*)runtime->control,
PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
kfree(runtime->hw_constraints.rules);
- kfree(runtime);
+ /* Avoid concurrent access to runtime via PCM timer interface */
+ if (substream->timer)
+ spin_lock_irq(&substream->timer->lock);
substream->runtime = NULL;
+ if (substream->timer)
+ spin_unlock_irq(&substream->timer->lock);
+ kfree(runtime);
put_pid(substream->pid);
substream->pid = NULL;
substream->pstr->substream_opened--;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8e5649a..019f60b 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3460,7 +3460,7 @@
area,
substream->runtime->dma_area,
substream->runtime->dma_addr,
- area->vm_end - area->vm_start);
+ substream->runtime->dma_bytes);
#endif /* CONFIG_X86 */
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index 5143801..180261d 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -976,9 +976,9 @@
struct snd_rawmidi_runtime *runtime = substream->runtime;
unsigned long appl_ptr;
- spin_lock_irqsave(&runtime->lock, flags);
if (userbuf)
mutex_lock(&runtime->realloc_mutex);
+ spin_lock_irqsave(&runtime->lock, flags);
while (count > 0 && runtime->avail) {
count1 = runtime->buffer_size - runtime->appl_ptr;
if (count1 > count)
diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c
index f69764d..e30e30b 100644
--- a/sound/core/rawmidi_compat.c
+++ b/sound/core/rawmidi_compat.c
@@ -36,8 +36,6 @@
struct snd_rawmidi_params params;
unsigned int val;
- if (rfile->output == NULL)
- return -EINVAL;
if (get_user(params.stream, &src->stream) ||
get_user(params.buffer_size, &src->buffer_size) ||
get_user(params.avail_min, &src->avail_min) ||
@@ -46,8 +44,12 @@
params.no_active_sensing = val;
switch (params.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
+ if (!rfile->output)
+ return -EINVAL;
return snd_rawmidi_output_params(rfile->output, ¶ms);
case SNDRV_RAWMIDI_STREAM_INPUT:
+ if (!rfile->input)
+ return -EINVAL;
return snd_rawmidi_input_params(rfile->input, ¶ms);
}
return -EINVAL;
@@ -67,16 +69,18 @@
int err;
struct snd_rawmidi_status status;
- if (rfile->output == NULL)
- return -EINVAL;
if (get_user(status.stream, &src->stream))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
+ if (!rfile->output)
+ return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
+ if (!rfile->input)
+ return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
@@ -112,16 +116,18 @@
int err;
struct snd_rawmidi_status status;
- if (rfile->output == NULL)
- return -EINVAL;
if (get_user(status.stream, &src->stream))
return -EFAULT;
switch (status.stream) {
case SNDRV_RAWMIDI_STREAM_OUTPUT:
+ if (!rfile->output)
+ return -EINVAL;
err = snd_rawmidi_output_status(rfile->output, &status);
break;
case SNDRV_RAWMIDI_STREAM_INPUT:
+ if (!rfile->input)
+ return -EINVAL;
err = snd_rawmidi_input_status(rfile->input, &status);
break;
default:
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 733b342..7d3f88d 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1514,7 +1514,8 @@
*/
u8 val;
pci_read_config_byte(chip->pci, 0x42, &val);
- if (!(val & 0x80) && chip->pci->revision == 0x30)
+ if (!(val & 0x80) && (chip->pci->revision == 0x30 ||
+ chip->pci->revision == 0x20))
snoop = false;
}
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c
index 993bde2..7693e63 100644
--- a/sound/soc/codecs/ssm2602.c
+++ b/sound/soc/codecs/ssm2602.c
@@ -54,10 +54,17 @@
* using 2 wire for device control, so we cache them instead.
* There is no point in caching the reset register
*/
-static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = {
- 0x0097, 0x0097, 0x0079, 0x0079,
- 0x000a, 0x0008, 0x009f, 0x000a,
- 0x0000, 0x0000
+static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = {
+ { .reg = 0x00, .def = 0x0097 },
+ { .reg = 0x01, .def = 0x0097 },
+ { .reg = 0x02, .def = 0x0079 },
+ { .reg = 0x03, .def = 0x0079 },
+ { .reg = 0x04, .def = 0x000a },
+ { .reg = 0x05, .def = 0x0008 },
+ { .reg = 0x06, .def = 0x009f },
+ { .reg = 0x07, .def = 0x000a },
+ { .reg = 0x08, .def = 0x0000 },
+ { .reg = 0x09, .def = 0x0000 }
};
@@ -620,8 +627,8 @@
.volatile_reg = ssm2602_register_volatile,
.cache_type = REGCACHE_RBTREE,
- .reg_defaults_raw = ssm2602_reg,
- .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg),
+ .reg_defaults = ssm2602_reg,
+ .num_reg_defaults = ARRAY_SIZE(ssm2602_reg),
};
EXPORT_SYMBOL_GPL(ssm2602_regmap_config);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index dd88c2c..48804e4 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -201,7 +201,7 @@
if (ret < 0)
return ret;
- ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX);
+ ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c
index 4ccc80e..c798f8d 100644
--- a/sound/soc/intel/atom/sst/sst_stream.c
+++ b/sound/soc/intel/atom/sst/sst_stream.c
@@ -221,7 +221,7 @@
sst_free_block(sst_drv_ctx, block);
out:
test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
- return 0;
+ return ret;
}
/*
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c
index 9052561..b1eb696 100644
--- a/sound/soc/intel/boards/cht_bsw_rt5645.c
+++ b/sound/soc/intel/boards/cht_bsw_rt5645.c
@@ -111,6 +111,7 @@
SND_SOC_DAPM_HP("Headphone", NULL),
SND_SOC_DAPM_MIC("Headset Mic", NULL),
SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Analog Mic", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
@@ -121,6 +122,8 @@
{"IN1N", NULL, "Headset Mic"},
{"DMIC L1", NULL, "Int Mic"},
{"DMIC R1", NULL, "Int Mic"},
+ {"IN2P", NULL, "Int Analog Mic"},
+ {"IN2N", NULL, "Int Analog Mic"},
{"Headphone", NULL, "HPOL"},
{"Headphone", NULL, "HPOR"},
{"Ext Spk", NULL, "SPOL"},
@@ -134,6 +137,9 @@
{"Headphone", NULL, "Platform Clock"},
{"Headset Mic", NULL, "Platform Clock"},
{"Int Mic", NULL, "Platform Clock"},
+ {"Int Analog Mic", NULL, "Platform Clock"},
+ {"Int Analog Mic", NULL, "micbias1"},
+ {"Int Analog Mic", NULL, "micbias2"},
{"Ext Spk", NULL, "Platform Clock"},
};
@@ -162,6 +168,7 @@
SOC_DAPM_PIN_SWITCH("Headphone"),
SOC_DAPM_PIN_SWITCH("Headset Mic"),
SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Analog Mic"),
SOC_DAPM_PIN_SWITCH("Ext Spk"),
};
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c
index 805b7f2..78472c9 100644
--- a/sound/soc/intel/skylake/skl-messages.c
+++ b/sound/soc/intel/skylake/skl-messages.c
@@ -331,7 +331,11 @@
if (skl->skl_sst->is_first_boot == true)
return 0;
+ /* disable dynamic clock gating during fw and lib download */
+ ctx->enable_miscbdcge(ctx->dev, false);
+
ret = skl_dsp_wake(ctx->dsp);
+ ctx->enable_miscbdcge(ctx->dev, true);
if (ret < 0)
return ret;
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index 58c7286..2fd213c 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -1191,7 +1191,11 @@
return -EIO;
}
+ /* disable dynamic clock gating during fw and lib download */
+ skl->skl_sst->enable_miscbdcge(platform->dev, false);
+
ret = ops->init_fw(platform->dev, skl->skl_sst);
+ skl->skl_sst->enable_miscbdcge(platform->dev, true);
if (ret < 0) {
dev_err(platform->dev, "Failed to boot first fw: %d\n", ret);
return ret;
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index fefa6ad..17e305b 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -552,6 +552,13 @@
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 *buf = (u32 *)(runtime->dma_area +
rsnd_dai_pointer_offset(io, 0));
+ int shift = 0;
+
+ switch (runtime->sample_bits) {
+ case 32:
+ shift = 8;
+ break;
+ }
/*
* 8/16/32 data can be assesse to TDR/RDR register
@@ -559,9 +566,9 @@
* see rsnd_ssi_init()
*/
if (rsnd_io_is_play(io))
- rsnd_mod_write(mod, SSITDR, *buf);
+ rsnd_mod_write(mod, SSITDR, (*buf) << shift);
else
- *buf = rsnd_mod_read(mod, SSIRDR);
+ *buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
elapsed = rsnd_dai_pointer_update(io, sizeof(*buf));
}
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
index d0fb2f2..4f4ebe9 100644
--- a/sound/usb/line6/midi.c
+++ b/sound/usb/line6/midi.c
@@ -125,7 +125,7 @@
}
usb_fill_int_urb(urb, line6->usbdev,
- usb_sndbulkpipe(line6->usbdev,
+ usb_sndintpipe(line6->usbdev,
line6->properties->ep_ctrl_w),
transfer_buffer, length, midi_sent, line6,
line6->interval);
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 1cd7f8b..45655b9 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -1175,6 +1175,7 @@
switch (id) {
case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */
case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
+ case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
return true;
}
return false;
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 4c596ba..0fd8bfb 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -679,6 +679,10 @@
{ .name = "mlockall", .errmsg = true,
.arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, },
{ .name = "mmap", .hexret = true,
+/* The standard mmap maps to old_mmap on s390x */
+#if defined(__s390x__)
+ .alias = "old_mmap",
+#endif
.arg_scnprintf = { [0] = SCA_HEX, /* addr */
[2] = SCA_MMAP_PROT, /* prot */
[3] = SCA_MMAP_FLAGS, /* flags */ }, },
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index d2c6cdd..4bc5882 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -366,7 +366,23 @@
if (!is_regular_file(name))
return -EINVAL;
+ if (dso__needs_decompress(dso)) {
+ char newpath[KMOD_DECOMP_LEN];
+ size_t len = sizeof(newpath);
+
+ if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) {
+ free(name);
+ return -dso->load_errno;
+ }
+
+ strcpy(name, newpath);
+ }
+
fd = do_open(name);
+
+ if (dso__needs_decompress(dso))
+ unlink(name);
+
free(name);
return fd;
}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 28bdb48..ab36aa5 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1454,8 +1454,16 @@
dso__set_build_id(dso, &bev->build_id);
- if (!is_kernel_module(filename, cpumode))
- dso->kernel = dso_type;
+ if (dso_type != DSO_TYPE_USER) {
+ struct kmod_path m = { .name = NULL, };
+
+ if (!kmod_path__parse_name(&m, filename) && m.kmod)
+ dso__set_short_name(dso, strdup(m.name), true);
+ else
+ dso->kernel = dso_type;
+
+ free(m.name);
+ }
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
sbuild_id);
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 7e27207..cac3953 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c
@@ -1300,6 +1300,7 @@
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;
decoder->overflow = true;
return -EOVERFLOW;
@@ -1522,6 +1523,7 @@
case INTEL_PT_PSBEND:
intel_pt_log("ERROR: Missing TIP after FUP\n");
decoder->pkt_state = INTEL_PT_STATE_ERR3;
+ decoder->pkt_step = 0;
return -ENOENT;
case INTEL_PT_OVF:
@@ -2182,14 +2184,6 @@
return &decoder->state;
}
-static bool intel_pt_at_psb(unsigned char *buf, size_t len)
-{
- if (len < INTEL_PT_PSB_LEN)
- return false;
- return memmem(buf, INTEL_PT_PSB_LEN, INTEL_PT_PSB_STR,
- INTEL_PT_PSB_LEN);
-}
-
/**
* intel_pt_next_psb - move buffer pointer to the start of the next PSB packet.
* @buf: pointer to buffer pointer
@@ -2278,6 +2272,7 @@
* @buf: buffer
* @len: size of buffer
* @tsc: TSC value returned
+ * @rem: returns remaining size when TSC is found
*
* Find a TSC packet in @buf and return the TSC value. This function assumes
* that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a
@@ -2285,7 +2280,8 @@
*
* Return: %true if TSC is found, false otherwise.
*/
-static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc)
+static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc,
+ size_t *rem)
{
struct intel_pt_pkt packet;
int ret;
@@ -2296,6 +2292,7 @@
return false;
if (packet.type == INTEL_PT_TSC) {
*tsc = packet.payload;
+ *rem = len;
return true;
}
if (packet.type == INTEL_PT_PSBEND)
@@ -2346,6 +2343,8 @@
* @len_a: size of first buffer
* @buf_b: second buffer
* @len_b: size of second buffer
+ * @consecutive: returns true if there is data in buf_b that is consecutive
+ * to buf_a
*
* If the trace contains TSC we can look at the last TSC of @buf_a and the
* first TSC of @buf_b in order to determine if the buffers overlap, and then
@@ -2358,33 +2357,41 @@
static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a,
size_t len_a,
unsigned char *buf_b,
- size_t len_b)
+ size_t len_b, bool *consecutive)
{
uint64_t tsc_a, tsc_b;
unsigned char *p;
- size_t len;
+ size_t len, rem_a, rem_b;
p = intel_pt_last_psb(buf_a, len_a);
if (!p)
return buf_b; /* No PSB in buf_a => no overlap */
len = len_a - (p - buf_a);
- if (!intel_pt_next_tsc(p, len, &tsc_a)) {
+ if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) {
/* The last PSB+ in buf_a is incomplete, so go back one more */
len_a -= len;
p = intel_pt_last_psb(buf_a, len_a);
if (!p)
return buf_b; /* No full PSB+ => assume no overlap */
len = len_a - (p - buf_a);
- if (!intel_pt_next_tsc(p, len, &tsc_a))
+ if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a))
return buf_b; /* No TSC in buf_a => assume no overlap */
}
while (1) {
/* Ignore PSB+ with no TSC */
- if (intel_pt_next_tsc(buf_b, len_b, &tsc_b) &&
- intel_pt_tsc_cmp(tsc_a, tsc_b) < 0)
- return buf_b; /* tsc_a < tsc_b => no overlap */
+ if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) {
+ int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b);
+
+ /* Same TSC, so buffers are consecutive */
+ if (!cmp && rem_b >= rem_a) {
+ *consecutive = true;
+ return buf_b + len_b - (rem_b - rem_a);
+ }
+ if (cmp < 0)
+ return buf_b; /* tsc_a < tsc_b => no overlap */
+ }
if (!intel_pt_step_psb(&buf_b, &len_b))
return buf_b + len_b; /* No PSB in buf_b => no data */
@@ -2398,6 +2405,8 @@
* @buf_b: second buffer
* @len_b: size of second buffer
* @have_tsc: can use TSC packets to detect overlap
+ * @consecutive: returns true if there is data in buf_b that is consecutive
+ * to buf_a
*
* When trace samples or snapshots are recorded there is the possibility that
* the data overlaps. Note that, for the purposes of decoding, data is only
@@ -2408,7 +2417,7 @@
*/
unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
unsigned char *buf_b, size_t len_b,
- bool have_tsc)
+ bool have_tsc, bool *consecutive)
{
unsigned char *found;
@@ -2420,7 +2429,8 @@
return buf_b; /* No overlap */
if (have_tsc) {
- found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b);
+ found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b,
+ consecutive);
if (found)
return found;
}
@@ -2435,28 +2445,16 @@
}
/* Now len_b >= len_a */
- if (len_b > len_a) {
- /* The leftover buffer 'b' must start at a PSB */
- while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) {
- if (!intel_pt_step_psb(&buf_a, &len_a))
- return buf_b; /* No overlap */
- }
- }
-
while (1) {
/* Potential overlap so check the bytes */
found = memmem(buf_a, len_a, buf_b, len_a);
- if (found)
+ if (found) {
+ *consecutive = true;
return buf_b + len_a;
+ }
/* Try again at next PSB in buffer 'a' */
if (!intel_pt_step_psb(&buf_a, &len_a))
return buf_b; /* No overlap */
-
- /* The leftover buffer 'b' must start at a PSB */
- while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) {
- if (!intel_pt_step_psb(&buf_a, &len_a))
- return buf_b; /* No overlap */
- }
}
}
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 8939998..9ae4df1 100644
--- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
+++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h
@@ -103,7 +103,7 @@
unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a,
unsigned char *buf_b, size_t len_b,
- bool have_tsc);
+ bool have_tsc, bool *consecutive);
int intel_pt__strerror(int code, char *buf, size_t buflen);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index dc041d4..b1161d7 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -131,6 +131,7 @@
bool stop;
bool step_through_buffers;
bool use_buffer_pid_tid;
+ bool sync_switch;
pid_t pid, tid;
int cpu;
int switch_state;
@@ -194,14 +195,17 @@
static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a,
struct auxtrace_buffer *b)
{
+ bool consecutive = false;
void *start;
start = intel_pt_find_overlap(a->data, a->size, b->data, b->size,
- pt->have_tsc);
+ pt->have_tsc, &consecutive);
if (!start)
return -EINVAL;
b->use_size = b->data + b->size - start;
b->use_data = start;
+ if (b->use_size && consecutive)
+ b->consecutive = true;
return 0;
}
@@ -928,10 +932,12 @@
if (pt->timeless_decoding || !pt->have_sched_switch)
ptq->use_buffer_pid_tid = true;
}
+
+ ptq->sync_switch = pt->sync_switch;
}
if (!ptq->on_heap &&
- (!pt->sync_switch ||
+ (!ptq->sync_switch ||
ptq->switch_state != INTEL_PT_SS_EXPECTING_SWITCH_EVENT)) {
const struct intel_pt_state *state;
int ret;
@@ -1333,7 +1339,7 @@
if (pt->synth_opts.last_branch)
intel_pt_update_last_branch_rb(ptq);
- if (!pt->sync_switch)
+ if (!ptq->sync_switch)
return 0;
if (intel_pt_is_switch_ip(ptq, state->to_ip)) {
@@ -1414,6 +1420,21 @@
return switch_ip;
}
+static void intel_pt_enable_sync_switch(struct intel_pt *pt)
+{
+ unsigned int i;
+
+ pt->sync_switch = true;
+
+ for (i = 0; i < pt->queues.nr_queues; i++) {
+ struct auxtrace_queue *queue = &pt->queues.queue_array[i];
+ struct intel_pt_queue *ptq = queue->priv;
+
+ if (ptq)
+ ptq->sync_switch = true;
+ }
+}
+
static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp)
{
const struct intel_pt_state *state = ptq->state;
@@ -1430,7 +1451,7 @@
if (pt->switch_ip) {
intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n",
pt->switch_ip, pt->ptss_ip);
- pt->sync_switch = true;
+ intel_pt_enable_sync_switch(pt);
}
}
}
@@ -1446,9 +1467,9 @@
if (state->err) {
if (state->err == INTEL_PT_ERR_NODATA)
return 1;
- if (pt->sync_switch &&
+ if (ptq->sync_switch &&
state->from_ip >= pt->kernel_start) {
- pt->sync_switch = false;
+ ptq->sync_switch = false;
intel_pt_next_tid(pt, ptq);
}
if (pt->synth_opts.errors) {
@@ -1474,7 +1495,7 @@
state->timestamp, state->est_timestamp);
ptq->timestamp = state->est_timestamp;
/* Use estimated TSC in unknown switch state */
- } else if (pt->sync_switch &&
+ } else if (ptq->sync_switch &&
ptq->switch_state == INTEL_PT_SS_UNKNOWN &&
intel_pt_is_switch_ip(ptq, state->to_ip) &&
ptq->next_tid == -1) {
@@ -1621,7 +1642,7 @@
return 1;
ptq = intel_pt_cpu_to_ptq(pt, cpu);
- if (!ptq)
+ if (!ptq || !ptq->sync_switch)
return 1;
switch (ptq->switch_state) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 4d2e22f..c93dacc 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -2609,6 +2609,14 @@
out:
free(nbase);
+
+ /* Final validation */
+ if (ret >= 0 && !is_c_func_name(buf)) {
+ pr_warning("Internal error: \"%s\" is an invalid event name.\n",
+ buf);
+ ret = -EINVAL;
+ }
+
return ret;
}
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 783a53f..b46e1cf 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -38,6 +38,14 @@
return 0;
mod = dwfl_addrmodule(ui->dwfl, ip);
+ if (mod) {
+ Dwarf_Addr s;
+
+ dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL);
+ if (s != al->map->start)
+ mod = 0;
+ }
+
if (!mod)
mod = dwfl_report_elf(ui->dwfl, dso->short_name,
dso->long_name, -1, al->map->start,
@@ -167,12 +175,16 @@
{
struct unwind_info *ui = arg;
Dwarf_Addr pc;
+ bool isactivation;
- if (!dwfl_frame_pc(state, &pc, NULL)) {
+ if (!dwfl_frame_pc(state, &pc, &isactivation)) {
pr_err("%s", dwfl_errmsg(-1));
return DWARF_CB_ABORT;
}
+ if (!isactivation)
+ --pc;
+
return entry(pc, ui) || !(--ui->max_stack) ?
DWARF_CB_ABORT : DWARF_CB_OK;
}
diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c
index 20c2e57..1203834 100644
--- a/tools/perf/util/unwind-libunwind-local.c
+++ b/tools/perf/util/unwind-libunwind-local.c
@@ -646,6 +646,17 @@
while (!ret && (unw_step(&c) > 0) && i < max_stack) {
unw_get_reg(&c, UNW_REG_IP, &ips[i]);
+
+ /*
+ * Decrement the IP for any non-activation frames.
+ * this is required to properly find the srcline
+ * for caller frames.
+ * See also the documentation for dwfl_frame_pc(),
+ * which this code tries to replicate.
+ */
+ if (unw_is_signal_frame(&c) <= 0)
+ --ips[i];
+
++i;
}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index 85c5680..dfb010b 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -207,7 +207,7 @@
size -= ret;
off_in += ret;
- off_out -= ret;
+ off_out += ret;
}
munmap(ptr, off_in + size);
diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
index d9c49f4..e79ccd6 100644
--- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
+++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c
@@ -42,12 +42,12 @@
printf("Check DSCR TM context switch: ");
fflush(stdout);
for (;;) {
- rv = 1;
asm __volatile__ (
/* set a known value into the DSCR */
"ld 3, %[dscr1];"
"mtspr %[sprn_dscr], 3;"
+ "li %[rv], 1;"
/* start and suspend a transaction */
"tbegin.;"
"beq 1f;"
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index cbb0564..f689981 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -1318,7 +1318,7 @@
iov.iov_len = sizeof(regs);
ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov);
#endif
- EXPECT_EQ(0, ret);
+ EXPECT_EQ(0, ret) {}
#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \
defined(__s390__) || defined(__hppa__)